Merge pull request #2365 from Xwite/master

feat: 实现本地文件不存在时自动下载webDav文件
pull/2368/head
kunfei 2 years ago committed by GitHub
commit e230d92131
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      app/src/main/java/io/legado/app/data/entities/Book.kt
  2. 42
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  3. 5
      app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
  4. 3
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBookManager.kt
  5. 4
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBookViewModel.kt
  6. 11
      app/src/main/java/io/legado/app/ui/book/remote/manager/RemoteBookWebDav.kt

@ -14,6 +14,7 @@ import io.legado.app.model.ReadBook
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import io.legado.app.utils.MD5Utils import io.legado.app.utils.MD5Utils
import io.legado.app.utils.fromJsonObject import io.legado.app.utils.fromJsonObject
import io.legado.app.utils.isUri
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@ -108,7 +109,9 @@ data class Book(
) : Parcelable, BaseBook { ) : Parcelable, BaseBook {
fun isLocalBook(): Boolean { fun isLocalBook(): Boolean {
return origin == BookType.local //通过判断书籍链接来判断http* file:// content://
//origin判断不可靠 http* BookType.local webDav::
return origin == BookType.local || bookUrl.isUri()
} }
fun isLocalTxt(): Boolean { fun isLocalTxt(): Boolean {

@ -7,6 +7,7 @@ import com.script.SimpleBindings
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.constant.AppLog import io.legado.app.constant.AppLog
import io.legado.app.constant.BookType
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.BaseSource import io.legado.app.data.entities.BaseSource
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
@ -15,12 +16,15 @@ import io.legado.app.exception.NoStackTraceException
import io.legado.app.exception.TocEmptyException import io.legado.app.exception.TocEmptyException
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.AppWebDav
import io.legado.app.lib.webdav.WebDav
import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.utils.* import io.legado.app.utils.*
import org.jsoup.nodes.Entities import org.jsoup.nodes.Entities
import splitties.init.appCtx import splitties.init.appCtx
import java.io.* import java.io.*
import java.util.regex.Pattern import java.util.regex.Pattern
import kotlinx.coroutines.runBlocking
/** /**
* 书籍文件导入 目录正文解析 * 书籍文件导入 目录正文解析
@ -38,13 +42,9 @@ object LocalBook {
@Throws(FileNotFoundException::class, SecurityException::class) @Throws(FileNotFoundException::class, SecurityException::class)
fun getBookInputStream(book: Book): InputStream { fun getBookInputStream(book: Book): InputStream {
val uri = Uri.parse(book.bookUrl) val uri = Uri.parse(book.bookUrl)
if (uri.isContentScheme()) { //文件不存在 尝试下载webDav文件 book.remoteUrl
return appCtx.contentResolver.openInputStream(uri)!! val inputStream = uri.inputStream(appCtx) ?: downloadRemoteBook(book)
} if (inputStream != null) return inputStream
val file = File(uri.path!!)
if (file.exists()) {
return FileInputStream(File(uri.path!!))
}
throw FileNotFoundException("${uri.path} 文件不存在") throw FileNotFoundException("${uri.path} 文件不存在")
} }
@ -302,4 +302,32 @@ object LocalBook {
return localBook return localBook
} }
//下载book.remoteUrl对应的远程文件并更新bookUrl 返回inputStream
private fun downloadRemoteBook(localBook: Book): InputStream? {
if (localBook.origin == BookType.local) return null
//webDav::${http}
val webDavUrl = localBook.origin.split("::").getOrNull(1)
webDavUrl ?: return null
try {
val uri = AppWebDav.authorization?.let {
val webdav = WebDav(webDavUrl, it)
runBlocking {
webdav.downloadInputStream().let { inputStream ->
saveBookFile(inputStream, localBook.originName)
}
}
}
return uri?.let {
localBook.bookUrl = if (it.isContentScheme()) it.toString()
else it.path!!
localBook.save()
it.inputStream(appCtx)
}
} catch (e: Exception) {
e.printOnDebug()
AppLog.put("自动下载webDav书籍失败", e)
}
return null
}
} }

@ -207,12 +207,12 @@ class BookInfoActivity :
R.id.menu_upload -> { R.id.menu_upload -> {
launch { launch {
val uri = Uri.parse(viewModel.bookData.value?.bookUrl.toString()) viewModel.bookData.value?.let {
val waitDialog = WaitDialog(this@BookInfoActivity) val waitDialog = WaitDialog(this@BookInfoActivity)
waitDialog.setText("上传中.....") waitDialog.setText("上传中.....")
waitDialog.show() waitDialog.show()
try { try {
val isUpload = RemoteBookWebDav.upload(uri) val isUpload = RemoteBookWebDav.upload(it)
if (isUpload) if (isUpload)
toastOnUi(getString(R.string.upload_book_success)) toastOnUi(getString(R.string.upload_book_success))
else else
@ -225,6 +225,7 @@ class BookInfoActivity :
} }
} }
} }
}
return super.onCompatOptionsItemSelected(item) return super.onCompatOptionsItemSelected(item)
} }

@ -1,12 +1,13 @@
package io.legado.app.ui.book.remote package io.legado.app.ui.book.remote
import android.net.Uri import android.net.Uri
import io.legado.app.data.entities.Book
abstract class RemoteBookManager { abstract class RemoteBookManager {
protected val remoteBookFolder : String = "books" protected val remoteBookFolder : String = "books"
abstract suspend fun initRemoteContext() abstract suspend fun initRemoteContext()
abstract suspend fun getRemoteBookList(path: String): MutableList<RemoteBook> abstract suspend fun getRemoteBookList(path: String): MutableList<RemoteBook>
abstract suspend fun upload(localBookUri: Uri): Boolean abstract suspend fun upload(book: Book): Boolean
abstract suspend fun delete(remoteBookUrl: String): Boolean abstract suspend fun delete(remoteBookUrl: String): Boolean
/** /**

@ -95,7 +95,9 @@ class RemoteBookViewModel(application: Application) : BaseViewModel(application)
remoteBooks.forEach { remoteBook -> remoteBooks.forEach { remoteBook ->
val downloadBookPath = RemoteBookWebDav.getRemoteBook(remoteBook) val downloadBookPath = RemoteBookWebDav.getRemoteBook(remoteBook)
downloadBookPath?.let { downloadBookPath?.let {
LocalBook.importFile(it) val localBook = LocalBook.importFile(it)
localBook.origin= "webDav::" + remoteBook.path
localBook.save()
remoteBook.isOnBookShelf = true remoteBook.isOnBookShelf = true
} }
} }

@ -1,8 +1,8 @@
package io.legado.app.ui.book.remote.manager package io.legado.app.ui.book.remote.manager
import android.net.Uri import android.net.Uri
import io.legado.app.constant.AppPattern.bookFileRegex import io.legado.app.constant.AppPattern.bookFileRegex
import io.legado.app.data.entities.Book
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.AppWebDav import io.legado.app.help.AppWebDav
import io.legado.app.lib.webdav.WebDav import io.legado.app.lib.webdav.WebDav
@ -85,11 +85,10 @@ object RemoteBookWebDav : RemoteBookManager() {
/** /**
* 上传本地导入的书籍到远程 * 上传本地导入的书籍到远程
*/ */
override suspend fun upload(localBookUri: Uri): Boolean { override suspend fun upload(book: Book): Boolean {
if (!NetworkUtils.isAvailable()) return false if (!NetworkUtils.isAvailable()) return false
val localBookUri = Uri.parse(book.bookUrl)
val localBookName = localBookUri.path?.substringAfterLast(File.separator) val putUrl = "${rootBookUrl}${File.separator}${book.originName}"
val putUrl = "${rootBookUrl}${File.separator}${localBookName}"
AppWebDav.authorization?.let { AppWebDav.authorization?.let {
if (localBookUri.isContentScheme()) { if (localBookUri.isContentScheme()) {
WebDav(putUrl, it).upload( WebDav(putUrl, it).upload(
@ -100,6 +99,8 @@ object RemoteBookWebDav : RemoteBookManager() {
WebDav(putUrl, it).upload(localBookUri.path!!) WebDav(putUrl, it).upload(localBookUri.path!!)
} }
} }
book.origin = "webDav::" + putUrl
book.save()
return true return true
} }

Loading…
Cancel
Save