更新时检测webDav书籍是否比本地新,自动重新下载
This commit is contained in:
@@ -1,19 +0,0 @@
|
|||||||
package io.legado.app.data.entities
|
|
||||||
|
|
||||||
import com.android.tools.r8.Keep
|
|
||||||
|
|
||||||
@Keep
|
|
||||||
data class RemoteBook(
|
|
||||||
val filename: String,
|
|
||||||
val path: String,
|
|
||||||
val size: Long,
|
|
||||||
val contentType: String,
|
|
||||||
val lastModify: Long,
|
|
||||||
var isOnBookShelf: Boolean = false
|
|
||||||
) {
|
|
||||||
|
|
||||||
val isDir by lazy {
|
|
||||||
contentType == "folder"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -44,6 +44,13 @@ val Book.isOnLineTxt: Boolean
|
|||||||
return !isLocal && type and BookType.text > 0
|
return !isLocal && type and BookType.text > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Book.getRemoteUrl(): String? {
|
||||||
|
if (origin.startsWith(BookType.webDavTag)) {
|
||||||
|
return origin.substring(8)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
fun Book.upType() {
|
fun Book.upType() {
|
||||||
if (type < 8) {
|
if (type < 8) {
|
||||||
type = when (type) {
|
type = when (type) {
|
||||||
|
|||||||
@@ -92,12 +92,11 @@ open class WebDav(val path: String, val authorization: Authorization) {
|
|||||||
/**
|
/**
|
||||||
* 获取当前url文件信息
|
* 获取当前url文件信息
|
||||||
*/
|
*/
|
||||||
|
@Throws(WebDavException::class)
|
||||||
suspend fun getWebDavFile(): WebDavFile? {
|
suspend fun getWebDavFile(): WebDavFile? {
|
||||||
return kotlin.runCatching {
|
return propFindResponse(depth = 0)?.let {
|
||||||
propFindResponse(depth = 0)?.let {
|
parseBody(it).firstOrNull()
|
||||||
return parseBody(it).firstOrNull()
|
|
||||||
}
|
}
|
||||||
}.getOrNull()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package io.legado.app.model.remote
|
||||||
|
|
||||||
|
import com.android.tools.r8.Keep
|
||||||
|
import io.legado.app.lib.webdav.WebDavFile
|
||||||
|
import io.legado.app.model.localBook.LocalBook
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class RemoteBook(
|
||||||
|
val filename: String,
|
||||||
|
val path: String,
|
||||||
|
val size: Long,
|
||||||
|
val lastModify: Long,
|
||||||
|
var contentType: String = "folder",
|
||||||
|
var isOnBookShelf: Boolean = false
|
||||||
|
) {
|
||||||
|
|
||||||
|
val isDir get() = contentType == "folder"
|
||||||
|
|
||||||
|
constructor(webDavFile: WebDavFile) : this(
|
||||||
|
webDavFile.displayName,
|
||||||
|
webDavFile.path,
|
||||||
|
webDavFile.size,
|
||||||
|
webDavFile.lastModify
|
||||||
|
) {
|
||||||
|
if (!webDavFile.isDir) {
|
||||||
|
contentType = webDavFile.displayName.substringAfterLast(".")
|
||||||
|
isOnBookShelf = LocalBook.isOnBookShelf(webDavFile.displayName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package io.legado.app.model.remote
|
|||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import io.legado.app.data.entities.Book
|
import io.legado.app.data.entities.Book
|
||||||
import io.legado.app.data.entities.RemoteBook
|
|
||||||
|
|
||||||
abstract class RemoteBookManager {
|
abstract class RemoteBookManager {
|
||||||
protected val remoteBookFolder: String = "books"
|
protected val remoteBookFolder: String = "books"
|
||||||
@@ -15,6 +14,18 @@ abstract class RemoteBookManager {
|
|||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
abstract suspend fun getRemoteBookList(path: String): MutableList<RemoteBook>
|
abstract suspend fun getRemoteBookList(path: String): MutableList<RemoteBook>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据书籍地址获取书籍信息
|
||||||
|
*/
|
||||||
|
@Throws(Exception::class)
|
||||||
|
abstract suspend fun getRemoteBook(path: String): RemoteBook
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Uri:下载到本地的路径
|
||||||
|
*/
|
||||||
|
@Throws(Exception::class)
|
||||||
|
abstract suspend fun downloadRemoteBook(remoteBook: RemoteBook): Uri
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传书籍
|
* 上传书籍
|
||||||
*/
|
*/
|
||||||
@@ -27,9 +38,4 @@ abstract class RemoteBookManager {
|
|||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
abstract suspend fun delete(remoteBookUrl: String)
|
abstract suspend fun delete(remoteBookUrl: String)
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Uri:下载到本地的路径
|
|
||||||
*/
|
|
||||||
@Throws(Exception::class)
|
|
||||||
abstract suspend fun getRemoteBook(remoteBook: RemoteBook): Uri
|
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,6 @@ import android.net.Uri
|
|||||||
import io.legado.app.constant.AppPattern.bookFileRegex
|
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.data.entities.RemoteBook
|
|
||||||
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
|
||||||
@@ -40,34 +39,24 @@ object RemoteBookWebDav : RemoteBookManager() {
|
|||||||
val remoteWebDavFileList: List<WebDavFile> = WebDav(path, it).listFiles()
|
val remoteWebDavFileList: List<WebDavFile> = WebDav(path, it).listFiles()
|
||||||
//转化远程文件信息到本地对象
|
//转化远程文件信息到本地对象
|
||||||
remoteWebDavFileList.forEach { webDavFile ->
|
remoteWebDavFileList.forEach { webDavFile ->
|
||||||
if (webDavFile.isDir) {
|
if (webDavFile.isDir || bookFileRegex.matches(webDavFile.displayName)) {
|
||||||
remoteBooks.add(
|
|
||||||
RemoteBook(
|
|
||||||
webDavFile.displayName, webDavFile.path, webDavFile.size,
|
|
||||||
"folder", webDavFile.lastModify
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
//分割后缀
|
|
||||||
val fileExtension = webDavFile.displayName.substringAfterLast(".")
|
|
||||||
|
|
||||||
//扩展名符合阅读的格式则认为是书籍
|
//扩展名符合阅读的格式则认为是书籍
|
||||||
if (bookFileRegex.matches(webDavFile.displayName)) {
|
remoteBooks.add(RemoteBook(webDavFile))
|
||||||
val isOnBookShelf = LocalBook.isOnBookShelf(webDavFile.displayName)
|
|
||||||
remoteBooks.add(
|
|
||||||
RemoteBook(
|
|
||||||
webDavFile.displayName, webDavFile.path, webDavFile.size,
|
|
||||||
fileExtension, webDavFile.lastModify, isOnBookShelf
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ?: throw NoStackTraceException("webDav没有配置")
|
} ?: throw NoStackTraceException("webDav没有配置")
|
||||||
return remoteBooks
|
return remoteBooks
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getRemoteBook(remoteBook: RemoteBook): Uri {
|
override suspend fun getRemoteBook(path: String): RemoteBook {
|
||||||
|
AppWebDav.authorization?.let {
|
||||||
|
val webDavFile = WebDav(path, it).getWebDavFile()
|
||||||
|
?: throw NoStackTraceException("远程书籍不存在")
|
||||||
|
return RemoteBook(webDavFile)
|
||||||
|
} ?: throw NoStackTraceException("webDav没有配置")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun downloadRemoteBook(remoteBook: RemoteBook): Uri {
|
||||||
return AppWebDav.authorization?.let {
|
return AppWebDav.authorization?.let {
|
||||||
val webdav = WebDav(remoteBook.path, it)
|
val webdav = WebDav(remoteBook.path, it)
|
||||||
webdav.downloadInputStream().let { inputStream ->
|
webdav.downloadInputStream().let { inputStream ->
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class BookInfoActivity :
|
|||||||
private val readBookResult = registerForActivityResult(
|
private val readBookResult = registerForActivityResult(
|
||||||
ActivityResultContracts.StartActivityForResult()
|
ActivityResultContracts.StartActivityForResult()
|
||||||
) {
|
) {
|
||||||
viewModel.refreshData(intent)
|
viewModel.upBook(intent)
|
||||||
if (it.resultCode == RESULT_OK) {
|
if (it.resultCode == RESULT_OK) {
|
||||||
viewModel.inBookshelf = true
|
viewModel.inBookshelf = true
|
||||||
upTvBookshelf()
|
upTvBookshelf()
|
||||||
@@ -162,10 +162,7 @@ class BookInfoActivity :
|
|||||||
R.id.menu_refresh -> {
|
R.id.menu_refresh -> {
|
||||||
upLoading(true)
|
upLoading(true)
|
||||||
viewModel.bookData.value?.let {
|
viewModel.bookData.value?.let {
|
||||||
if (it.isLocal) {
|
viewModel.refreshBook(it)
|
||||||
it.tocUrl = ""
|
|
||||||
}
|
|
||||||
viewModel.loadBookInfo(it, false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.menu_login -> viewModel.bookSource?.let {
|
R.id.menu_login -> viewModel.bookSource?.let {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshData(intent: Intent) {
|
fun upBook(intent: Intent) {
|
||||||
execute {
|
execute {
|
||||||
val name = intent.getStringExtra("name") ?: ""
|
val name = intent.getStringExtra("name") ?: ""
|
||||||
val author = intent.getStringExtra("author") ?: ""
|
val author = intent.getStringExtra("author") ?: ""
|
||||||
@@ -107,6 +107,13 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun refreshBook(book: Book) {
|
||||||
|
if (book.isLocal) {
|
||||||
|
book.tocUrl = ""
|
||||||
|
}
|
||||||
|
loadBookInfo(book, false)
|
||||||
|
}
|
||||||
|
|
||||||
fun loadBookInfo(
|
fun loadBookInfo(
|
||||||
book: Book,
|
book: Book,
|
||||||
canReName: Boolean = true,
|
canReName: Boolean = true,
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import androidx.core.view.isGone
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.base.VMBaseActivity
|
import io.legado.app.base.VMBaseActivity
|
||||||
import io.legado.app.data.entities.RemoteBook
|
|
||||||
import io.legado.app.databinding.ActivityImportBookBinding
|
import io.legado.app.databinding.ActivityImportBookBinding
|
||||||
import io.legado.app.lib.theme.backgroundColor
|
import io.legado.app.lib.theme.backgroundColor
|
||||||
|
import io.legado.app.model.remote.RemoteBook
|
||||||
import io.legado.app.ui.about.AppLogDialog
|
import io.legado.app.ui.about.AppLogDialog
|
||||||
import io.legado.app.ui.widget.SelectActionBar
|
import io.legado.app.ui.widget.SelectActionBar
|
||||||
import io.legado.app.ui.widget.dialog.WaitDialog
|
import io.legado.app.ui.widget.dialog.WaitDialog
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import io.legado.app.R
|
|||||||
import io.legado.app.base.adapter.ItemViewHolder
|
import io.legado.app.base.adapter.ItemViewHolder
|
||||||
import io.legado.app.base.adapter.RecyclerAdapter
|
import io.legado.app.base.adapter.RecyclerAdapter
|
||||||
import io.legado.app.constant.AppConst
|
import io.legado.app.constant.AppConst
|
||||||
import io.legado.app.data.entities.RemoteBook
|
|
||||||
import io.legado.app.databinding.ItemImportBookBinding
|
import io.legado.app.databinding.ItemImportBookBinding
|
||||||
|
import io.legado.app.model.remote.RemoteBook
|
||||||
import io.legado.app.utils.ConvertUtils
|
import io.legado.app.utils.ConvertUtils
|
||||||
import io.legado.app.utils.gone
|
import io.legado.app.utils.gone
|
||||||
import io.legado.app.utils.invisible
|
import io.legado.app.utils.invisible
|
||||||
|
|||||||
@@ -4,8 +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.data.entities.RemoteBook
|
|
||||||
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.RemoteBookWebDav
|
import io.legado.app.model.remote.RemoteBookWebDav
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -95,7 +95,7 @@ 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.getRemoteBook(remoteBook)
|
val downloadBookPath = RemoteBookWebDav.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
|
||||||
|
|||||||
Reference in New Issue
Block a user