pull/34/head
kunfei 5 years ago
parent dfd21b5c5c
commit 8316e13987
  1. 6
      app/src/main/java/io/legado/app/help/FileHelp.kt
  2. 10
      app/src/main/java/io/legado/app/help/storage/Backup.kt
  3. 6
      app/src/main/java/io/legado/app/help/storage/Restore.kt
  4. 81
      app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt
  5. 3
      app/src/main/java/io/legado/app/service/BaseReadAloudService.kt
  6. 420
      app/src/main/java/io/legado/app/utils/ZipUtils.kt

@ -1,5 +1,6 @@
package io.legado.app.help package io.legado.app.help
import io.legado.app.App
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@ -32,4 +33,9 @@ object FileHelp {
} }
return file return file
} }
fun getCachePath(): String {
return App.INSTANCE.externalCacheDir?.absolutePath
?: App.INSTANCE.cacheDir.absolutePath
}
} }

@ -13,10 +13,13 @@ import java.io.File
object Backup { object Backup {
val defaultPath by lazy {
FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp"
}
fun backup() { fun backup() {
doAsync { doAsync {
val path = val path = defaultPath
FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp"
backupBookshelf(path) backupBookshelf(path)
backupBookSource(path) backupBookSource(path)
backupRssSource(path) backupRssSource(path)
@ -29,8 +32,7 @@ object Backup {
fun autoBackup(activity: AppCompatActivity) { fun autoBackup(activity: AppCompatActivity) {
doAsync { doAsync {
val path = val path = defaultPath
FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp"
backupBookshelf(path) backupBookshelf(path)
backupBookSource(path) backupBookSource(path)
backupRssSource(path) backupRssSource(path)

@ -12,6 +12,7 @@ import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
import io.legado.app.data.entities.RssSource import io.legado.app.data.entities.RssSource
import io.legado.app.help.FileHelp import io.legado.app.help.FileHelp
import io.legado.app.help.storage.Backup.defaultPath
import io.legado.app.utils.* import io.legado.app.utils.*
import org.jetbrains.anko.doAsync import org.jetbrains.anko.doAsync
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
@ -25,10 +26,6 @@ object Restore {
.build() .build()
) )
private val defaultPath by lazy {
FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp"
}
fun restore(path: String = defaultPath) { fun restore(path: String = defaultPath) {
doAsync { doAsync {
try { try {
@ -67,6 +64,7 @@ object Restore {
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
uiThread { App.INSTANCE.toast("恢复完成") }
} }
} }

@ -0,0 +1,81 @@
package io.legado.app.help.storage
import android.content.Context
import io.legado.app.App
import io.legado.app.help.FileHelp
import io.legado.app.lib.webdav.WebDav
import io.legado.app.lib.webdav.http.HttpAuth
import io.legado.app.utils.ZipUtils
import io.legado.app.utils.getPrefString
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.selector
import org.jetbrains.anko.uiThread
import kotlin.math.min
object WebDavHelp {
fun getWebDavUrl(): String? {
var url = App.INSTANCE.getPrefString("web_dav_url")
if (url.isNullOrBlank()) return null
if (!url.endsWith("/")) url += "/"
return url
}
private fun initWebDav(): Boolean {
val account = App.INSTANCE.getPrefString("web_dav_account")
val password = App.INSTANCE.getPrefString("web_dav_password")
if (!account.isNullOrBlank() && !password.isNullOrBlank()) {
HttpAuth.auth = HttpAuth.Auth(account, password)
return true
}
return false
}
private fun getWebDavFileNames(): ArrayList<String> {
val url = getWebDavUrl()
val names = arrayListOf<String>()
if (!url.isNullOrBlank() && initWebDav()) {
val files = WebDav(url + "legado/").listFiles()
files.reversed()
for (index: Int in 0 until min(10, files.size)) {
files[index].displayName?.let {
names.add(it)
}
}
}
return names
}
fun showRestoreDialog(context: Context) {
doAsync {
val names = getWebDavFileNames()
if (names.isNotEmpty()) {
uiThread {
context.selector(title = "选择恢复文件", items = names) { _, index ->
if (index in 0 until names.size) {
restoreWebDav(names[index])
}
}
}
} else {
Restore.restore()
}
}
}
private fun restoreWebDav(name: String) {
doAsync {
getWebDavUrl()?.let {
val file = WebDav(it + "legado/" + name)
val zipFilePath = FileHelp.getCachePath() + "/backup" + ".zip"
file.downloadTo(zipFilePath, true)
ZipUtils.unzipFile(zipFilePath, Backup.defaultPath)
Restore.restore()
}
}
}
fun backUpWebDav() {
}
}

@ -59,6 +59,7 @@ abstract class BaseReadAloudService : BaseService(),
initMediaSession() initMediaSession()
initBroadcastReceiver() initBroadcastReceiver()
upNotification() upNotification()
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING)
} }
override fun onDestroy() { override fun onDestroy() {
@ -116,7 +117,6 @@ abstract class BaseReadAloudService : BaseService(),
} }
open fun play() { open fun play() {
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING)
postEvent(Bus.ALOUD_STATE, Status.PLAY) postEvent(Bus.ALOUD_STATE, Status.PLAY)
upNotification() upNotification()
} }
@ -132,6 +132,7 @@ abstract class BaseReadAloudService : BaseService(),
@CallSuper @CallSuper
open fun resumeReadAloud() { open fun resumeReadAloud() {
pause = false pause = false
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING)
} }
abstract fun upSpeechRate(reset: Boolean = false) abstract fun upSpeechRate(reset: Boolean = false)

@ -0,0 +1,420 @@
package io.legado.app.utils
import android.util.Log
import java.io.*
import java.util.*
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream
/**
* <pre>
* author: Blankj
* blog : http://blankj.com
* time : 2016/08/27
* desc : utils about zip
</pre> *
*/
object ZipUtils {
/**
* Zip the files.
*
* @param srcFiles The source of files.
* @param zipFilePath The path of ZIP file.
* @return `true`: success<br></br>`false`: fail
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun zipFiles(
srcFiles: Collection<String>,
zipFilePath: String
): Boolean {
return zipFiles(srcFiles, zipFilePath, null)
}
/**
* Zip the files.
*
* @param srcFilePaths The paths of source files.
* @param zipFilePath The path of ZIP file.
* @param comment The comment.
* @return `true`: success<br></br>`false`: fail
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun zipFiles(
srcFilePaths: Collection<String>?,
zipFilePath: String?,
comment: String?
): Boolean {
if (srcFilePaths == null || zipFilePath == null) return false
var zos: ZipOutputStream? = null
try {
zos = ZipOutputStream(FileOutputStream(zipFilePath))
for (srcFile in srcFilePaths) {
if (!zipFile(getFileByPath(srcFile)!!, "", zos, comment)) return false
}
return true
} finally {
if (zos != null) {
zos.finish()
zos.close()
}
}
}
/**
* Zip the files.
*
* @param srcFiles The source of files.
* @param zipFile The ZIP file.
* @param comment The comment.
* @return `true`: success<br></br>`false`: fail
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
@JvmOverloads
fun zipFiles(
srcFiles: Collection<File>?,
zipFile: File?,
comment: String? = null
): Boolean {
if (srcFiles == null || zipFile == null) return false
var zos: ZipOutputStream? = null
try {
zos = ZipOutputStream(FileOutputStream(zipFile))
for (srcFile in srcFiles) {
if (!zipFile(srcFile, "", zos, comment)) return false
}
return true
} finally {
if (zos != null) {
zos.finish()
zos.close()
}
}
}
/**
* Zip the file.
*
* @param srcFilePath The path of source file.
* @param zipFilePath The path of ZIP file.
* @return `true`: success<br></br>`false`: fail
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun zipFile(
srcFilePath: String,
zipFilePath: String
): Boolean {
return zipFile(getFileByPath(srcFilePath), getFileByPath(zipFilePath), null)
}
/**
* Zip the file.
*
* @param srcFilePath The path of source file.
* @param zipFilePath The path of ZIP file.
* @param comment The comment.
* @return `true`: success<br></br>`false`: fail
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun zipFile(
srcFilePath: String,
zipFilePath: String,
comment: String
): Boolean {
return zipFile(getFileByPath(srcFilePath), getFileByPath(zipFilePath), comment)
}
/**
* Zip the file.
*
* @param srcFile The source of file.
* @param zipFile The ZIP file.
* @param comment The comment.
* @return `true`: success<br></br>`false`: fail
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
@JvmOverloads
fun zipFile(
srcFile: File?,
zipFile: File?,
comment: String? = null
): Boolean {
if (srcFile == null || zipFile == null) return false
ZipOutputStream(FileOutputStream(zipFile)).use { zos ->
return zipFile(
srcFile,
"",
zos,
comment
)
}
}
@Throws(IOException::class)
private fun zipFile(
srcFile: File,
rootPath: String,
zos: ZipOutputStream,
comment: String?
): Boolean {
var rootPath = rootPath
if (!srcFile.exists()) return true
rootPath = rootPath + (if (isSpace(rootPath)) "" else File.separator) + srcFile.name
if (srcFile.isDirectory) {
val fileList = srcFile.listFiles()
if (fileList == null || fileList.isEmpty()) {
val entry = ZipEntry("$rootPath/")
entry.comment = comment
zos.putNextEntry(entry)
zos.closeEntry()
} else {
for (file in fileList) {
if (!zipFile(file, rootPath, zos, comment)) return false
}
}
} else {
BufferedInputStream(FileInputStream(srcFile)).use { `is` ->
val entry = ZipEntry(rootPath)
entry.comment = comment
zos.putNextEntry(entry)
zos.write(`is`.readBytes())
zos.closeEntry()
}
}
return true
}
/**
* Unzip the file.
*
* @param zipFilePath The path of ZIP file.
* @param destDirPath The path of destination directory.
* @return the unzipped files
* @throws IOException if unzip unsuccessfully
*/
@Throws(IOException::class)
fun unzipFile(zipFilePath: String, destDirPath: String): List<File>? {
return unzipFileByKeyword(zipFilePath, destDirPath, null)
}
/**
* Unzip the file.
*
* @param zipFile The ZIP file.
* @param destDir The destination directory.
* @return the unzipped files
* @throws IOException if unzip unsuccessfully
*/
@Throws(IOException::class)
fun unzipFile(
zipFile: File,
destDir: File
): List<File>? {
return unzipFileByKeyword(zipFile, destDir, null)
}
/**
* Unzip the file by keyword.
*
* @param zipFilePath The path of ZIP file.
* @param destDirPath The path of destination directory.
* @param keyword The keyboard.
* @return the unzipped files
* @throws IOException if unzip unsuccessfully
*/
@Throws(IOException::class)
fun unzipFileByKeyword(
zipFilePath: String,
destDirPath: String,
keyword: String?
): List<File>? {
return unzipFileByKeyword(
getFileByPath(zipFilePath),
getFileByPath(destDirPath),
keyword
)
}
/**
* Unzip the file by keyword.
*
* @param zipFile The ZIP file.
* @param destDir The destination directory.
* @param keyword The keyboard.
* @return the unzipped files
* @throws IOException if unzip unsuccessfully
*/
@Throws(IOException::class)
fun unzipFileByKeyword(
zipFile: File?,
destDir: File?,
keyword: String?
): List<File>? {
if (zipFile == null || destDir == null) return null
val files = ArrayList<File>()
val zip = ZipFile(zipFile)
val entries = zip.entries()
try {
if (isSpace(keyword)) {
while (entries.hasMoreElements()) {
val entry = entries.nextElement() as ZipEntry
val entryName = entry.name
if (entryName.contains("../")) {
Log.e("ZipUtils", "entryName: $entryName is dangerous!")
continue
}
if (!unzipChildFile(destDir, files, zip, entry, entryName)) return files
}
} else {
while (entries.hasMoreElements()) {
val entry = entries.nextElement() as ZipEntry
val entryName = entry.name
if (entryName.contains("../")) {
Log.e("ZipUtils", "entryName: $entryName is dangerous!")
continue
}
if (entryName.contains(keyword!!)) {
if (!unzipChildFile(destDir, files, zip, entry, entryName)) return files
}
}
}
} finally {
zip.close()
}
return files
}
@Throws(IOException::class)
private fun unzipChildFile(
destDir: File,
files: MutableList<File>,
zip: ZipFile,
entry: ZipEntry,
name: String
): Boolean {
val file = File(destDir, name)
files.add(file)
if (entry.isDirectory) {
return createOrExistsDir(file)
} else {
if (!createOrExistsFile(file)) return false
BufferedInputStream(zip.getInputStream(entry)).use { `in` ->
BufferedOutputStream(FileOutputStream(file)).use { out ->
out.write(`in`.readBytes())
}
}
}
return true
}
/**
* Return the files' path in ZIP file.
*
* @param zipFilePath The path of ZIP file.
* @return the files' path in ZIP file
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun getFilesPath(zipFilePath: String): List<String>? {
return getFilesPath(getFileByPath(zipFilePath))
}
/**
* Return the files' path in ZIP file.
*
* @param zipFile The ZIP file.
* @return the files' path in ZIP file
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun getFilesPath(zipFile: File?): List<String>? {
if (zipFile == null) return null
val paths = ArrayList<String>()
val zip = ZipFile(zipFile)
val entries = zip.entries()
while (entries.hasMoreElements()) {
val entryName = (entries.nextElement() as ZipEntry).name
if (entryName.contains("../")) {
Log.e("ZipUtils", "entryName: $entryName is dangerous!")
paths.add(entryName)
} else {
paths.add(entryName)
}
}
zip.close()
return paths
}
/**
* Return the files' comment in ZIP file.
*
* @param zipFilePath The path of ZIP file.
* @return the files' comment in ZIP file
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun getComments(zipFilePath: String): List<String>? {
return getComments(getFileByPath(zipFilePath))
}
/**
* Return the files' comment in ZIP file.
*
* @param zipFile The ZIP file.
* @return the files' comment in ZIP file
* @throws IOException if an I/O error has occurred
*/
@Throws(IOException::class)
fun getComments(zipFile: File?): List<String>? {
if (zipFile == null) return null
val comments = ArrayList<String>()
val zip = ZipFile(zipFile)
val entries = zip.entries()
while (entries.hasMoreElements()) {
val entry = entries.nextElement() as ZipEntry
comments.add(entry.comment)
}
zip.close()
return comments
}
private fun createOrExistsDir(file: File?): Boolean {
return file != null && if (file.exists()) file.isDirectory else file.mkdirs()
}
private fun createOrExistsFile(file: File?): Boolean {
if (file == null) return false
if (file.exists()) return file.isFile
if (!createOrExistsDir(file.parentFile)) return false
return try {
file.createNewFile()
} catch (e: IOException) {
e.printStackTrace()
false
}
}
private fun getFileByPath(filePath: String): File? {
return if (isSpace(filePath)) null else File(filePath)
}
private fun isSpace(s: String?): Boolean {
if (s == null) return true
var i = 0
val len = s.length
while (i < len) {
if (!Character.isWhitespace(s[i])) {
return false
}
++i
}
return true
}
}
Loading…
Cancel
Save