pull/737/head
gedoor 5 years ago
parent 8da3227542
commit f3917d9d5e
  1. 19
      app/src/main/java/io/legado/app/data/dao/BookDao.kt
  2. 6
      app/src/main/java/io/legado/app/data/entities/BookProgress.kt
  3. 58
      app/src/main/java/io/legado/app/help/storage/SyncBookProgress.kt
  4. 27
      app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt
  5. 22
      app/src/main/java/io/legado/app/lib/webdav/WebDav.kt
  6. 5
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  7. 7
      app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
  8. 2
      app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt

@ -4,7 +4,6 @@ import androidx.lifecycle.LiveData
import androidx.room.* import androidx.room.*
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.BookProgress
@Dao @Dao
interface BookDao { interface BookDao {
@ -81,22 +80,4 @@ interface BookDao {
@Query("update books set `group` = :newGroupId where `group` = :oldGroupId") @Query("update books set `group` = :newGroupId where `group` = :oldGroupId")
fun upGroup(oldGroupId: Long, newGroupId: Long) fun upGroup(oldGroupId: Long, newGroupId: Long)
@get:Query("select bookUrl, tocUrl, origin, originName, durChapterIndex, durChapterPos, durChapterTime, durChapterTitle from books")
val allBookProgress: List<BookProgress>
@Query(
"""
update books set
durChapterIndex = :durChapterIndex, durChapterPos = :durChapterPos,
durChapterTime = :durChapterTime, durChapterTitle = :durChapterTitle
where bookUrl = :bookUrl and durChapterTime < :durChapterTime
"""
)
fun upBookProgress(
bookUrl: String,
durChapterIndex: Int,
durChapterPos: Int,
durChapterTime: Long,
durChapterTitle: String?
)
} }

@ -1,10 +1,8 @@
package io.legado.app.data.entities package io.legado.app.data.entities
data class BookProgress( data class BookProgress(
val bookUrl: String, val name: String,
val tocUrl: String = "", val author: String,
var origin: String = "",
var originName: String = "",
val durChapterIndex: Int, val durChapterIndex: Int,
val durChapterPos: Int, val durChapterPos: Int,
val durChapterTime: Long, val durChapterTime: Long,

@ -1,50 +1,50 @@
package io.legado.app.help.storage package io.legado.app.help.storage
import io.legado.app.App import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookProgress import io.legado.app.data.entities.BookProgress
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.lib.webdav.WebDav import io.legado.app.lib.webdav.WebDav
import io.legado.app.utils.FileUtils
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import io.legado.app.utils.fromJsonArray import io.legado.app.utils.fromJsonObject
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
object SyncBookProgress { object SyncBookProgress {
const val fileName = "bookProgress.json"
private val file = FileUtils.createFileIfNotExist(App.INSTANCE.cacheDir, fileName)
private val webDavUrl = "${WebDavHelp.rootWebDavUrl}$fileName"
fun uploadBookProgress() { private val webDavUrl = "${WebDavHelp.rootWebDavUrl}bookProgress/"
fun uploadBookProgress(book: Book) {
Coroutine.async { Coroutine.async {
val value = App.db.bookDao.allBookProgress val bookProgress = BookProgress(
if (value.isNotEmpty()) { name = book.name,
val json = GSON.toJson(value) author = book.author,
file.writeText(json) durChapterIndex = book.durChapterIndex,
if (WebDavHelp.initWebDav()) { durChapterPos = book.durChapterPos,
WebDav(webDavUrl).upload(file.absolutePath) durChapterTime = book.durChapterTime,
} durChapterTitle = book.durChapterTitle
)
val json = GSON.toJson(bookProgress)
val url = getUrl(book)
if (WebDavHelp.initWebDav()) {
WebDav(webDavUrl).makeAsDir()
WebDav(url).upload(json.toByteArray())
} }
} }
} }
fun downloadBookProgress() { fun getBookProgress(book: Book): BookProgress? {
Coroutine.async { if (WebDavHelp.initWebDav()) {
if (WebDavHelp.initWebDav()) { val url = getUrl(book)
WebDav(webDavUrl).downloadTo(file.absolutePath, true) WebDav(url).download()?.let { byteArray ->
if (file.exists()) { val json = String(byteArray)
val json = file.readText() GSON.fromJsonObject<BookProgress>(json)?.let {
GSON.fromJsonArray<BookProgress>(json)?.forEach { return it
App.db.bookDao.upBookProgress(
bookUrl = it.bookUrl,
durChapterIndex = it.durChapterIndex,
durChapterPos = it.durChapterPos,
durChapterTime = it.durChapterTime,
durChapterTitle = it.durChapterTitle
)
}
} }
} }
} }
return null
} }
private fun getUrl(book: Book): String {
return webDavUrl + book.name + "_" + book.author + ".json"
}
} }

@ -18,7 +18,6 @@ import org.jetbrains.anko.toast
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.math.min
object WebDavHelp { object WebDavHelp {
private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/" private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/"
@ -55,9 +54,10 @@ object WebDavHelp {
if (initWebDav()) { if (initWebDav()) {
var files = WebDav(url).listFiles() var files = WebDav(url).listFiles()
files = files.reversed() files = files.reversed()
for (index: Int in 0 until min(10, files.size)) { files.forEach {
files[index].displayName?.let { val name = it.displayName
names.add(it) if (name?.startsWith("backup") == true) {
names.add(name)
} }
} }
} }
@ -85,16 +85,12 @@ object WebDavHelp {
private fun restoreWebDav(name: String) { private fun restoreWebDav(name: String) {
Coroutine.async { Coroutine.async {
rootWebDavUrl.let { rootWebDavUrl.let {
if (name == SyncBookProgress.fileName) { val webDav = WebDav(it + name)
SyncBookProgress.downloadBookProgress() webDav.downloadTo(zipFilePath, true)
} else { @Suppress("BlockingMethodInNonBlockingContext")
val webDav = WebDav(it + name) ZipUtils.unzipFile(zipFilePath, Backup.backupPath)
webDav.downloadTo(zipFilePath, true) Restore.restoreDatabase()
@Suppress("BlockingMethodInNonBlockingContext") Restore.restoreConfig()
ZipUtils.unzipFile(zipFilePath, Backup.backupPath)
Restore.restoreDatabase()
Restore.restoreConfig()
}
} }
}.onError { }.onError {
App.INSTANCE.toast("WebDavError:${it.localizedMessage}") App.INSTANCE.toast("WebDavError:${it.localizedMessage}")
@ -122,6 +118,7 @@ object WebDavHelp {
} }
} }
} }
fun exportWebDav(path: String, fileName: String) { fun exportWebDav(path: String, fileName: String) {
try { try {
if (initWebDav()) { if (initWebDav()) {
@ -131,7 +128,7 @@ object WebDavHelp {
WebDav(exportsWebDavUrl).makeAsDir() WebDav(exportsWebDavUrl).makeAsDir()
val file = File("${path}${File.separator}${fileName}") val file = File("${path}${File.separator}${fileName}")
// 如果导出的本地文件存在,开始上传 // 如果导出的本地文件存在,开始上传
if(file.exists()) { if (file.exists()) {
val putUrl = exportsWebDavUrl + fileName val putUrl = exportsWebDavUrl + fileName
WebDav(putUrl).upload("${path}${File.separator}${fileName}") WebDav(putUrl).upload("${path}${File.separator}${fileName}")
} }

@ -50,6 +50,7 @@ class WebDav(urlStr: String) {
var exists = false var exists = false
var parent = "" var parent = ""
var urlName = "" var urlName = ""
var contentType = ""
/** /**
* 填充文件信息实例化WebDAVFile对象时并没有将远程文件的信息填充到实例中需要手动填充 * 填充文件信息实例化WebDAVFile对象时并没有将远程文件的信息填充到实例中需要手动填充
@ -139,6 +140,9 @@ class WebDav(urlStr: String) {
try { try {
webDavFile = WebDav(baseUrl + fileName) webDavFile = WebDav(baseUrl + fileName)
webDavFile.displayName = fileName webDavFile.displayName = fileName
webDavFile.contentType = element
.getElementsByTag("d:getcontenttype")
.getOrNull(0)?.text() ?: ""
if (href.isEmpty()) { if (href.isEmpty()) {
webDavFile.urlName = webDavFile.urlName =
if (parent.isEmpty()) url.file.replace("/", "") if (parent.isEmpty()) url.file.replace("/", "")
@ -188,6 +192,11 @@ class WebDav(urlStr: String) {
return true return true
} }
fun download(): ByteArray? {
val inputS = getInputStream() ?: return null
return inputS.readBytes()
}
/** /**
* 上传文件 * 上传文件
*/ */
@ -207,6 +216,19 @@ class WebDav(urlStr: String) {
return false return false
} }
fun upload(byteArray: ByteArray, contentType: String? = null): Boolean {
val mediaType = contentType?.let { MediaType.parse(it) }
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
val fileBody = RequestBody.create(mediaType, byteArray)
httpUrl?.let {
val request = Request.Builder()
.url(it)
.put(fileBody)
return execRequest(request)
}
return false
}
/** /**
* 执行请求获取响应结果 * 执行请求获取响应结果
* @param requestBuilder 因为还需要追加验证信息所以此处传递Request.Builder的对象而不是Request的对象 * @param requestBuilder 因为还需要追加验证信息所以此处传递Request.Builder的对象而不是Request的对象

@ -138,7 +138,9 @@ class ReadBookActivity : ReadBookBaseActivity(),
} }
upSystemUiVisibility() upSystemUiVisibility()
if (!BuildConfig.DEBUG) { if (!BuildConfig.DEBUG) {
SyncBookProgress.uploadBookProgress() ReadBook.book?.let {
SyncBookProgress.uploadBookProgress(it)
}
Backup.autoBack(this) Backup.autoBack(this)
} }
} }
@ -814,7 +816,6 @@ class ReadBookActivity : ReadBookBaseActivity(),
binding.readView.onDestroy() binding.readView.onDestroy()
ReadBook.msg = null ReadBook.msg = null
if (!BuildConfig.DEBUG) { if (!BuildConfig.DEBUG) {
SyncBookProgress.uploadBookProgress()
Backup.autoBack(this) Backup.autoBack(this)
} }
} }

@ -11,6 +11,7 @@ import io.legado.app.data.entities.SearchBook
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.BookHelp import io.legado.app.help.BookHelp
import io.legado.app.help.IntentDataHelp import io.legado.app.help.IntentDataHelp
import io.legado.app.help.storage.SyncBookProgress
import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.LocalBook
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.service.BaseReadAloudService import io.legado.app.service.BaseReadAloudService
@ -46,6 +47,12 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
private fun initBook(book: Book) { private fun initBook(book: Book) {
if (ReadBook.book?.bookUrl != book.bookUrl) { if (ReadBook.book?.bookUrl != book.bookUrl) {
SyncBookProgress.getBookProgress(book)?.let {
book.durChapterIndex = it.durChapterIndex
book.durChapterPos = it.durChapterPos
book.durChapterTime = it.durChapterTime
book.durChapterTitle = it.durChapterTitle
}
ReadBook.resetData(book) ReadBook.resetData(book)
isInitFinish = true isInitFinish = true
if (!book.isLocalBook() && ReadBook.webBook == null) { if (!book.isLocalBook() && ReadBook.webBook == null) {

@ -10,7 +10,6 @@ import io.legado.app.constant.PreferKey
import io.legado.app.databinding.ActivityWelcomeBinding import io.legado.app.databinding.ActivityWelcomeBinding
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.help.storage.SyncBookProgress
import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.accentColor
import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.book.read.ReadBookActivity
import io.legado.app.ui.main.MainActivity import io.legado.app.ui.main.MainActivity
@ -50,7 +49,6 @@ open class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
else -> null else -> null
} }
} }
SyncBookProgress.downloadBookProgress()
binding.root.postDelayed({ startMainActivity() }, 500) binding.root.postDelayed({ startMainActivity() }, 500)
} }

Loading…
Cancel
Save