Merge remote-tracking branch 'origin/master'
This commit is contained in:
+1
-1
@@ -190,7 +190,7 @@ dependencies {
|
|||||||
|
|
||||||
//media
|
//media
|
||||||
implementation("androidx.media:media:1.6.0")
|
implementation("androidx.media:media:1.6.0")
|
||||||
def exoplayer_version = '2.17.1'
|
def exoplayer_version = '2.18.0'
|
||||||
implementation("com.google.android.exoplayer:exoplayer-core:$exoplayer_version")
|
implementation("com.google.android.exoplayer:exoplayer-core:$exoplayer_version")
|
||||||
implementation("com.google.android.exoplayer:extension-okhttp:$exoplayer_version")
|
implementation("com.google.android.exoplayer:extension-okhttp:$exoplayer_version")
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
{"x86_64":"136f62aca55e9479aa3994213be6ca1d","x86":"2a7c8d7107832839d2459334c1d8f966","armeabi-v7a":"d890a3023e76d3e942485b80c74f8e9b","arm64-v8a":"d4bb1dce5666d38fda7c46a53f2c5aaa","version":"102.0.5005.125"}
|
{"x86_64":"cbb7148b4ac5771e6ebd9392bfb65010","armeabi-v7a":"f4006d0fef882d5c09f75e59e5256933","arm64-v8a":"ee4a9a6c4b5faf0588a050f3fbd0f0b5","x86":"a323610b6994b79bbf17223da1192945","version":"103.0.5060.53"}
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
**2022/06/16**
|
**2022/06/16**
|
||||||
|
|
||||||
|
* 更新cronet: 103.0.5060.53
|
||||||
* 导出使用单线程,导出占用大量内存,并行容易OOM
|
* 导出使用单线程,导出占用大量内存,并行容易OOM
|
||||||
* 导出到WebDav文件夹改为books,方便导入
|
* 导出到WebDav文件夹改为books,方便导入
|
||||||
* WebDav导入基本能用了
|
* WebDav导入基本能用了
|
||||||
|
|||||||
@@ -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,24 +62,28 @@ 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 列出当前路径下的文件
|
* 列出当前路径下的文件
|
||||||
*
|
|
||||||
* @return 文件列表
|
* @return 文件列表
|
||||||
*/
|
*/
|
||||||
@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 +117,15 @@ open class WebDav(urlStr: String, val authorization: Authorization) {
|
|||||||
}.body?.text()
|
}.body?.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseDir(s: String): List<WebDavFile> {
|
/**
|
||||||
|
* 解析webDav返回的xml
|
||||||
|
*/
|
||||||
|
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 +145,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 +172,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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -297,6 +301,9 @@ open class WebDav(urlStr: String, val authorization: Authorization) {
|
|||||||
}.isSuccess
|
}.isSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测返回结果是否正确
|
||||||
|
*/
|
||||||
private fun checkResult(response: Response) {
|
private fun checkResult(response: Response) {
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
throw WebDavException("${url}\n${response.code}:${response.message}")
|
throw WebDavException("${url}\n${response.code}:${response.message}")
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -2,9 +2,15 @@ package io.legado.app.ui.book.remote
|
|||||||
|
|
||||||
data class RemoteBook(
|
data class RemoteBook(
|
||||||
val filename: String,
|
val filename: String,
|
||||||
val urlName: String,
|
val path: String,
|
||||||
val size: Long,
|
val size: Long,
|
||||||
val contentType: String,
|
val contentType: String,
|
||||||
val lastModify: Long,
|
val lastModify: Long,
|
||||||
val isOnBookShelf: Boolean
|
val isOnBookShelf: Boolean
|
||||||
)
|
) {
|
||||||
|
|
||||||
|
val isDir by lazy {
|
||||||
|
contentType == "folder"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ import io.legado.app.base.VMBaseActivity
|
|||||||
|
|
||||||
|
|
||||||
import io.legado.app.databinding.ActivityRemoteBookBinding
|
import io.legado.app.databinding.ActivityRemoteBookBinding
|
||||||
|
import io.legado.app.ui.book.remote.manager.RemoteBookWebDav
|
||||||
import io.legado.app.ui.widget.dialog.WaitDialog
|
import io.legado.app.ui.widget.dialog.WaitDialog
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding, RemoteBookV
|
|||||||
adapter.setItems(remoteBooks)
|
adapter.setItems(remoteBooks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewModel.loadRemoteBookList()
|
viewModel.loadRemoteBookList(RemoteBookWebDav.rootBookUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
@@ -61,12 +62,38 @@ class RemoteBookActivity : VMBaseActivity<ActivityRemoteBookBinding, RemoteBookV
|
|||||||
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.menu_refresh -> {
|
R.id.menu_refresh -> {
|
||||||
viewModel.loadRemoteBookList()
|
viewModel.loadRemoteBookList(
|
||||||
|
viewModel.dirList.lastOrNull()?.path ?: RemoteBookWebDav.rootBookUrl
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onCompatOptionsItemSelected(item)
|
return super.onCompatOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun finish() {
|
||||||
|
if (viewModel.dirList.isEmpty()) {
|
||||||
|
super.finish()
|
||||||
|
} else {
|
||||||
|
viewModel.dirList.removeLastOrNull()
|
||||||
|
val remoteBook = viewModel.dirList.lastOrNull()
|
||||||
|
viewModel.dataCallback?.clear()
|
||||||
|
if (remoteBook != null) {
|
||||||
|
binding.titleBar.title = remoteBook.filename
|
||||||
|
viewModel.loadRemoteBookList(remoteBook.path)
|
||||||
|
} else {
|
||||||
|
binding.titleBar.setTitle(R.string.remote_book)
|
||||||
|
viewModel.loadRemoteBookList(RemoteBookWebDav.rootBookUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun openDir(remoteBook: RemoteBook) {
|
||||||
|
viewModel.dirList.add(remoteBook)
|
||||||
|
binding.titleBar.title = remoteBook.filename
|
||||||
|
viewModel.dataCallback?.clear()
|
||||||
|
viewModel.loadRemoteBookList(remoteBook.path)
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
override fun addToBookshelf(remoteBook: RemoteBook) {
|
override fun addToBookshelf(remoteBook: RemoteBook) {
|
||||||
waitDialog.show()
|
waitDialog.show()
|
||||||
|
|||||||
@@ -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,21 +38,31 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerListener(holder: ItemViewHolder, binding: ItemRemoteBookBinding) {
|
override fun registerListener(holder: ItemViewHolder, binding: ItemRemoteBookBinding) {
|
||||||
|
binding.root.setOnClickListener {
|
||||||
|
getItem(holder.layoutPosition)?.let {
|
||||||
|
if (it.isDir) {
|
||||||
|
callBack.openDir(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
binding.btnDownload.setOnClickListener {
|
binding.btnDownload.setOnClickListener {
|
||||||
getItem(holder.layoutPosition)?.let {
|
getItem(holder.layoutPosition)?.let {
|
||||||
callBack.addToBookshelf(it)
|
callBack.addToBookshelf(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CallBack {
|
interface CallBack {
|
||||||
|
fun openDir(remoteBook: RemoteBook)
|
||||||
fun addToBookshelf(remoteBook: RemoteBook)
|
fun addToBookshelf(remoteBook: RemoteBook)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ import android.net.Uri
|
|||||||
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(): MutableList<RemoteBook>
|
abstract suspend fun getRemoteBookList(path: String): MutableList<RemoteBook>
|
||||||
abstract suspend fun upload(localBookUri: Uri): Boolean
|
abstract suspend fun upload(localBookUri: Uri): Boolean
|
||||||
abstract suspend fun delete(remoteBookUrl: String): Boolean
|
abstract suspend fun delete(remoteBookUrl: String): Boolean
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ import kotlinx.coroutines.flow.flowOn
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class RemoteBookViewModel(application: Application): BaseViewModel(application){
|
class RemoteBookViewModel(application: Application): BaseViewModel(application){
|
||||||
private var dataCallback : DataCallback? = null
|
|
||||||
|
val dirList = arrayListOf<RemoteBook>()
|
||||||
|
|
||||||
|
var dataCallback: DataCallback? = null
|
||||||
|
|
||||||
val dataFlow = callbackFlow<List<RemoteBook>> {
|
val dataFlow = callbackFlow<List<RemoteBook>> {
|
||||||
|
|
||||||
@@ -49,10 +52,10 @@ class RemoteBookViewModel(application: Application): BaseViewModel(application){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadRemoteBookList() {
|
fun loadRemoteBookList(path: String) {
|
||||||
execute {
|
execute {
|
||||||
dataCallback?.clear()
|
dataCallback?.clear()
|
||||||
val bookList = RemoteBookWebDav.getRemoteBookList()
|
val bookList = RemoteBookWebDav.getRemoteBookList(path)
|
||||||
dataCallback?.setItems(bookList)
|
dataCallback?.setItems(bookList)
|
||||||
}.onError {
|
}.onError {
|
||||||
context.toastOnUi("获取webDav书籍出错\n${it.localizedMessage}")
|
context.toastOnUi("获取webDav书籍出错\n${it.localizedMessage}")
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import java.io.File
|
|||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
|
||||||
object RemoteBookWebDav : RemoteBookManager() {
|
object RemoteBookWebDav : RemoteBookManager() {
|
||||||
private val remoteBookUrl get() = "${AppWebDav.rootWebDavUrl}${remoteBookFolder}"
|
val rootBookUrl get() = "${AppWebDav.rootWebDavUrl}${remoteBookFolder}"
|
||||||
|
|
||||||
init {
|
init {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
@@ -29,7 +29,7 @@ object RemoteBookWebDav : RemoteBookManager() {
|
|||||||
|
|
||||||
override suspend fun initRemoteContext() {
|
override suspend fun initRemoteContext() {
|
||||||
AppWebDav.authorization?.let {
|
AppWebDav.authorization?.let {
|
||||||
WebDav(remoteBookUrl, it).makeAsDir()
|
WebDav(rootBookUrl, it).makeAsDir()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,20 +37,24 @@ object RemoteBookWebDav : RemoteBookManager() {
|
|||||||
* 获取远程书籍列表
|
* 获取远程书籍列表
|
||||||
*/
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
override suspend fun getRemoteBookList(): MutableList<RemoteBook> {
|
override suspend fun getRemoteBookList(path: String): MutableList<RemoteBook> {
|
||||||
val remoteBooks = mutableListOf<RemoteBook>()
|
val remoteBooks = mutableListOf<RemoteBook>()
|
||||||
AppWebDav.authorization?.let {
|
AppWebDav.authorization?.let {
|
||||||
//读取文件列表
|
//读取文件列表
|
||||||
val remoteWebDavFileList: List<WebDavFile> = WebDav(remoteBookUrl, it).listFiles()
|
val remoteWebDavFileList: List<WebDavFile> = WebDav(path, it).listFiles()
|
||||||
//转化远程文件信息到本地对象
|
//转化远程文件信息到本地对象
|
||||||
remoteWebDavFileList.forEach { webDavFile ->
|
remoteWebDavFileList.forEach { webDavFile ->
|
||||||
var webDavFileName = webDavFile.displayName
|
var webDavFileName = webDavFile.displayName
|
||||||
var webDavUrlName = "${remoteBookUrl}${File.separator}${webDavFile.displayName}"
|
|
||||||
webDavFileName = URLDecoder.decode(webDavFileName, "utf-8")
|
webDavFileName = URLDecoder.decode(webDavFileName, "utf-8")
|
||||||
webDavUrlName = URLDecoder.decode(webDavUrlName, "utf-8")
|
|
||||||
|
|
||||||
webDavFile.isDir
|
|
||||||
|
|
||||||
|
if (webDavFile.isDir) {
|
||||||
|
remoteBooks.add(
|
||||||
|
RemoteBook(
|
||||||
|
webDavFileName, webDavFile.path, webDavFile.size,
|
||||||
|
"folder", webDavFile.lastModify, false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
//分割后缀
|
//分割后缀
|
||||||
val fileExtension = webDavFileName.substringAfterLast(".")
|
val fileExtension = webDavFileName.substringAfterLast(".")
|
||||||
|
|
||||||
@@ -59,12 +63,13 @@ object RemoteBookWebDav : RemoteBookManager() {
|
|||||||
val isOnBookShelf = LocalBook.isOnBookShelf(webDavFileName)
|
val isOnBookShelf = LocalBook.isOnBookShelf(webDavFileName)
|
||||||
remoteBooks.add(
|
remoteBooks.add(
|
||||||
RemoteBook(
|
RemoteBook(
|
||||||
webDavFileName, webDavUrlName, webDavFile.size,
|
webDavFileName, webDavFile.path, webDavFile.size,
|
||||||
fileExtension, webDavFile.lastModify, isOnBookShelf
|
fileExtension, webDavFile.lastModify, isOnBookShelf
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} ?: throw NoStackTraceException("webDav没有配置")
|
} ?: throw NoStackTraceException("webDav没有配置")
|
||||||
return remoteBooks
|
return remoteBooks
|
||||||
}
|
}
|
||||||
@@ -74,7 +79,7 @@ object RemoteBookWebDav : RemoteBookManager() {
|
|||||||
*/
|
*/
|
||||||
override suspend fun getRemoteBook(remoteBook: RemoteBook): Uri? {
|
override suspend fun getRemoteBook(remoteBook: RemoteBook): Uri? {
|
||||||
return AppWebDav.authorization?.let {
|
return AppWebDav.authorization?.let {
|
||||||
val webdav = WebDav(remoteBook.urlName, it)
|
val webdav = WebDav(remoteBook.path, it)
|
||||||
webdav.download().let { bytes ->
|
webdav.download().let { bytes ->
|
||||||
LocalBook.saveBookFile(bytes, remoteBook.filename)
|
LocalBook.saveBookFile(bytes, remoteBook.filename)
|
||||||
}
|
}
|
||||||
@@ -88,7 +93,7 @@ object RemoteBookWebDav : RemoteBookManager() {
|
|||||||
if (!NetworkUtils.isAvailable()) return false
|
if (!NetworkUtils.isAvailable()) return false
|
||||||
|
|
||||||
val localBookName = localBookUri.path?.substringAfterLast(File.separator)
|
val localBookName = localBookUri.path?.substringAfterLast(File.separator)
|
||||||
val putUrl = "${remoteBookUrl}${File.separator}${localBookName}"
|
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(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:title="远程书籍" />
|
app:title="@string/remote_book" />
|
||||||
|
|
||||||
<io.legado.app.ui.widget.anima.RefreshProgressBar
|
<io.legado.app.ui.widget.anima.RefreshProgressBar
|
||||||
android:id="@+id/refresh_progress_bar"
|
android:id="@+id/refresh_progress_bar"
|
||||||
|
|||||||
@@ -996,4 +996,5 @@
|
|||||||
<string name="error_decode_bitmap">Fail to decode bitmap</string>
|
<string name="error_decode_bitmap">Fail to decode bitmap</string>
|
||||||
<string name="error_image_url_empty">Image url is empty, check replacement rules</string>
|
<string name="error_image_url_empty">Image url is empty, check replacement rules</string>
|
||||||
<string name="variable_comment">变量说明(variableComment)</string>
|
<string name="variable_comment">变量说明(variableComment)</string>
|
||||||
|
<string name="remote_book">远程书籍</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -999,4 +999,5 @@
|
|||||||
<string name="error_decode_bitmap">Fail to decode bitmap</string>
|
<string name="error_decode_bitmap">Fail to decode bitmap</string>
|
||||||
<string name="error_image_url_empty">Image url is empty, check replacement rules</string>
|
<string name="error_image_url_empty">Image url is empty, check replacement rules</string>
|
||||||
<string name="variable_comment">变量说明(variableComment)</string>
|
<string name="variable_comment">变量说明(variableComment)</string>
|
||||||
|
<string name="remote_book">远程书籍</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -999,4 +999,5 @@
|
|||||||
<string name="error_decode_bitmap">Fail to decode bitmap</string>
|
<string name="error_decode_bitmap">Fail to decode bitmap</string>
|
||||||
<string name="error_image_url_empty">Image url is empty, check replacement rules</string>
|
<string name="error_image_url_empty">Image url is empty, check replacement rules</string>
|
||||||
<string name="variable_comment">变量说明(variableComment)</string>
|
<string name="variable_comment">变量说明(variableComment)</string>
|
||||||
|
<string name="remote_book">远程书籍</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -996,4 +996,5 @@
|
|||||||
<string name="error_decode_bitmap">图片解码失败</string>
|
<string name="error_decode_bitmap">图片解码失败</string>
|
||||||
<string name="error_image_url_empty">图片链接为空,检查替换净化规则</string>
|
<string name="error_image_url_empty">图片链接为空,检查替换净化规则</string>
|
||||||
<string name="variable_comment">变量说明(variableComment)</string>
|
<string name="variable_comment">变量说明(variableComment)</string>
|
||||||
|
<string name="remote_book">远程书籍</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -998,4 +998,5 @@
|
|||||||
<string name="error_decode_bitmap">图片解码失败</string>
|
<string name="error_decode_bitmap">图片解码失败</string>
|
||||||
<string name="error_image_url_empty">图片链接为空,检查替换净化规则</string>
|
<string name="error_image_url_empty">图片链接为空,检查替换净化规则</string>
|
||||||
<string name="variable_comment">变量说明(variableComment)</string>
|
<string name="variable_comment">变量说明(variableComment)</string>
|
||||||
|
<string name="remote_book">远程书籍</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -998,4 +998,5 @@
|
|||||||
<string name="error_decode_bitmap">图片解码失败</string>
|
<string name="error_decode_bitmap">图片解码失败</string>
|
||||||
<string name="error_image_url_empty">图片链接为空,检查替换净化规则</string>
|
<string name="error_image_url_empty">图片链接为空,检查替换净化规则</string>
|
||||||
<string name="variable_comment">变量说明(variableComment)</string>
|
<string name="variable_comment">变量说明(variableComment)</string>
|
||||||
|
<string name="remote_book">远程书籍</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -999,4 +999,5 @@
|
|||||||
<string name="error_decode_bitmap">Fail to decode bitmap</string>
|
<string name="error_decode_bitmap">Fail to decode bitmap</string>
|
||||||
<string name="error_image_url_empty">Image url is empty, check replacement rules</string>
|
<string name="error_image_url_empty">Image url is empty, check replacement rules</string>
|
||||||
<string name="variable_comment">变量说明(variableComment)</string>
|
<string name="variable_comment">变量说明(variableComment)</string>
|
||||||
|
<string name="remote_book">远程书籍</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
+1
-1
@@ -26,4 +26,4 @@ android.experimental.enableNewResourceShrinker.preciseShrinking=true
|
|||||||
# and none from the library's dependencies, thereby reducing the size of the R class for that library.
|
# and none from the library's dependencies, thereby reducing the size of the R class for that library.
|
||||||
android.nonTransitiveRClass=true
|
android.nonTransitiveRClass=true
|
||||||
#https://chromiumdash.appspot.com/releases?platform=Android
|
#https://chromiumdash.appspot.com/releases?platform=Android
|
||||||
CronetVersion=102.0.5005.125
|
CronetVersion=103.0.5060.53
|
||||||
|
|||||||
Reference in New Issue
Block a user