Rename
This commit is contained in:
1 parent
b86d90021c
commit
6c0757c91b
972 files changed
+6885
-7321
No files matched your search
@@ -0,0 +1,333 @@
|
||||
package io.legato.kazusa.help
|
||||
|
||||
import android.net.Uri
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
import io.legato.kazusa.constant.PreferKey
|
||||
import io.legato.kazusa.data.appDb
|
||||
import io.legato.kazusa.data.entities.Book
|
||||
import io.legato.kazusa.data.entities.BookProgress
|
||||
import io.legato.kazusa.exception.NoStackTraceException
|
||||
import io.legato.kazusa.help.config.AppConfig
|
||||
import io.legato.kazusa.help.storage.Backup
|
||||
import io.legato.kazusa.help.storage.Restore
|
||||
import io.legato.kazusa.lib.webdav.Authorization
|
||||
import io.legato.kazusa.lib.webdav.WebDav
|
||||
import io.legato.kazusa.lib.webdav.WebDavException
|
||||
import io.legato.kazusa.lib.webdav.WebDavFile
|
||||
import io.legato.kazusa.model.remote.RemoteBookWebDav
|
||||
import io.legato.kazusa.utils.AlphanumComparator
|
||||
import io.legato.kazusa.utils.FileUtils
|
||||
import io.legato.kazusa.utils.GSON
|
||||
import io.legato.kazusa.utils.NetworkUtils
|
||||
import io.legato.kazusa.utils.UrlUtil
|
||||
import io.legato.kazusa.utils.compress.ZipUtils
|
||||
import io.legato.kazusa.utils.fromJsonObject
|
||||
import io.legato.kazusa.utils.getPrefString
|
||||
import io.legato.kazusa.utils.isJson
|
||||
import io.legato.kazusa.utils.removePref
|
||||
import io.legato.kazusa.utils.toastOnUi
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
/**
|
||||
* webDav初始化会访问网络,不要放到主线程
|
||||
*/
|
||||
object AppWebDav {
|
||||
private const val defaultWebDavUrl = "https://dav.jianguoyun.com/dav/"
|
||||
private val bookProgressUrl get() = "${rootWebDavUrl}bookProgress/"
|
||||
private val exportsWebDavUrl get() = "${rootWebDavUrl}books/"
|
||||
private val bgWebDavUrl get() = "${rootWebDavUrl}background/"
|
||||
|
||||
var authorization: Authorization? = null
|
||||
private set
|
||||
|
||||
var defaultBookWebDav: RemoteBookWebDav? = null
|
||||
|
||||
val isOk get() = authorization != null
|
||||
|
||||
val isJianGuoYun get() = rootWebDavUrl.startsWith(defaultWebDavUrl, true)
|
||||
|
||||
init {
|
||||
runBlocking {
|
||||
upConfig()
|
||||
}
|
||||
}
|
||||
|
||||
private val rootWebDavUrl: String
|
||||
get() {
|
||||
val configUrl = appCtx.getPrefString(PreferKey.webDavUrl)?.trim()
|
||||
var url = if (configUrl.isNullOrEmpty()) defaultWebDavUrl else configUrl
|
||||
if (!url.endsWith("/")) url = "${url}/"
|
||||
AppConfig.webDavDir?.trim()?.let {
|
||||
if (it.isNotEmpty()) {
|
||||
url = "${url}${it}/"
|
||||
}
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
suspend fun upConfig() {
|
||||
kotlin.runCatching {
|
||||
authorization = null
|
||||
defaultBookWebDav = null
|
||||
val account = appCtx.getPrefString(PreferKey.webDavAccount)
|
||||
val password = appCtx.getPrefString(PreferKey.webDavPassword)
|
||||
if (!account.isNullOrEmpty() && !password.isNullOrEmpty()) {
|
||||
val mAuthorization = Authorization(account, password)
|
||||
checkAuthorization(mAuthorization)
|
||||
WebDav(rootWebDavUrl, mAuthorization).makeAsDir()
|
||||
WebDav(bookProgressUrl, mAuthorization).makeAsDir()
|
||||
WebDav(exportsWebDavUrl, mAuthorization).makeAsDir()
|
||||
WebDav(bgWebDavUrl, mAuthorization).makeAsDir()
|
||||
val rootBooksUrl = "${rootWebDavUrl}books/"
|
||||
defaultBookWebDav = RemoteBookWebDav(rootBooksUrl, mAuthorization)
|
||||
authorization = mAuthorization
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(WebDavException::class)
|
||||
private suspend fun checkAuthorization(authorization: Authorization) {
|
||||
if (!WebDav(rootWebDavUrl, authorization).check()) {
|
||||
appCtx.removePref(PreferKey.webDavPassword)
|
||||
appCtx.toastOnUi(R.string.webdav_application_authorization_error)
|
||||
throw WebDavException(appCtx.getString(R.string.webdav_application_authorization_error))
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
suspend fun getBackupNames(): ArrayList<String> {
|
||||
val names = arrayListOf<String>()
|
||||
authorization?.let {
|
||||
var files = WebDav(rootWebDavUrl, it).listFiles()
|
||||
files = files.sortedWith { o1, o2 ->
|
||||
AlphanumComparator.compare(o1.displayName, o2.displayName)
|
||||
}.reversed()
|
||||
files.forEach { webDav ->
|
||||
val name = webDav.displayName
|
||||
if (name.startsWith("backup")) {
|
||||
names.add(name)
|
||||
}
|
||||
}
|
||||
} ?: throw NoStackTraceException("webDav没有配置")
|
||||
return names
|
||||
}
|
||||
|
||||
@Throws(WebDavException::class)
|
||||
suspend fun restoreWebDav(name: String) {
|
||||
authorization?.let {
|
||||
val webDav = WebDav(rootWebDavUrl + name, it)
|
||||
webDav.downloadTo(Backup.zipFilePath, true)
|
||||
FileUtils.delete(Backup.backupPath)
|
||||
ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath)
|
||||
Restore.restoreLocked(Backup.backupPath)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun hasBackUp(backUpName: String): Boolean {
|
||||
authorization?.let {
|
||||
val url = "$rootWebDavUrl${backUpName}"
|
||||
return WebDav(url, it).exists()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
suspend fun lastBackUp(): Result<WebDavFile?> {
|
||||
return kotlin.runCatching {
|
||||
authorization?.let {
|
||||
var lastBackupFile: WebDavFile? = null
|
||||
WebDav(rootWebDavUrl, it).listFiles().reversed().forEach { webDavFile ->
|
||||
if (webDavFile.displayName.startsWith("backup")) {
|
||||
if (lastBackupFile == null
|
||||
|| webDavFile.lastModify > lastBackupFile.lastModify
|
||||
) {
|
||||
lastBackupFile = webDavFile
|
||||
}
|
||||
}
|
||||
}
|
||||
lastBackupFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* webDav备份
|
||||
* @param fileName 备份文件名
|
||||
*/
|
||||
@Throws(Exception::class)
|
||||
suspend fun backUpWebDav(fileName: String) {
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
authorization?.let {
|
||||
val putUrl = "$rootWebDavUrl$fileName"
|
||||
WebDav(putUrl, it).upload(Backup.zipFilePath)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取云端所有背景名称
|
||||
*/
|
||||
private suspend fun getAllBgWebDavFiles(): Result<List<WebDavFile>> {
|
||||
return kotlin.runCatching {
|
||||
if (!NetworkUtils.isAvailable())
|
||||
throw NoStackTraceException("网络未连接")
|
||||
authorization.let {
|
||||
it ?: throw NoStackTraceException("webDav未配置")
|
||||
WebDav(bgWebDavUrl, it).listFiles()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传背景图片
|
||||
*/
|
||||
suspend fun upBgs(files: Array<File>) {
|
||||
val authorization = authorization ?: return
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
val bgWebDavFiles = getAllBgWebDavFiles().getOrThrow()
|
||||
.map { it.displayName }
|
||||
.toSet()
|
||||
files.forEach {
|
||||
if (!bgWebDavFiles.contains(it.name) && it.exists()) {
|
||||
WebDav("$bgWebDavUrl${it.name}", authorization)
|
||||
.upload(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载背景图片
|
||||
*/
|
||||
suspend fun downBgs() {
|
||||
val authorization = authorization ?: return
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
val bgWebDavFiles = getAllBgWebDavFiles().getOrThrow()
|
||||
.map { it.displayName }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
suspend fun exportWebDav(byteArray: ByteArray, fileName: String) {
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
try {
|
||||
authorization?.let {
|
||||
// 如果导出的本地文件存在,开始上传
|
||||
val putUrl = exportsWebDavUrl + fileName
|
||||
WebDav(putUrl, it).upload(byteArray, "text/plain")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
coroutineContext.ensureActive()
|
||||
AppLog.put("WebDav导出失败\n${e.localizedMessage}", e, true)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun exportWebDav(uri: Uri, fileName: String) {
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
try {
|
||||
authorization?.let {
|
||||
// 如果导出的本地文件存在,开始上传
|
||||
val putUrl = exportsWebDavUrl + fileName
|
||||
WebDav(putUrl, it).upload(uri, "text/plain")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
coroutineContext.ensureActive()
|
||||
AppLog.put("WebDav导出失败\n${e.localizedMessage}", e, true)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun uploadBookProgress(book: Book) {
|
||||
val authorization = authorization ?: return
|
||||
if (!AppConfig.syncBookProgress) return
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
try {
|
||||
val bookProgress = BookProgress(book)
|
||||
val json = GSON.toJson(bookProgress)
|
||||
val url = getProgressUrl(book.name, book.author)
|
||||
WebDav(url, authorization).upload(json.toByteArray(), "application/json")
|
||||
book.syncTime = System.currentTimeMillis()
|
||||
} catch (e: Exception) {
|
||||
coroutineContext.ensureActive()
|
||||
AppLog.put("上传进度失败\n${e.localizedMessage}", e)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun uploadBookProgress(bookProgress: BookProgress, onSuccess: (() -> Unit)? = null) {
|
||||
try {
|
||||
val authorization = authorization ?: return
|
||||
if (!AppConfig.syncBookProgress) return
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
val json = GSON.toJson(bookProgress)
|
||||
val url = getProgressUrl(bookProgress.name, bookProgress.author)
|
||||
WebDav(url, authorization).upload(json.toByteArray(), "application/json")
|
||||
onSuccess?.invoke()
|
||||
} catch (e: Exception) {
|
||||
coroutineContext.ensureActive()
|
||||
AppLog.put("上传进度失败\n${e.localizedMessage}", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getProgressUrl(name: String, author: String): String {
|
||||
return bookProgressUrl + getProgressFileName(name, author)
|
||||
}
|
||||
|
||||
private fun getProgressFileName(name: String, author: String): String {
|
||||
return UrlUtil.replaceReservedChar("${name}_${author}") + ".json"
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取书籍进度
|
||||
*/
|
||||
suspend fun getBookProgress(book: Book): BookProgress? {
|
||||
authorization?.let {
|
||||
val url = getProgressUrl(book.name, book.author)
|
||||
kotlin.runCatching {
|
||||
WebDav(url, it).download().let { byteArray ->
|
||||
val json = String(byteArray)
|
||||
if (json.isJson()) {
|
||||
return GSON.fromJsonObject<BookProgress>(json).getOrNull()
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
coroutineContext.ensureActive()
|
||||
AppLog.put("获取书籍进度失败\n${it.localizedMessage}", it)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun downloadAllBookProgress() {
|
||||
val authorization = authorization ?: return
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
val bookProgressFiles = WebDav(bookProgressUrl, authorization).listFiles()
|
||||
val map = hashMapOf<String, WebDavFile>()
|
||||
bookProgressFiles.forEach {
|
||||
map[it.displayName] = it
|
||||
}
|
||||
appDb.bookDao.all.forEach { book ->
|
||||
val progressFileName = getProgressFileName(book.name, book.author)
|
||||
val webDavFile = map[progressFileName]
|
||||
webDavFile ?: return
|
||||
if (webDavFile.lastModify <= book.syncTime) {
|
||||
//本地同步时间大于上传时间不用同步
|
||||
return
|
||||
}
|
||||
getBookProgress(book)?.let { bookProgress ->
|
||||
if (bookProgress.durChapterIndex > book.durChapterIndex
|
||||
|| (bookProgress.durChapterIndex == book.durChapterIndex
|
||||
&& bookProgress.durChapterPos > book.durChapterPos)
|
||||
) {
|
||||
book.durChapterIndex = bookProgress.durChapterIndex
|
||||
book.durChapterPos = bookProgress.durChapterPos
|
||||
book.durChapterTitle = bookProgress.durChapterTitle
|
||||
book.durChapterTime = bookProgress.durChapterTime
|
||||
book.syncTime = System.currentTimeMillis()
|
||||
appDb.bookDao.update(book)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user