Explorar el Código

Merge remote-tracking branch 'origin/master'

kunfei hace 4 años
padre
commit
9cc4dd6bd6

+ 16 - 0
app/src/main/java/io/legado/app/help/AppWebDav.kt

@@ -1,6 +1,7 @@
 package io.legado.app.help
 
 import android.content.Context
+import android.net.Uri
 import io.legado.app.R
 import io.legado.app.constant.AppLog
 import io.legado.app.constant.PreferKey
@@ -207,6 +208,21 @@ object AppWebDav {
         }
     }
 
+    suspend fun exportWebDav(uri: Uri, fileName: String) {
+        if (!NetworkUtils.isAvailable()) return
+        try {
+            authorization?.let {
+                // 如果导出的本地文件存在,开始上传
+                val putUrl = exportsWebDavUrl + fileName
+                WebDav(putUrl, it).upload(uri, "text/plain")
+            }
+        } catch (e: Exception) {
+            val msg = "WebDav导出\n${e.localizedMessage}"
+            AppLog.put(msg, e)
+            appCtx.toastOnUi(msg)
+        }
+    }
+
     fun uploadBookProgress(book: Book) {
         val authorization = authorization ?: return
         if (!syncBookProgress) return

+ 22 - 0
app/src/main/java/io/legado/app/lib/webdav/WebDav.kt

@@ -1,6 +1,7 @@
 package io.legado.app.lib.webdav
 
 import android.annotation.SuppressLint
+import android.net.Uri
 import io.legado.app.constant.AppLog
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.help.http.newCallResponse
@@ -8,6 +9,7 @@ import io.legado.app.help.http.okHttpClient
 import io.legado.app.help.http.text
 import io.legado.app.utils.NetworkUtils
 import io.legado.app.utils.printOnDebug
+import io.legado.app.utils.toRequestBody
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.withContext
 import okhttp3.Interceptor
@@ -316,6 +318,26 @@ open class WebDav(val path: String, val authorization: Authorization) {
         }
     }
 
+    @Throws(WebDavException::class)
+    suspend fun upload(uri: Uri, contentType: String) {
+        // 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
+        kotlin.runCatching {
+            withContext(IO) {
+                val fileBody = uri.toRequestBody(contentType.toMediaType())
+                val url = httpUrl ?: throw NoStackTraceException("url不能为空")
+                webDavClient.newCallResponse {
+                    url(url)
+                    put(fileBody)
+                }.let {
+                    checkResult(it)
+                }
+            }
+        }.onFailure {
+            AppLog.put("WebDav上传失败\n${it.localizedMessage}", it)
+            throw WebDavException("WebDav上传失败\n${it.localizedMessage}")
+        }
+    }
+
     @Throws(WebDavException::class)
     suspend fun downloadInputStream(): InputStream {
         val url = httpUrl ?: throw WebDavException("WebDav下载出错\nurl为空")

+ 16 - 19
app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt

@@ -122,7 +122,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
             exportMsg[book.bookUrl] = context.getString(R.string.export_success)
             upAdapterLiveData.postValue(book.bookUrl)
         }.onFinally {
-            exportNumber--
+            mutex.withLock {
+                exportNumber--
+            }
         }
     }
 
@@ -132,14 +134,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
         DocumentUtils.delete(doc, filename)
         val bookDoc = DocumentUtils.createFileIfNotExist(doc, filename)
             ?: throw NoStackTraceException("创建文档失败,请尝试重新设置导出文件夹")
-        val stringBuilder = StringBuilder()
-        val exportToWebDav = AppConfig.exportToWebDav
         context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
             getAllContents(book) { text, srcList ->
                 bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset)))
-                if (exportToWebDav) {
-                    stringBuilder.append(text)
-                }
                 srcList?.forEach {
                     val vFile = BookHelp.getImage(book, it.third)
                     if (vFile.exists()) {
@@ -154,9 +151,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
         }
         if (AppConfig.exportToWebDav) {
             // 导出到webdav
-            val byteArray =
-                stringBuilder.toString().toByteArray(Charset.forName(AppConfig.exportCharset))
-            AppWebDav.exportWebDav(byteArray, filename)
+            AppWebDav.exportWebDav(bookDoc.uri, filename)
         }
     }
 
@@ -164,13 +159,8 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
         val filename = "${getExportFileName(book)}.txt"
         val bookPath = FileUtils.getPath(file, filename)
         val bookFile = FileUtils.createFileWithReplace(bookPath)
-        val stringBuilder = StringBuilder()
-        val exportToWebDav = AppConfig.exportToWebDav
         getAllContents(book) { text, srcList ->
             bookFile.appendText(text, Charset.forName(AppConfig.exportCharset))
-            if (exportToWebDav) {
-                stringBuilder.append(text)
-            }
             srcList?.forEach {
                 val vFile = BookHelp.getImage(book, it.third)
                 if (vFile.exists()) {
@@ -185,9 +175,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
             }
         }
         if (AppConfig.exportToWebDav) {
-            val byteArray =
-                stringBuilder.toString().toByteArray(Charset.forName(AppConfig.exportCharset))
-            AppWebDav.exportWebDav(byteArray, filename) // 导出到webdav
+            AppWebDav.exportWebDav(Uri.fromFile(bookFile), filename) // 导出到webdav
         }
     }
 
@@ -299,7 +287,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
             exportMsg[book.bookUrl] = context.getString(R.string.export_success)
             upAdapterLiveData.postValue(book.bookUrl)
         }.onFinally {
-            exportNumber--
+            mutex.withLock {
+                exportNumber--
+            }
         }
     }
 
@@ -322,7 +312,10 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
             context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
                 EpubWriter().write(epubBook, bookOs)
             }
-
+            if (AppConfig.exportToWebDav) {
+                // 导出到webdav
+                AppWebDav.exportWebDav(bookDoc.uri, filename)
+            }
         }
     }
 
@@ -344,6 +337,10 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
         setEpubContent(contentModel, book, epubBook)
         @Suppress("BlockingMethodInNonBlockingContext")
         EpubWriter().write(epubBook, FileOutputStream(bookFile))
+        if (AppConfig.exportToWebDav) {
+            // 导出到webdav
+            AppWebDav.exportWebDav(Uri.fromFile(bookFile), filename)
+        }
     }
 
     private fun setAssets(doc: DocumentFile, book: Book, epubBook: EpubBook): String {

+ 23 - 0
app/src/main/java/io/legado/app/utils/UriExtensions.kt

@@ -10,6 +10,11 @@ import io.legado.app.constant.AppLog
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.lib.permission.Permissions
 import io.legado.app.lib.permission.PermissionsCompat
+import okhttp3.MediaType
+import okhttp3.RequestBody
+import okio.BufferedSink
+import okio.source
+import splitties.init.appCtx
 import java.io.File
 import java.io.FileInputStream
 import java.io.InputStream
@@ -197,4 +202,22 @@ fun Uri.inputStream(context: Context): Result<InputStream> {
             throw e
         }
     }
+}
+
+fun Uri.toRequestBody(contentType: MediaType? = null): RequestBody {
+    val uri = this
+    return object : RequestBody() {
+        override fun contentType() = contentType
+
+        override fun contentLength(): Long {
+            val length = uri.inputStream(appCtx).getOrThrow().available().toLong()
+            return if (length > 0) length else -1
+        }
+
+        override fun writeTo(sink: BufferedSink) {
+            uri.inputStream(appCtx).getOrThrow().source().use { source ->
+                sink.writeAll(source)
+            }
+        }
+    }
 }