pull/1395/head
gedoor 3 years ago
parent 605e5064e0
commit 3cd9b379c6
  1. 21
      app/src/main/java/io/legado/app/help/BookHelp.kt
  2. 3
      app/src/main/java/io/legado/app/help/CrashHandler.kt
  3. 10
      app/src/main/java/io/legado/app/help/ReadBookConfig.kt
  4. 2
      app/src/main/java/io/legado/app/help/storage/Backup.kt
  5. 9
      app/src/main/java/io/legado/app/help/storage/ImportOldData.kt
  6. 2
      app/src/main/java/io/legado/app/help/storage/Restore.kt
  7. 4
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  8. 2
      app/src/main/java/io/legado/app/model/localBook/TextFile.kt
  9. 36
      app/src/main/java/io/legado/app/service/HttpReadAloudService.kt
  10. 2
      app/src/main/java/io/legado/app/ui/about/AboutFragment.kt
  11. 13
      app/src/main/java/io/legado/app/utils/FileExtensions.kt
  12. 18
      app/src/main/java/io/legado/app/utils/FileUtils.kt

@ -48,7 +48,7 @@ object BookHelp {
appDb.bookDao.all.forEach { appDb.bookDao.all.forEach {
bookFolderNames.add(it.getFolderName()) bookFolderNames.add(it.getFolderName())
} }
val file = FileUtils.getFile(downloadDir, cacheFolderName) val file = downloadDir.getFile(cacheFolderName)
file.listFiles()?.forEach { bookFile -> file.listFiles()?.forEach { bookFile ->
if (!bookFolderNames.contains(bookFile.name)) { if (!bookFolderNames.contains(bookFile.name)) {
FileUtils.deleteFile(bookFile.absolutePath) FileUtils.deleteFile(bookFile.absolutePath)
@ -58,12 +58,7 @@ object BookHelp {
} }
fun getEpubFile(book: Book): File { fun getEpubFile(book: Book): File {
val file = FileUtils.getFile( val file = downloadDir.getFile(cacheFolderName, book.getFolderName(), "index.epubx")
downloadDir,
cacheFolderName,
book.getFolderName(),
"index.epubx"
)
if (!file.exists()) { if (!file.exists()) {
val input = if (book.bookUrl.isContentScheme()) { val input = if (book.bookUrl.isContentScheme()) {
val uri = Uri.parse(book.bookUrl) val uri = Uri.parse(book.bookUrl)
@ -133,8 +128,7 @@ object BookHelp {
} }
fun getImage(book: Book, src: String): File { fun getImage(book: Book, src: String): File {
return FileUtils.getFile( return downloadDir.getFile(
downloadDir,
cacheFolderName, cacheFolderName,
book.getFolderName(), book.getFolderName(),
cacheImageFolderName, cacheImageFolderName,
@ -171,8 +165,7 @@ object BookHelp {
return if (book.isLocalTxt()) { return if (book.isLocalTxt()) {
true true
} else { } else {
FileUtils.exists( downloadDir.exists(
downloadDir,
cacheFolderName, cacheFolderName,
book.getFolderName(), book.getFolderName(),
bookChapter.getFileName() bookChapter.getFileName()
@ -219,8 +212,7 @@ object BookHelp {
} }
return string return string
} else { } else {
val file = FileUtils.getFile( val file = downloadDir.getFile(
downloadDir,
cacheFolderName, cacheFolderName,
book.getFolderName(), book.getFolderName(),
bookChapter.getFileName() bookChapter.getFileName()
@ -237,8 +229,7 @@ object BookHelp {
*/ */
fun reverseContent(book: Book, bookChapter: BookChapter) { fun reverseContent(book: Book, bookChapter: BookChapter) {
if (!book.isLocalBook()) { if (!book.isLocalBook()) {
val file = FileUtils.getFile( val file = downloadDir.getFile(
downloadDir,
cacheFolderName, cacheFolderName,
book.getFolderName(), book.getFolderName(),
bookChapter.getFileName() bookChapter.getFileName()

@ -7,6 +7,7 @@ import android.util.Log
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.model.ReadAloud import io.legado.app.model.ReadAloud
import io.legado.app.utils.FileUtils import io.legado.app.utils.FileUtils
import io.legado.app.utils.getFile
import io.legado.app.utils.longToastOnUi import io.legado.app.utils.longToastOnUi
import io.legado.app.utils.msg import io.legado.app.utils.msg
import java.io.PrintWriter import java.io.PrintWriter
@ -113,7 +114,7 @@ class CrashHandler(val context: Context) : Thread.UncaughtExceptionHandler {
val time = format.format(Date()) val time = format.format(Date())
val fileName = "crash-$time-$timestamp.log" val fileName = "crash-$time-$timestamp.log"
context.externalCacheDir?.let { rootFile -> context.externalCacheDir?.let { rootFile ->
FileUtils.getFile(rootFile, "crash").listFiles()?.forEach { rootFile.getFile("crash").listFiles()?.forEach {
if (it.lastModified() < System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7)) { if (it.lastModified() < System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7)) {
it.delete() it.delete()
} }

@ -368,14 +368,14 @@ object ReadBookConfig {
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath)) ZipUtils.unzipFile(zipFile, FileUtils.createFolderIfNotExist(configDirPath))
val configDir = FileUtils.createFolderIfNotExist(configDirPath) val configDir = FileUtils.createFolderIfNotExist(configDirPath)
val configFile = FileUtils.getFile(configDir, "readConfig.json") val configFile = configDir.getFile("readConfig.json")
val config: Config = GSON.fromJsonObject(configFile.readText())!! val config: Config = GSON.fromJsonObject(configFile.readText())!!
if (config.textFont.isNotEmpty()) { if (config.textFont.isNotEmpty()) {
val fontName = FileUtils.getName(config.textFont) val fontName = FileUtils.getName(config.textFont)
val fontPath = val fontPath =
FileUtils.getPath(appCtx.externalFiles, "font", fontName) FileUtils.getPath(appCtx.externalFiles, "font", fontName)
if (!FileUtils.exist(fontPath)) { if (!FileUtils.exist(fontPath)) {
FileUtils.getFile(configDir, fontName).copyTo(File(fontPath)) configDir.getFile(fontName).copyTo(File(fontPath))
} }
config.textFont = fontPath config.textFont = fontPath
} }
@ -383,7 +383,7 @@ object ReadBookConfig {
val bgName = FileUtils.getName(config.bgStr) val bgName = FileUtils.getName(config.bgStr)
val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName) val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName)
if (!FileUtils.exist(bgPath)) { if (!FileUtils.exist(bgPath)) {
val bgFile = FileUtils.getFile(configDir, bgName) val bgFile = configDir.getFile(bgName)
if (bgFile.exists()) { if (bgFile.exists()) {
bgFile.copyTo(File(bgPath)) bgFile.copyTo(File(bgPath))
} }
@ -393,7 +393,7 @@ object ReadBookConfig {
val bgName = FileUtils.getName(config.bgStrNight) val bgName = FileUtils.getName(config.bgStrNight)
val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName) val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName)
if (!FileUtils.exist(bgPath)) { if (!FileUtils.exist(bgPath)) {
val bgFile = FileUtils.getFile(configDir, bgName) val bgFile = configDir.getFile(bgName)
if (bgFile.exists()) { if (bgFile.exists()) {
bgFile.copyTo(File(bgPath)) bgFile.copyTo(File(bgPath))
} }
@ -403,7 +403,7 @@ object ReadBookConfig {
val bgName = FileUtils.getName(config.bgStrEInk) val bgName = FileUtils.getName(config.bgStrEInk)
val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName) val bgPath = FileUtils.getPath(appCtx.externalFiles, "bg", bgName)
if (!FileUtils.exist(bgPath)) { if (!FileUtils.exist(bgPath)) {
val bgFile = FileUtils.getFile(configDir, bgName) val bgFile = configDir.getFile(bgName)
if (bgFile.exists()) { if (bgFile.exists()) {
bgFile.copyTo(File(bgPath)) bgFile.copyTo(File(bgPath))
} }

@ -21,7 +21,7 @@ import java.util.concurrent.TimeUnit
object Backup { object Backup {
val backupPath: String by lazy { val backupPath: String by lazy {
FileUtils.getFile(appCtx.filesDir, "backup").absolutePath appCtx.filesDir.getFile("backup").absolutePath
} }
val backupFileNames by lazy { val backupFileNames by lazy {

@ -5,10 +5,7 @@ import android.net.Uri
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.help.BookSourceAnalyzer import io.legado.app.help.BookSourceAnalyzer
import io.legado.app.utils.DocumentUtils import io.legado.app.utils.*
import io.legado.app.utils.FileUtils
import io.legado.app.utils.isContentScheme
import io.legado.app.utils.toastOnUi
import java.io.File import java.io.File
object ImportOldData { object ImportOldData {
@ -61,7 +58,7 @@ object ImportOldData {
kotlin.runCatching {// Book source kotlin.runCatching {// Book source
val sourceFile = val sourceFile =
FileUtils.getFile(file, "myBookSource.json") file.getFile("myBookSource.json")
val json = sourceFile.readText() val json = sourceFile.readText()
val importCount = importOldSource(json) val importCount = importOldSource(json)
context.toastOnUi("成功导入书源${importCount}") context.toastOnUi("成功导入书源${importCount}")
@ -70,7 +67,7 @@ object ImportOldData {
} }
kotlin.runCatching {// Replace rules kotlin.runCatching {// Replace rules
val ruleFile = FileUtils.getFile(file, "myBookReplaceRule.json") val ruleFile = file.getFile("myBookReplaceRule.json")
if (ruleFile.exists()) { if (ruleFile.exists()) {
val json = ruleFile.readText() val json = ruleFile.readText()
val importCount = importOldReplaceRule(json) val importCount = importOldReplaceRule(json)

@ -82,7 +82,7 @@ object Restore {
try { try {
val file = File(path) val file = File(path)
for (fileName in Backup.backupFileNames) { for (fileName in Backup.backupFileNames) {
FileUtils.getFile(file, fileName).let { file.getFile(fileName).let {
if (it.exists()) { if (it.exists()) {
it.copyTo( it.copyTo(
FileUtils.createFileIfNotExist("${Backup.backupPath}${File.separator}$fileName"), FileUtils.createFileIfNotExist("${Backup.backupPath}${File.separator}$fileName"),

@ -64,7 +64,7 @@ object LocalBook {
path = uri.toString() path = uri.toString()
val doc = DocumentFile.fromSingleUri(appCtx, uri) val doc = DocumentFile.fromSingleUri(appCtx, uri)
doc?.let { doc?.let {
val bookFile = FileUtils.getFile(cacheFolder, it.name!!) val bookFile = cacheFolder.getFile(it.name!!)
if (!bookFile.exists()) { if (!bookFile.exists()) {
bookFile.createNewFile() bookFile.createNewFile()
doc.readBytes(appCtx)?.let { bytes -> doc.readBytes(appCtx)?.let { bytes ->
@ -147,7 +147,7 @@ object LocalBook {
fun deleteBook(book: Book, deleteOriginal: Boolean) { fun deleteBook(book: Book, deleteOriginal: Boolean) {
kotlin.runCatching { kotlin.runCatching {
if (book.isLocalTxt() || book.isUmd()) { if (book.isLocalTxt() || book.isUmd()) {
val bookFile = FileUtils.getFile(cacheFolder, book.originName) val bookFile = cacheFolder.getFile(book.originName)
bookFile.delete() bookFile.delete()
} }
if (book.isEpub()) { if (book.isEpub()) {

@ -264,7 +264,7 @@ class TextFile {
private fun getBookFile(book: Book): File { private fun getBookFile(book: Book): File {
if (book.bookUrl.isContentScheme()) { if (book.bookUrl.isContentScheme()) {
val uri = Uri.parse(book.bookUrl) val uri = Uri.parse(book.bookUrl)
val bookFile = FileUtils.getFile(LocalBook.cacheFolder, book.originName) val bookFile = LocalBook.cacheFolder.getFile(book.originName)
if (!bookFile.exists()) { if (!bookFile.exists()) {
bookFile.createNewFile() bookFile.createNewFile()
DocumentUtils.readBytes(appCtx, uri)?.let { DocumentUtils.readBytes(appCtx, uri)?.let {

@ -28,13 +28,13 @@ class HttpReadAloudService : BaseReadAloudService(),
private val bdRegex = "^(\\s|\\p{P})+$".toRegex() private val bdRegex = "^(\\s|\\p{P})+$".toRegex()
private val mediaPlayer = MediaPlayer() private val mediaPlayer = MediaPlayer()
private val ttsFolder: String by lazy { private val ttsFolderPath: String by lazy {
externalCacheDir!!.absolutePath + File.separator + "httpTTS" externalCacheDir!!.absolutePath + File.separator + "httpTTS" + File.separator
} }
private var task: Coroutine<*>? = null private var task: Coroutine<*>? = null
private var playingIndex = -1 private var playingIndex = -1
private var playIndexJob: Job? = null private var playIndexJob: Job? = null
private var errorNo = 0
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -87,6 +87,8 @@ class HttpReadAloudService : BaseReadAloudService(),
} }
} }
private var downloadErrorNo: Int = 0
private fun downloadAudio() { private fun downloadAudio() {
task?.cancel() task?.cancel()
task = execute { task = execute {
@ -140,12 +142,13 @@ class HttpReadAloudService : BaseReadAloudService(),
playAudio(fis.fd) playAudio(fis.fd)
} }
} }
downloadErrorNo = 0
} catch (e: CancellationException) { } catch (e: CancellationException) {
//任务取消,不处理 //任务取消,不处理
} catch (e: SocketTimeoutException) { } catch (e: SocketTimeoutException) {
removeSpeakCacheFile(fileName) removeSpeakCacheFile(fileName)
errorNo++ downloadErrorNo++
if (errorNo > 5) { if (playErrorNo > 5) {
createSilentSound(fileName) createSilentSound(fileName)
} else { } else {
toastOnUi("tts接口超时,尝试重新获取") toastOnUi("tts接口超时,尝试重新获取")
@ -188,7 +191,6 @@ class HttpReadAloudService : BaseReadAloudService(),
} }
} }
private fun speakFilePath() = ttsFolder + File.separator
private fun md5SpeakFileName(url: String, ttsConfig: String, content: String): String { private fun md5SpeakFileName(url: String, ttsConfig: String, content: String): String {
return MD5Utils.md5Encode16(textChapter!!.title) + "_" + MD5Utils.md5Encode16("$url-|-$ttsConfig-|-$content") return MD5Utils.md5Encode16(textChapter!!.title) + "_" + MD5Utils.md5Encode16("$url-|-$ttsConfig-|-$content")
} }
@ -199,26 +201,26 @@ class HttpReadAloudService : BaseReadAloudService(),
} }
private fun hasSpeakFile(name: String) = private fun hasSpeakFile(name: String) =
FileUtils.exist("${speakFilePath()}$name.mp3") FileUtils.exist("${ttsFolderPath}$name.mp3")
private fun hasSpeakCacheFile(name: String) = private fun hasSpeakCacheFile(name: String) =
FileUtils.exist("${speakFilePath()}$name.mp3.cache") FileUtils.exist("${ttsFolderPath}$name.mp3.cache")
private fun createSpeakCacheFile(name: String): File = private fun createSpeakCacheFile(name: String): File =
FileUtils.createFileWithReplace("${speakFilePath()}$name.mp3.cache") FileUtils.createFileWithReplace("${ttsFolderPath}$name.mp3.cache")
private fun removeSpeakCacheFile(name: String) { private fun removeSpeakCacheFile(name: String) {
FileUtils.delete("${speakFilePath()}$name.mp3.cache") FileUtils.delete("${ttsFolderPath}$name.mp3.cache")
} }
private fun getSpeakFileAsMd5(name: String): File = private fun getSpeakFileAsMd5(name: String): File =
FileUtils.getFile(File(speakFilePath()), "$name.mp3") File("${ttsFolderPath}$name.mp3")
private fun createSpeakFileAsMd5IfNotExist(name: String): File = private fun createSpeakFileAsMd5IfNotExist(name: String): File =
FileUtils.createFileIfNotExist("${speakFilePath()}$name.mp3") FileUtils.createFileIfNotExist("${ttsFolderPath}$name.mp3")
private fun removeCacheFile() { private fun removeCacheFile() {
FileUtils.listDirsAndFiles(speakFilePath())?.forEach { FileUtils.listDirsAndFiles(ttsFolderPath)?.forEach {
if (Regex(""".+\.mp3$""").matches(it.name)) { //mp3缓存文件 if (Regex(""".+\.mp3$""").matches(it.name)) { //mp3缓存文件
val reg = val reg =
"""^${MD5Utils.md5Encode16(textChapter!!.title)}_[a-z0-9]{16}\.mp3$""".toRegex() """^${MD5Utils.md5Encode16(textChapter!!.title)}_[a-z0-9]{16}\.mp3$""".toRegex()
@ -293,14 +295,16 @@ class HttpReadAloudService : BaseReadAloudService(),
upPlayPos() upPlayPos()
} }
private var playErrorNo = 0
override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean { override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
if (what == -38 && extra == 0) { if (what == -38 && extra == 0) {
play() play()
return true return true
} }
AppLog.put("朗读错误,($what, $extra)") AppLog.put("朗读错误,($what, $extra)")
errorNo++ playErrorNo++
if (errorNo >= 5) { if (playErrorNo >= 5) {
toastOnUi("朗读连续5次错误, 最后一次错误代码($what, $extra)") toastOnUi("朗读连续5次错误, 最后一次错误代码($what, $extra)")
ReadAloud.pause(this) ReadAloud.pause(this)
} else { } else {
@ -310,7 +314,7 @@ class HttpReadAloudService : BaseReadAloudService(),
} }
override fun onCompletion(mp: MediaPlayer?) { override fun onCompletion(mp: MediaPlayer?) {
errorNo = 0 playErrorNo = 0
playNext() playNext()
} }

@ -125,7 +125,7 @@ class AboutFragment : PreferenceFragmentCompat() {
private fun showCrashLogs() { private fun showCrashLogs() {
context?.externalCacheDir?.let { exCacheDir -> context?.externalCacheDir?.let { exCacheDir ->
val crashDir = FileUtils.getFile(exCacheDir, "crash") val crashDir = exCacheDir.getFile("crash")
val crashLogs = crashDir.listFiles() val crashLogs = crashDir.listFiles()
val crashLogNames = arrayListOf<String>() val crashLogNames = arrayListOf<String>()
crashLogs?.forEach { crashLogs?.forEach {

@ -0,0 +1,13 @@
package io.legado.app.utils
import java.io.File
fun File.getFile(vararg subDirFiles: String): File {
val path = FileUtils.getPath(this, *subDirFiles)
return File(path)
}
fun File.exists(vararg subDirFiles: String): Boolean {
return getFile(*subDirFiles).exists()
}

@ -14,10 +14,6 @@ import java.util.regex.Pattern
@Suppress("unused", "MemberVisibilityCanBePrivate") @Suppress("unused", "MemberVisibilityCanBePrivate")
object FileUtils { object FileUtils {
fun exists(root: File, vararg subDirFiles: String): Boolean {
return getFile(root, *subDirFiles).exists()
}
fun createFileIfNotExist(root: File, vararg subDirFiles: String): File { fun createFileIfNotExist(root: File, vararg subDirFiles: String): File {
val filePath = getPath(root, *subDirFiles) val filePath = getPath(root, *subDirFiles)
return createFileIfNotExist(filePath) return createFileIfNotExist(filePath)
@ -71,9 +67,17 @@ object FileUtils {
return file return file
} }
fun getFile(root: File, vararg subDirFiles: String): File { fun getPath(rootPath: String, vararg subDirFiles: String): String {
val filePath = getPath(root, *subDirFiles) val path = StringBuilder(rootPath)
return File(filePath) subDirFiles.forEach {
if (it.isNotEmpty()) {
if (!path.endsWith(File.separator)) {
path.append(File.separator)
}
path.append(it)
}
}
return path.toString()
} }
fun getPath(root: File, vararg subDirFiles: String): String { fun getPath(root: File, vararg subDirFiles: String): String {

Loading…
Cancel
Save