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