pull/1990/head
kunfei 2 years ago
parent 94c6be7202
commit 61aee76c53
  1. 34
      app/src/main/java/io/legado/app/lib/webdav/WebDav.kt
  2. 3
      app/src/main/java/io/legado/app/model/ReadBook.kt
  3. 8
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBook.kt
  4. 13
      app/src/main/java/io/legado/app/ui/book/remote/RemoteBookAdapter.kt
  5. 25
      app/src/main/java/io/legado/app/ui/book/remote/manager/RemoteBookWebDav.kt

@ -6,6 +6,7 @@ import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.http.newCallResponse import io.legado.app.help.http.newCallResponse
import io.legado.app.help.http.okHttpClient 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.printOnDebug import io.legado.app.utils.printOnDebug
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.asRequestBody
@ -61,11 +62,14 @@ open class WebDav(urlStr: String, val authorization: Authorization) {
/** /**
* 填充文件信息实例化WebDAVFile对象时并没有将远程文件的信息填充到实例中需要手动填充 * 获取当前url文件信息
* @return 远程文件是否存在
*/ */
suspend fun indexFileInfo(): Boolean { suspend fun getWebDavFile(): WebDavFile? {
return !propFindResponse(ArrayList()).isNullOrEmpty() return kotlin.runCatching {
propFindResponse(depth = 0)?.let {
return parseBody(it).firstOrNull()
}
}.getOrNull()
} }
/** /**
@ -76,9 +80,11 @@ open class WebDav(urlStr: String, val authorization: Authorization) {
@Throws(WebDavException::class) @Throws(WebDavException::class)
suspend fun listFiles(): List<WebDavFile> { suspend fun listFiles(): List<WebDavFile> {
propFindResponse()?.let { body -> propFindResponse()?.let { body ->
return parseDir(body) return parseBody(body).filter {
it.path != path
}
} }
return ArrayList() return emptyList()
} }
/** /**
@ -112,12 +118,12 @@ open class WebDav(urlStr: String, val authorization: Authorization) {
}.body?.text() }.body?.text()
} }
private fun parseDir(s: String): List<WebDavFile> { private fun parseBody(s: String): List<WebDavFile> {
val list = ArrayList<WebDavFile>() val list = ArrayList<WebDavFile>()
val document = Jsoup.parse(s) val document = Jsoup.parse(s)
val elements = document.getElementsByTag("d:response") val elements = document.getElementsByTag("d:response")
httpUrl?.let { urlStr -> httpUrl?.let { urlStr ->
val baseUrl = if (urlStr.endsWith("/")) urlStr else "$urlStr/" val baseUrl = NetworkUtils.getBaseUrl(urlStr)
for (element in elements) { for (element in elements) {
val href = element.getElementsByTag("d:href")[0].text() val href = element.getElementsByTag("d:href")[0].text()
if (!href.endsWith("/")) { if (!href.endsWith("/")) {
@ -137,11 +143,12 @@ open class WebDav(urlStr: String, val authorization: Authorization) {
val lastModify: Long = kotlin.runCatching { val lastModify: Long = kotlin.runCatching {
element.getElementsByTag("d:getlastmodified") element.getElementsByTag("d:getlastmodified")
.firstOrNull()?.text()?.let { .firstOrNull()?.text()?.let {
LocalDateTime.parse(it, dateTimeFormatter).toInstant(ZoneOffset.of("+8")).toEpochMilli() LocalDateTime.parse(it, dateTimeFormatter)
.toInstant(ZoneOffset.of("+8")).toEpochMilli()
} }
}.getOrNull() ?: 0 }.getOrNull() ?: 0
webDavFile = WebDavFile( webDavFile = WebDavFile(
baseUrl + fileName, "$baseUrl$href",
authorization, authorization,
displayName = fileName, displayName = fileName,
urlName = urlName, urlName = urlName,
@ -163,12 +170,7 @@ open class WebDav(urlStr: String, val authorization: Authorization) {
* 文件是否存在 * 文件是否存在
*/ */
suspend fun exists(): Boolean { suspend fun exists(): Boolean {
return kotlin.runCatching { return getWebDavFile() != null
val response = propFindResponse(depth = 0) ?: return false
val document = Jsoup.parse(response)
val elements = document.getElementsByTag("d:response")
return elements.isNotEmpty()
}.getOrDefault(false)
} }
/** /**

@ -21,6 +21,7 @@ import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import splitties.init.appCtx import splitties.init.appCtx
import kotlin.math.min
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
@ -437,7 +438,7 @@ object ReadBook : CoroutineScope by MainScope() {
delay(1000) delay(1000)
download(i) download(i)
} }
val minChapterIndex = durChapterIndex - 5 val minChapterIndex = durChapterIndex - min(5, AppConfig.preDownloadNum)
for (i in durChapterIndex.minus(2) downTo minChapterIndex) { for (i in durChapterIndex.minus(2) downTo minChapterIndex) {
delay(1000) delay(1000)
download(i) download(i)

@ -7,4 +7,10 @@ data class RemoteBook(
val contentType: String, val contentType: String,
val lastModify: Long, val lastModify: Long,
val isOnBookShelf: Boolean val isOnBookShelf: Boolean
) ) {
val isDir by lazy {
contentType == "folder"
}
}

@ -2,6 +2,7 @@ package io.legado.app.ui.book.remote
import android.content.Context import android.content.Context
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isGone
import cn.hutool.core.date.LocalDateTimeUtil import cn.hutool.core.date.LocalDateTimeUtil
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
@ -37,7 +38,11 @@ class RemoteBookAdapter (context: Context, val callBack: CallBack) :
tvName.text = item.filename.substringBeforeLast(".") tvName.text = item.filename.substringBeforeLast(".")
tvContentType.text = item.contentType tvContentType.text = item.contentType
tvSize.text = ConvertUtils.formatFileSize(item.size) tvSize.text = ConvertUtils.formatFileSize(item.size)
tvDate.text = LocalDateTimeUtil.format(LocalDateTimeUtil.of(item.lastModify), "yyyy-MM-dd") tvDate.text =
LocalDateTimeUtil.format(LocalDateTimeUtil.of(item.lastModify), "yyyy-MM-dd")
llInfo.isGone = item.isDir
tvContentType.isGone = item.isDir
btnDownload.isGone = item.isDir
} }
} }
@ -45,7 +50,11 @@ class RemoteBookAdapter (context: Context, val callBack: CallBack) :
binding.btnDownload.setOnClickListener { binding.btnDownload.setOnClickListener {
getItem(holder.layoutPosition)?.let { getItem(holder.layoutPosition)?.let {
callBack.addToBookshelf(it) if (it.isDir) {
} else {
callBack.addToBookshelf(it)
}
} }
} }

@ -49,20 +49,27 @@ object RemoteBookWebDav : RemoteBookManager() {
webDavFileName = URLDecoder.decode(webDavFileName, "utf-8") webDavFileName = URLDecoder.decode(webDavFileName, "utf-8")
webDavUrlName = URLDecoder.decode(webDavUrlName, "utf-8") webDavUrlName = URLDecoder.decode(webDavUrlName, "utf-8")
webDavFile.isDir if (webDavFile.isDir) {
//分割后缀
val fileExtension = webDavFileName.substringAfterLast(".")
//扩展名符合阅读的格式则认为是书籍
if (bookFileRegex.matches(webDavFileName)) {
val isOnBookShelf = LocalBook.isOnBookShelf(webDavFileName)
remoteBooks.add( remoteBooks.add(
RemoteBook( RemoteBook(
webDavFileName, webDavUrlName, webDavFile.size, webDavFileName, webDavUrlName, webDavFile.size,
fileExtension, webDavFile.lastModify, isOnBookShelf "folder", webDavFile.lastModify, false
) )
) )
} else {
//分割后缀
val fileExtension = webDavFileName.substringAfterLast(".")
//扩展名符合阅读的格式则认为是书籍
if (bookFileRegex.matches(webDavFileName)) {
val isOnBookShelf = LocalBook.isOnBookShelf(webDavFileName)
remoteBooks.add(
RemoteBook(
webDavFileName, webDavUrlName, webDavFile.size,
fileExtension, webDavFile.lastModify, isOnBookShelf
)
)
}
} }
} }
} ?: throw NoStackTraceException("webDav没有配置") } ?: throw NoStackTraceException("webDav没有配置")

Loading…
Cancel
Save