This commit is contained in:
kunfei 2023-03-02 11:10:34 +08:00
parent 323854f647
commit eb635cae15
6 changed files with 65 additions and 52 deletions

View File

@ -18,6 +18,7 @@ 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.lib.webdav.WebDavException import io.legado.app.lib.webdav.WebDavException
import io.legado.app.lib.webdav.WebDavFile import io.legado.app.lib.webdav.WebDavFile
import io.legado.app.model.remote.RemoteBookWebDav
import io.legado.app.ui.widget.dialog.WaitDialog import io.legado.app.ui.widget.dialog.WaitDialog
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
@ -78,6 +79,13 @@ object AppWebDav {
} }
} }
fun getDefaultRemoteBookWebDav(): RemoteBookWebDav {
val rootUrl = "${rootWebDavUrl}books"
val authorization = AppWebDav.authorization
?: throw NoStackTraceException("webDav没有配置")
return RemoteBookWebDav(rootUrl, authorization)
}
suspend fun upConfig() { suspend fun upConfig() {
kotlin.runCatching { kotlin.runCatching {
authorization = null authorization = null

View File

@ -4,7 +4,6 @@ import android.net.Uri
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
abstract class RemoteBookManager { abstract class RemoteBookManager {
protected val remoteBookFolder: String = "books"
/** /**
* 获取书籍列表 * 获取书籍列表

View File

@ -5,8 +5,8 @@ import io.legado.app.constant.AppPattern.bookFileRegex
import io.legado.app.constant.BookType import io.legado.app.constant.BookType
import io.legado.app.data.entities.Book 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.config.AppConfig import io.legado.app.help.config.AppConfig
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.lib.webdav.WebDavFile import io.legado.app.lib.webdav.WebDavFile
import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.LocalBook
@ -17,9 +17,8 @@ import kotlinx.coroutines.runBlocking
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
object RemoteBookWebDav : RemoteBookManager() { class RemoteBookWebDav(val rootBookUrl: String, val authorization: Authorization) :
RemoteBookManager() {
val rootBookUrl get() = "${AppWebDav.rootWebDavUrl}${remoteBookFolder}"
init { init {
runBlocking { runBlocking {
@ -28,69 +27,61 @@ object RemoteBookWebDav : RemoteBookManager() {
} }
suspend fun initRemoteContext() { suspend fun initRemoteContext() {
AppWebDav.authorization?.let { WebDav(rootBookUrl, authorization).makeAsDir()
WebDav(rootBookUrl, it).makeAsDir()
}
} }
@Throws(Exception::class) @Throws(Exception::class)
override suspend fun getRemoteBookList(path: String): MutableList<RemoteBook> { override suspend fun getRemoteBookList(path: String): MutableList<RemoteBook> {
if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用")
val remoteBooks = mutableListOf<RemoteBook>() val remoteBooks = mutableListOf<RemoteBook>()
AppWebDav.authorization?.let { //读取文件列表
//读取文件列表 val remoteWebDavFileList: List<WebDavFile> = WebDav(path, authorization).listFiles()
val remoteWebDavFileList: List<WebDavFile> = WebDav(path, it).listFiles() //转化远程文件信息到本地对象
//转化远程文件信息到本地对象 remoteWebDavFileList.forEach { webDavFile ->
remoteWebDavFileList.forEach { webDavFile -> if (webDavFile.isDir || bookFileRegex.matches(webDavFile.displayName)) {
if (webDavFile.isDir || bookFileRegex.matches(webDavFile.displayName)) { //扩展名符合阅读的格式则认为是书籍
//扩展名符合阅读的格式则认为是书籍 remoteBooks.add(RemoteBook(webDavFile))
remoteBooks.add(RemoteBook(webDavFile))
}
} }
} ?: throw NoStackTraceException("webDav没有配置") }
return remoteBooks return remoteBooks
} }
override suspend fun getRemoteBook(path: String): RemoteBook? { override suspend fun getRemoteBook(path: String): RemoteBook? {
AppWebDav.authorization?.let { if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用")
val webDavFile = WebDav(path, it).getWebDavFile() val webDavFile = WebDav(path, authorization).getWebDavFile()
?: return null ?: return null
return RemoteBook(webDavFile) return RemoteBook(webDavFile)
} ?: throw NoStackTraceException("webDav没有配置")
} }
override suspend fun downloadRemoteBook(remoteBook: RemoteBook): Uri { override suspend fun downloadRemoteBook(remoteBook: RemoteBook): Uri {
AppConfig.defaultBookTreeUri AppConfig.defaultBookTreeUri
?: throw NoStackTraceException("没有设置书籍保存位置!") ?: throw NoStackTraceException("没有设置书籍保存位置!")
return AppWebDav.authorization?.let { if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用")
val webdav = WebDav(remoteBook.path, it) val webdav = WebDav(remoteBook.path, authorization)
webdav.downloadInputStream().let { inputStream -> return webdav.downloadInputStream().let { inputStream ->
LocalBook.saveBookFile(inputStream, remoteBook.filename) LocalBook.saveBookFile(inputStream, remoteBook.filename)
} }
} ?: throw NoStackTraceException("webDav没有配置")
} }
override suspend fun upload(book: Book) { override suspend fun upload(book: Book) {
if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用") if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用")
val localBookUri = Uri.parse(book.bookUrl) val localBookUri = Uri.parse(book.bookUrl)
val putUrl = "$rootBookUrl${File.separator}${book.originName}" val putUrl = "$rootBookUrl${File.separator}${book.originName}"
AppWebDav.authorization?.let { if (localBookUri.isContentScheme()) {
if (localBookUri.isContentScheme()) { WebDav(putUrl, authorization).upload(
WebDav(putUrl, it).upload( byteArray = localBookUri.readBytes(appCtx),
byteArray = localBookUri.readBytes(appCtx), contentType = "application/octet-stream"
contentType = "application/octet-stream" )
) } else {
} else { WebDav(putUrl, authorization).upload(localBookUri.path!!)
WebDav(putUrl, it).upload(localBookUri.path!!) }
}
} ?: throw NoStackTraceException("webDav没有配置")
book.origin = BookType.webDavTag + putUrl book.origin = BookType.webDavTag + putUrl
book.save() book.save()
} }
override suspend fun delete(remoteBookUrl: String) { override suspend fun delete(remoteBookUrl: String) {
AppWebDav.authorization?.let { if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用")
WebDav(remoteBookUrl, it).delete() WebDav(remoteBookUrl, authorization).delete()
} ?: throw NoStackTraceException("webDav没有配置")
} }
} }

View File

@ -4,6 +4,8 @@ import android.app.Application
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppLog import io.legado.app.constant.AppLog
import io.legado.app.constant.BookType import io.legado.app.constant.BookType
import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.AppWebDav
import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.LocalBook
import io.legado.app.model.remote.RemoteBook import io.legado.app.model.remote.RemoteBook
import io.legado.app.model.remote.RemoteBookWebDav import io.legado.app.model.remote.RemoteBookWebDav
@ -70,17 +72,26 @@ class RemoteBookViewModel(application: Application) : BaseViewModel(application)
} }
}.flowOn(Dispatchers.IO) }.flowOn(Dispatchers.IO)
private var remoteBookWebDav: RemoteBookWebDav? = null
init { init {
execute { execute {
RemoteBookWebDav.initRemoteContext() val rootUrl = "${AppWebDav.rootWebDavUrl}books"
val authorization = AppWebDav.authorization
?: throw NoStackTraceException("webDav没有配置")
remoteBookWebDav = RemoteBookWebDav(rootUrl, authorization)
}.onError {
context.toastOnUi("初始化webDav出错:${it.localizedMessage}")
} }
} }
fun loadRemoteBookList(path: String?, loadCallback: (loading: Boolean) -> Unit) { fun loadRemoteBookList(path: String?, loadCallback: (loading: Boolean) -> Unit) {
execute { execute {
val bookWebDav = remoteBookWebDav
?: throw NoStackTraceException("没有配置webDav")
dataCallback?.clear() dataCallback?.clear()
val url = path ?: RemoteBookWebDav.rootBookUrl val url = path ?: bookWebDav.rootBookUrl
val bookList = RemoteBookWebDav.getRemoteBookList(url) val bookList = bookWebDav.getRemoteBookList(url)
dataCallback?.setItems(bookList) dataCallback?.setItems(bookList)
}.onError { }.onError {
AppLog.put("获取webDav书籍出错\n${it.localizedMessage}", it) AppLog.put("获取webDav书籍出错\n${it.localizedMessage}", it)
@ -95,7 +106,9 @@ class RemoteBookViewModel(application: Application) : BaseViewModel(application)
fun addToBookshelf(remoteBooks: HashSet<RemoteBook>, finally: () -> Unit) { fun addToBookshelf(remoteBooks: HashSet<RemoteBook>, finally: () -> Unit) {
execute { execute {
remoteBooks.forEach { remoteBook -> remoteBooks.forEach { remoteBook ->
val downloadBookPath = RemoteBookWebDav.downloadRemoteBook(remoteBook) val bookWebDav = remoteBookWebDav
?: throw NoStackTraceException("没有配置webDav")
val downloadBookPath = bookWebDav.downloadRemoteBook(remoteBook)
downloadBookPath.let { downloadBookPath.let {
val localBook = LocalBook.importFile(it) val localBook = LocalBook.importFile(it)
localBook.origin = BookType.webDavTag + remoteBook.path localBook.origin = BookType.webDavTag + remoteBook.path

View File

@ -19,6 +19,7 @@ import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.databinding.ActivityBookInfoBinding import io.legado.app.databinding.ActivityBookInfoBinding
import io.legado.app.databinding.DialogEditTextBinding import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.help.AppWebDav
import io.legado.app.help.book.isAudio import io.legado.app.help.book.isAudio
import io.legado.app.help.book.isLocal import io.legado.app.help.book.isLocal
import io.legado.app.help.book.isLocalTxt import io.legado.app.help.book.isLocalTxt
@ -28,7 +29,6 @@ import io.legado.app.lib.theme.backgroundColor
import io.legado.app.lib.theme.bottomBackground import io.legado.app.lib.theme.bottomBackground
import io.legado.app.lib.theme.getPrimaryTextColor import io.legado.app.lib.theme.getPrimaryTextColor
import io.legado.app.model.BookCover import io.legado.app.model.BookCover
import io.legado.app.model.remote.RemoteBookWebDav
import io.legado.app.ui.about.AppLogDialog import io.legado.app.ui.about.AppLogDialog
import io.legado.app.ui.association.ImportOnLineBookFileDialog import io.legado.app.ui.association.ImportOnLineBookFileDialog
import io.legado.app.ui.book.audio.AudioPlayActivity import io.legado.app.ui.book.audio.AudioPlayActivity
@ -210,7 +210,8 @@ class BookInfoActivity :
waitDialog.setText("上传中.....") waitDialog.setText("上传中.....")
waitDialog.show() waitDialog.show()
try { try {
RemoteBookWebDav.upload(it) AppWebDav.getDefaultRemoteBookWebDav()
.upload(it)
//更新书籍最后更新时间,使之比远程书籍的时间新 //更新书籍最后更新时间,使之比远程书籍的时间新
it.lastCheckTime = System.currentTimeMillis() it.lastCheckTime = System.currentTimeMillis()
viewModel.saveBook(it) viewModel.saveBook(it)
@ -246,7 +247,7 @@ class BookInfoActivity :
private fun showCover(book: Book) { private fun showCover(book: Book) {
binding.ivCover.load(book.getDisplayCover(), book.name, book.author, false, book.origin) binding.ivCover.load(book.getDisplayCover(), book.name, book.author, false, book.origin)
if(!AppConfig.isEInkMode) { if (!AppConfig.isEInkMode) {
BookCover.loadBlur(this, book.getDisplayCover()) BookCover.loadBlur(this, book.getDisplayCover())
.into(binding.bgBook) .into(binding.bgBook)
} }

View File

@ -15,13 +15,13 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.AppWebDav
import io.legado.app.help.book.* import io.legado.app.help.book.*
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.lib.webdav.ObjectNotFoundException import io.legado.app.lib.webdav.ObjectNotFoundException
import io.legado.app.model.BookCover import io.legado.app.model.BookCover
import io.legado.app.model.ReadBook import io.legado.app.model.ReadBook
import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.LocalBook
import io.legado.app.model.remote.RemoteBookWebDav
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.utils.isContentScheme import io.legado.app.utils.isContentScheme
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
@ -114,11 +114,12 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
if (book.isLocal) { if (book.isLocal) {
book.tocUrl = "" book.tocUrl = ""
book.getRemoteUrl()?.let { book.getRemoteUrl()?.let {
val remoteBook = RemoteBookWebDav.getRemoteBook(it) val bookWebDav = AppWebDav.getDefaultRemoteBookWebDav()
val remoteBook = bookWebDav.getRemoteBook(it)
if (remoteBook == null) { if (remoteBook == null) {
book.origin = BookType.localTag book.origin = BookType.localTag
} else if (remoteBook.lastModify > book.lastCheckTime) { } else if (remoteBook.lastModify > book.lastCheckTime) {
val uri = RemoteBookWebDav.downloadRemoteBook(remoteBook) val uri = bookWebDav.downloadRemoteBook(remoteBook)
book.bookUrl = if (uri.isContentScheme()) uri.toString() else uri.path!! book.bookUrl = if (uri.isContentScheme()) uri.toString() else uri.path!!
book.lastCheckTime = remoteBook.lastModify book.lastCheckTime = remoteBook.lastModify
} }