Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package io.legado.app.help
|
package io.legado.app.help
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.constant.AppLog
|
import io.legado.app.constant.AppLog
|
||||||
import io.legado.app.constant.PreferKey
|
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) {
|
fun uploadBookProgress(book: Book) {
|
||||||
val authorization = authorization ?: return
|
val authorization = authorization ?: return
|
||||||
if (!syncBookProgress) return
|
if (!syncBookProgress) return
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.legado.app.lib.webdav
|
package io.legado.app.lib.webdav
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.net.Uri
|
||||||
import io.legado.app.constant.AppLog
|
import io.legado.app.constant.AppLog
|
||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
import io.legado.app.help.http.newCallResponse
|
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.help.http.text
|
||||||
import io.legado.app.utils.NetworkUtils
|
import io.legado.app.utils.NetworkUtils
|
||||||
import io.legado.app.utils.printOnDebug
|
import io.legado.app.utils.printOnDebug
|
||||||
|
import io.legado.app.utils.toRequestBody
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.Interceptor
|
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)
|
@Throws(WebDavException::class)
|
||||||
suspend fun downloadInputStream(): InputStream {
|
suspend fun downloadInputStream(): InputStream {
|
||||||
val url = httpUrl ?: throw WebDavException("WebDav下载出错\nurl为空")
|
val url = httpUrl ?: throw WebDavException("WebDav下载出错\nurl为空")
|
||||||
|
|||||||
+16
-19
@@ -122,7 +122,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
exportMsg[book.bookUrl] = context.getString(R.string.export_success)
|
exportMsg[book.bookUrl] = context.getString(R.string.export_success)
|
||||||
upAdapterLiveData.postValue(book.bookUrl)
|
upAdapterLiveData.postValue(book.bookUrl)
|
||||||
}.onFinally {
|
}.onFinally {
|
||||||
exportNumber--
|
mutex.withLock {
|
||||||
|
exportNumber--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,14 +134,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
DocumentUtils.delete(doc, filename)
|
DocumentUtils.delete(doc, filename)
|
||||||
val bookDoc = DocumentUtils.createFileIfNotExist(doc, filename)
|
val bookDoc = DocumentUtils.createFileIfNotExist(doc, filename)
|
||||||
?: throw NoStackTraceException("创建文档失败,请尝试重新设置导出文件夹")
|
?: throw NoStackTraceException("创建文档失败,请尝试重新设置导出文件夹")
|
||||||
val stringBuilder = StringBuilder()
|
|
||||||
val exportToWebDav = AppConfig.exportToWebDav
|
|
||||||
context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
|
context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
|
||||||
getAllContents(book) { text, srcList ->
|
getAllContents(book) { text, srcList ->
|
||||||
bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset)))
|
bookOs.write(text.toByteArray(Charset.forName(AppConfig.exportCharset)))
|
||||||
if (exportToWebDav) {
|
|
||||||
stringBuilder.append(text)
|
|
||||||
}
|
|
||||||
srcList?.forEach {
|
srcList?.forEach {
|
||||||
val vFile = BookHelp.getImage(book, it.third)
|
val vFile = BookHelp.getImage(book, it.third)
|
||||||
if (vFile.exists()) {
|
if (vFile.exists()) {
|
||||||
@@ -154,9 +151,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
if (AppConfig.exportToWebDav) {
|
if (AppConfig.exportToWebDav) {
|
||||||
// 导出到webdav
|
// 导出到webdav
|
||||||
val byteArray =
|
AppWebDav.exportWebDav(bookDoc.uri, filename)
|
||||||
stringBuilder.toString().toByteArray(Charset.forName(AppConfig.exportCharset))
|
|
||||||
AppWebDav.exportWebDav(byteArray, filename)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,13 +159,8 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
val filename = "${getExportFileName(book)}.txt"
|
val filename = "${getExportFileName(book)}.txt"
|
||||||
val bookPath = FileUtils.getPath(file, filename)
|
val bookPath = FileUtils.getPath(file, filename)
|
||||||
val bookFile = FileUtils.createFileWithReplace(bookPath)
|
val bookFile = FileUtils.createFileWithReplace(bookPath)
|
||||||
val stringBuilder = StringBuilder()
|
|
||||||
val exportToWebDav = AppConfig.exportToWebDav
|
|
||||||
getAllContents(book) { text, srcList ->
|
getAllContents(book) { text, srcList ->
|
||||||
bookFile.appendText(text, Charset.forName(AppConfig.exportCharset))
|
bookFile.appendText(text, Charset.forName(AppConfig.exportCharset))
|
||||||
if (exportToWebDav) {
|
|
||||||
stringBuilder.append(text)
|
|
||||||
}
|
|
||||||
srcList?.forEach {
|
srcList?.forEach {
|
||||||
val vFile = BookHelp.getImage(book, it.third)
|
val vFile = BookHelp.getImage(book, it.third)
|
||||||
if (vFile.exists()) {
|
if (vFile.exists()) {
|
||||||
@@ -185,9 +175,7 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (AppConfig.exportToWebDav) {
|
if (AppConfig.exportToWebDav) {
|
||||||
val byteArray =
|
AppWebDav.exportWebDav(Uri.fromFile(bookFile), filename) // 导出到webdav
|
||||||
stringBuilder.toString().toByteArray(Charset.forName(AppConfig.exportCharset))
|
|
||||||
AppWebDav.exportWebDav(byteArray, filename) // 导出到webdav
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +287,9 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
exportMsg[book.bookUrl] = context.getString(R.string.export_success)
|
exportMsg[book.bookUrl] = context.getString(R.string.export_success)
|
||||||
upAdapterLiveData.postValue(book.bookUrl)
|
upAdapterLiveData.postValue(book.bookUrl)
|
||||||
}.onFinally {
|
}.onFinally {
|
||||||
exportNumber--
|
mutex.withLock {
|
||||||
|
exportNumber--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +312,10 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
|
context.contentResolver.openOutputStream(bookDoc.uri, "wa")?.use { bookOs ->
|
||||||
EpubWriter().write(epubBook, 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)
|
setEpubContent(contentModel, book, epubBook)
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
EpubWriter().write(epubBook, FileOutputStream(bookFile))
|
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 {
|
private fun setAssets(doc: DocumentFile, book: Book, epubBook: EpubBook): String {
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ import io.legado.app.constant.AppLog
|
|||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
import io.legado.app.lib.permission.Permissions
|
import io.legado.app.lib.permission.Permissions
|
||||||
import io.legado.app.lib.permission.PermissionsCompat
|
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.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@@ -197,4 +202,22 @@ fun Uri.inputStream(context: Context): Result<InputStream> {
|
|||||||
throw e
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user