优化
This commit is contained in:
@@ -12,7 +12,7 @@ import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.lib.dialogs.selector
|
||||
import io.legado.app.lib.webdav.HttpAuth
|
||||
import io.legado.app.lib.webdav.Authorization
|
||||
import io.legado.app.lib.webdav.WebDav
|
||||
import io.legado.app.utils.*
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
@@ -31,7 +31,9 @@ object AppWebDav {
|
||||
|
||||
val syncBookProgress get() = appCtx.getPrefBoolean(PreferKey.syncBookProgress, true)
|
||||
|
||||
var isOk = false
|
||||
var authorization: Authorization? = null
|
||||
|
||||
val isOk get() = authorization != null
|
||||
|
||||
init {
|
||||
runBlocking {
|
||||
@@ -61,14 +63,15 @@ object AppWebDav {
|
||||
|
||||
suspend fun upConfig() {
|
||||
kotlin.runCatching {
|
||||
isOk = false
|
||||
authorization = null
|
||||
val account = appCtx.getPrefString(PreferKey.webDavAccount)
|
||||
val password = appCtx.getPrefString(PreferKey.webDavPassword)
|
||||
if (!account.isNullOrBlank() && !password.isNullOrBlank()) {
|
||||
HttpAuth.auth = HttpAuth.Auth(account, password)
|
||||
WebDav(rootWebDavUrl).makeAsDir()
|
||||
WebDav(bookProgressUrl).makeAsDir()
|
||||
isOk = true
|
||||
val mAuthorization = Authorization(account, password)
|
||||
WebDav(rootWebDavUrl, mAuthorization).makeAsDir()
|
||||
WebDav(bookProgressUrl, mAuthorization).makeAsDir()
|
||||
|
||||
authorization = mAuthorization
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,18 +80,16 @@ object AppWebDav {
|
||||
private suspend fun getWebDavFileNames(): ArrayList<String> {
|
||||
val url = rootWebDavUrl
|
||||
val names = arrayListOf<String>()
|
||||
if (isOk) {
|
||||
var files = WebDav(url).listFiles()
|
||||
authorization?.let {
|
||||
var files = WebDav(url, it).listFiles()
|
||||
files = files.reversed()
|
||||
files.forEach {
|
||||
val name = it.displayName
|
||||
files.forEach { webDav ->
|
||||
val name = webDav.displayName
|
||||
if (name?.startsWith("backup") == true) {
|
||||
names.add(name)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw NoStackTraceException("webDav没有配置")
|
||||
}
|
||||
} ?: throw NoStackTraceException("webDav没有配置")
|
||||
return names
|
||||
}
|
||||
|
||||
@@ -115,8 +116,8 @@ object AppWebDav {
|
||||
}
|
||||
|
||||
private suspend fun restoreWebDav(name: String) {
|
||||
rootWebDavUrl.let {
|
||||
val webDav = WebDav(it + name)
|
||||
authorization?.let {
|
||||
val webDav = WebDav(rootWebDavUrl + name, it)
|
||||
webDav.downloadTo(zipFilePath, true)
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
ZipUtils.unzipFile(zipFilePath, Backup.backupPath)
|
||||
@@ -126,16 +127,16 @@ object AppWebDav {
|
||||
}
|
||||
|
||||
suspend fun hasBackUp(): Boolean {
|
||||
if (isOk) {
|
||||
authorization?.let {
|
||||
val url = "${rootWebDavUrl}${backupFileName}"
|
||||
return WebDav(url).exists()
|
||||
return WebDav(url, it).exists()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
suspend fun backUpWebDav(path: String) {
|
||||
try {
|
||||
if (isOk && NetworkUtils.isAvailable()) {
|
||||
authorization?.let {
|
||||
val paths = arrayListOf(*Backup.backupFileNames)
|
||||
for (i in 0 until paths.size) {
|
||||
paths[i] = path + File.separator + paths[i]
|
||||
@@ -143,7 +144,7 @@ object AppWebDav {
|
||||
FileUtils.delete(zipFilePath)
|
||||
if (ZipUtils.zipFiles(paths, zipFilePath)) {
|
||||
val putUrl = "${rootWebDavUrl}${backupFileName}"
|
||||
WebDav(putUrl).upload(zipFilePath)
|
||||
WebDav(putUrl, it).upload(zipFilePath)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@@ -153,14 +154,14 @@ object AppWebDav {
|
||||
|
||||
suspend fun exportWebDav(byteArray: ByteArray, fileName: String) {
|
||||
try {
|
||||
if (isOk && NetworkUtils.isAvailable()) {
|
||||
authorization?.let {
|
||||
// 默认导出到legado文件夹下exports目录
|
||||
val exportsWebDavUrl = rootWebDavUrl + EncoderUtils.escape("exports") + "/"
|
||||
// 在legado文件夹创建exports目录,如果不存在的话
|
||||
WebDav(exportsWebDavUrl).makeAsDir()
|
||||
WebDav(exportsWebDavUrl, it).makeAsDir()
|
||||
// 如果导出的本地文件存在,开始上传
|
||||
val putUrl = exportsWebDavUrl + fileName
|
||||
WebDav(putUrl).upload(byteArray, "text/plain")
|
||||
WebDav(putUrl, it).upload(byteArray, "text/plain")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
@@ -170,14 +171,14 @@ object AppWebDav {
|
||||
}
|
||||
|
||||
fun uploadBookProgress(book: Book) {
|
||||
if (!isOk) return
|
||||
val authorization = authorization ?: return
|
||||
if (!syncBookProgress) return
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
Coroutine.async {
|
||||
val bookProgress = BookProgress(book)
|
||||
val json = GSON.toJson(bookProgress)
|
||||
val url = getProgressUrl(book)
|
||||
WebDav(url).upload(json.toByteArray(), "application/json")
|
||||
WebDav(url, authorization).upload(json.toByteArray(), "application/json")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,9 +190,9 @@ object AppWebDav {
|
||||
* 获取书籍进度
|
||||
*/
|
||||
suspend fun getBookProgress(book: Book): BookProgress? {
|
||||
if (isOk && NetworkUtils.isAvailable()) {
|
||||
authorization?.let {
|
||||
val url = getProgressUrl(book)
|
||||
WebDav(url).download()?.let { byteArray ->
|
||||
WebDav(url, it).download()?.let { byteArray ->
|
||||
val json = String(byteArray)
|
||||
if (json.isJson()) {
|
||||
return GSON.fromJsonObject<BookProgress>(json).getOrNull()
|
||||
@@ -202,7 +203,7 @@ object AppWebDav {
|
||||
}
|
||||
|
||||
suspend fun downloadAllBookProgress() {
|
||||
if (!isOk) return
|
||||
authorization ?: return
|
||||
appDb.bookDao.all.forEach { book ->
|
||||
getBookProgress(book)?.let { bookProgress ->
|
||||
if (bookProgress.durChapterIndex > book.durChapterIndex ||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.legado.app.lib.webdav
|
||||
|
||||
import okhttp3.Credentials
|
||||
import java.nio.charset.Charset
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
data class Authorization(
|
||||
val username: String,
|
||||
val password: String,
|
||||
val charset: Charset = StandardCharsets.ISO_8859_1
|
||||
) {
|
||||
|
||||
val data: String = Credentials.basic(username, password, charset)
|
||||
|
||||
override fun toString(): String {
|
||||
return data
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package io.legado.app.lib.webdav
|
||||
|
||||
object HttpAuth {
|
||||
|
||||
var auth: Auth? = null
|
||||
|
||||
class Auth internal constructor(val user: String, val pass: String)
|
||||
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
package io.legado.app.lib.webdav
|
||||
|
||||
import android.util.Log
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.help.http.newCallResponse
|
||||
import io.legado.app.help.http.newCallResponseBody
|
||||
import io.legado.app.help.http.okHttpClient
|
||||
import io.legado.app.help.http.text
|
||||
import io.legado.app.utils.printOnDebug
|
||||
import okhttp3.Credentials
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.net.MalformedURLException
|
||||
@@ -19,7 +19,7 @@ import java.net.URL
|
||||
import java.net.URLEncoder
|
||||
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
class WebDav(urlStr: String) {
|
||||
class WebDav(urlStr: String, val authorization: Authorization) {
|
||||
companion object {
|
||||
// 指定返回哪些属性
|
||||
@Language("xml")
|
||||
@@ -88,24 +88,20 @@ class WebDav(urlStr: String) {
|
||||
} else {
|
||||
String.format(DIR, requestProps.toString() + "\n")
|
||||
}
|
||||
val url = httpUrl
|
||||
val auth = HttpAuth.auth
|
||||
if (url != null && auth != null) {
|
||||
return kotlin.runCatching {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
|
||||
addHeader("Depth", "1")
|
||||
// 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性
|
||||
// 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。
|
||||
val requestBody = requestPropsStr.toRequestBody("text/plain".toMediaType())
|
||||
method("PROPFIND", requestBody)
|
||||
}.text()
|
||||
}.onFailure { e ->
|
||||
e.printOnDebug()
|
||||
}.getOrNull()
|
||||
}
|
||||
return null
|
||||
val url = httpUrl ?: return null
|
||||
return kotlin.runCatching {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
addHeader("Authorization", authorization.data)
|
||||
addHeader("Depth", "1")
|
||||
// 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性
|
||||
// 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。
|
||||
val requestBody = requestPropsStr.toRequestBody("text/plain".toMediaType())
|
||||
method("PROPFIND", requestBody)
|
||||
}.text()
|
||||
}.onFailure { e ->
|
||||
e.printOnDebug()
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
private fun parseDir(s: String): List<WebDav> {
|
||||
@@ -120,7 +116,7 @@ class WebDav(urlStr: String) {
|
||||
val fileName = href.substring(href.lastIndexOf("/") + 1)
|
||||
val webDavFile: WebDav
|
||||
try {
|
||||
webDavFile = WebDav(baseUrl + fileName)
|
||||
webDavFile = WebDav(baseUrl + fileName, authorization)
|
||||
webDavFile.displayName = fileName
|
||||
webDavFile.contentType = element
|
||||
.getElementsByTag("d:getcontenttype")
|
||||
@@ -157,23 +153,19 @@ class WebDav(urlStr: String) {
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
suspend fun makeAsDir(): Boolean {
|
||||
val url = httpUrl
|
||||
val auth = HttpAuth.auth
|
||||
if (url != null && auth != null) {
|
||||
//防止报错
|
||||
return kotlin.runCatching {
|
||||
if (!exists()) {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
method("MKCOL", null)
|
||||
addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
|
||||
}.close()
|
||||
}
|
||||
}.onFailure {
|
||||
AppLog.put(it.localizedMessage)
|
||||
}.isSuccess
|
||||
}
|
||||
return false
|
||||
val url = httpUrl ?: return false
|
||||
//防止报错
|
||||
return kotlin.runCatching {
|
||||
if (!exists()) {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
method("MKCOL", null)
|
||||
addHeader("Authorization", authorization.data)
|
||||
}.close()
|
||||
}
|
||||
}.onFailure {
|
||||
AppLog.put(it.localizedMessage)
|
||||
}.isSuccess
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,49 +200,41 @@ class WebDav(urlStr: String) {
|
||||
if (!file.exists()) return false
|
||||
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
|
||||
val fileBody = file.asRequestBody(contentType.toMediaType())
|
||||
val url = httpUrl
|
||||
val auth = HttpAuth.auth
|
||||
if (url != null && auth != null) {
|
||||
return kotlin.runCatching {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
put(fileBody)
|
||||
addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
|
||||
}.close()
|
||||
}.isSuccess
|
||||
}
|
||||
return false
|
||||
val url = httpUrl ?: return false
|
||||
return kotlin.runCatching {
|
||||
okHttpClient.newCallResponse {
|
||||
url(url)
|
||||
put(fileBody)
|
||||
addHeader("Authorization", authorization.data)
|
||||
}.body?.string()?.let {
|
||||
Log.d("webDav", it)
|
||||
}
|
||||
}.onFailure {
|
||||
it.printOnDebug()
|
||||
}.isSuccess
|
||||
}
|
||||
|
||||
suspend fun upload(byteArray: ByteArray, contentType: String): Boolean {
|
||||
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
|
||||
val fileBody = byteArray.toRequestBody(contentType.toMediaType())
|
||||
val url = httpUrl
|
||||
val auth = HttpAuth.auth
|
||||
if (url != null && auth != null) {
|
||||
return kotlin.runCatching {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
put(fileBody)
|
||||
addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
|
||||
}.close()
|
||||
}.isSuccess
|
||||
}
|
||||
return false
|
||||
val url = httpUrl ?: return false
|
||||
return kotlin.runCatching {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
put(fileBody)
|
||||
addHeader("Authorization", authorization.data)
|
||||
}.close()
|
||||
}.isSuccess
|
||||
}
|
||||
|
||||
private suspend fun getInputStream(): InputStream? {
|
||||
val url = httpUrl
|
||||
val auth = HttpAuth.auth
|
||||
if (url != null && auth != null) {
|
||||
return kotlin.runCatching {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
|
||||
}.byteStream()
|
||||
}.getOrNull()
|
||||
}
|
||||
return null
|
||||
val url = httpUrl ?: return null
|
||||
return kotlin.runCatching {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
addHeader("Authorization", authorization.data)
|
||||
}.byteStream()
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user