This commit is contained in:
Horis
2025-10-27 11:19:26 +08:00
parent ee5ef0e6ba
commit 6b55311ccc
9 changed files with 56 additions and 30 deletions
@@ -17,6 +17,7 @@ object AppPattern {
val nameRegex = Regex("\\s+作\\s*者.*|\\s+\\S+\\s+著") val nameRegex = Regex("\\s+作\\s*者.*|\\s+\\S+\\s+著")
val authorRegex = Regex("^\\s*作\\s*者[:\\s]+|\\s+著") val authorRegex = Regex("^\\s*作\\s*者[:\\s]+|\\s+著")
val fileNameRegex = Regex("[\\\\/:*?\"<>|.]") val fileNameRegex = Regex("[\\\\/:*?\"<>|.]")
val fileNameRegex2 = Regex("[\\\\/:*?\"<>|]")
val splitGroupRegex = Regex("[,;,;]") val splitGroupRegex = Regex("[,;,;]")
val titleNumPattern: Pattern = Pattern.compile("(第)(.+?)(章)") val titleNumPattern: Pattern = Pattern.compile("(第)(.+?)(章)")
@@ -25,13 +25,14 @@ import io.legado.app.utils.compress.ZipUtils
import io.legado.app.utils.fromJsonObject import io.legado.app.utils.fromJsonObject
import io.legado.app.utils.getPrefString import io.legado.app.utils.getPrefString
import io.legado.app.utils.isJson import io.legado.app.utils.isJson
import io.legado.app.utils.normalizeFileName
import io.legado.app.utils.removePref import io.legado.app.utils.removePref
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
import kotlin.coroutines.coroutineContext
/** /**
* webDav初始化会访问网络,不要放到主线程 * webDav初始化会访问网络,不要放到主线程
@@ -219,7 +220,7 @@ object AppWebDav {
WebDav(putUrl, it).upload(byteArray, "text/plain") WebDav(putUrl, it).upload(byteArray, "text/plain")
} }
} catch (e: Exception) { } catch (e: Exception) {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("WebDav导出失败\n${e.localizedMessage}", e, true) AppLog.put("WebDav导出失败\n${e.localizedMessage}", e, true)
} }
} }
@@ -233,12 +234,16 @@ object AppWebDav {
WebDav(putUrl, it).upload(uri, "text/plain") WebDav(putUrl, it).upload(uri, "text/plain")
} }
} catch (e: Exception) { } catch (e: Exception) {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("WebDav导出失败\n${e.localizedMessage}", e, true) AppLog.put("WebDav导出失败\n${e.localizedMessage}", e, true)
} }
} }
suspend fun uploadBookProgress(book: Book) { suspend fun uploadBookProgress(
book: Book,
toast: Boolean = false,
onSuccess: (() -> Unit)? = null
) {
val authorization = authorization ?: return val authorization = authorization ?: return
if (!AppConfig.syncBookProgress) return if (!AppConfig.syncBookProgress) return
if (!NetworkUtils.isAvailable()) return if (!NetworkUtils.isAvailable()) return
@@ -248,9 +253,10 @@ object AppWebDav {
val url = getProgressUrl(book.name, book.author) val url = getProgressUrl(book.name, book.author)
WebDav(url, authorization).upload(json.toByteArray(), "application/json") WebDav(url, authorization).upload(json.toByteArray(), "application/json")
book.syncTime = System.currentTimeMillis() book.syncTime = System.currentTimeMillis()
onSuccess?.invoke()
} catch (e: Exception) { } catch (e: Exception) {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("上传进度失败\n${e.localizedMessage}", e) AppLog.put("上传进度失败\n${e.localizedMessage}", e, toast)
} }
} }
@@ -264,7 +270,7 @@ object AppWebDav {
WebDav(url, authorization).upload(json.toByteArray(), "application/json") WebDav(url, authorization).upload(json.toByteArray(), "application/json")
onSuccess?.invoke() onSuccess?.invoke()
} catch (e: Exception) { } catch (e: Exception) {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("上传进度失败\n${e.localizedMessage}", e) AppLog.put("上传进度失败\n${e.localizedMessage}", e)
} }
} }
@@ -274,27 +280,26 @@ object AppWebDav {
} }
private fun getProgressFileName(name: String, author: String): String { private fun getProgressFileName(name: String, author: String): String {
return UrlUtil.replaceReservedChar("${name}_${author}") + ".json" return UrlUtil.replaceReservedChar("${name}_${author}".normalizeFileName()) + ".json"
} }
/** /**
* 获取书籍进度 * 获取书籍进度
*/ */
suspend fun getBookProgress(book: Book): BookProgress? { suspend fun getBookProgress(book: Book): BookProgress? {
authorization?.let {
val url = getProgressUrl(book.name, book.author) val url = getProgressUrl(book.name, book.author)
kotlin.runCatching { kotlin.runCatching {
WebDav(url, it).download().let { byteArray -> val authorization = authorization ?: return null
WebDav(url, authorization).download().let { byteArray ->
val json = String(byteArray) val json = String(byteArray)
if (json.isJson()) { if (json.isJson()) {
return GSON.fromJsonObject<BookProgress>(json).getOrNull() return GSON.fromJsonObject<BookProgress>(json).getOrNull()
} }
} }
}.onFailure { }.onFailure {
coroutineContext.ensureActive() currentCoroutineContext().ensureActive()
AppLog.put("获取书籍进度失败\n${it.localizedMessage}", it) AppLog.put("获取书籍进度失败\n${it.localizedMessage}", it)
} }
}
return null return null
} }
@@ -24,6 +24,7 @@ import io.legado.app.utils.exists
import io.legado.app.utils.find import io.legado.app.utils.find
import io.legado.app.utils.inputStream import io.legado.app.utils.inputStream
import io.legado.app.utils.isUri import io.legado.app.utils.isUri
import io.legado.app.utils.normalizeFileName
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
@@ -346,7 +347,7 @@ fun Book.getExportFileName(
RhinoScriptEngine.eval(jsStr, bindings).toString() + "." + suffix RhinoScriptEngine.eval(jsStr, bindings).toString() + "." + suffix
}.onFailure { }.onFailure {
AppLog.put("导出书名规则错误,使用默认规则\n${it.localizedMessage}", it) AppLog.put("导出书名规则错误,使用默认规则\n${it.localizedMessage}", it)
}.getOrDefault(default) }.getOrDefault(default).normalizeFileName()
} }
// 根据当前日期计算章节总数 // 根据当前日期计算章节总数
@@ -14,8 +14,20 @@ import io.legado.app.help.config.LocalConfig
import io.legado.app.help.config.ReadBookConfig import io.legado.app.help.config.ReadBookConfig
import io.legado.app.help.config.ThemeConfig import io.legado.app.help.config.ThemeConfig
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.utils.* import io.legado.app.utils.FileUtils
import io.legado.app.utils.GSON
import io.legado.app.utils.LogUtils
import io.legado.app.utils.compress.ZipUtils import io.legado.app.utils.compress.ZipUtils
import io.legado.app.utils.createFolderIfNotExist
import io.legado.app.utils.defaultSharedPreferences
import io.legado.app.utils.externalFiles
import io.legado.app.utils.getFile
import io.legado.app.utils.getSharedPreferences
import io.legado.app.utils.isContentScheme
import io.legado.app.utils.normalizeFileName
import io.legado.app.utils.openOutputStream
import io.legado.app.utils.outputStream
import io.legado.app.utils.writeToOutputStream
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@@ -26,7 +38,8 @@ import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileOutputStream import java.io.FileOutputStream
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.coroutines.coroutineContext import kotlin.coroutines.coroutineContext
@@ -77,7 +90,7 @@ object Backup {
"backup${backupDate}-${deviceName}.zip" "backup${backupDate}-${deviceName}.zip"
} else { } else {
"backup${backupDate}.zip" "backup${backupDate}.zip"
} }.normalizeFileName()
} }
private fun shouldBackup(): Boolean { private fun shouldBackup(): Boolean {
@@ -224,13 +224,14 @@ object ReadBook : CoroutineScope by MainScope() {
nextTextChapter?.clearSearchResult() nextTextChapter?.clearSearchResult()
} }
fun uploadProgress(successAction: (() -> Unit)? = null) { fun uploadProgress(toast: Boolean = false, successAction: (() -> Unit)? = null) {
book?.let { book?.let {
launch(IO) { launch(IO) {
AppWebDav.uploadBookProgress(it) AppWebDav.uploadBookProgress(it, toast) {
successAction?.invoke()
}
ensureActive() ensureActive()
it.update() it.update()
successAction?.invoke()
} }
} }
} }
@@ -482,10 +482,11 @@ object ReadManga : CoroutineScope by MainScope() {
fun uploadProgress(successAction: (() -> Unit)? = null) { fun uploadProgress(successAction: (() -> Unit)? = null) {
book?.let { book?.let {
launch(IO) { launch(IO) {
AppWebDav.uploadBookProgress(it) AppWebDav.uploadBookProgress(it) {
successAction?.invoke()
}
ensureActive() ensureActive()
it.update() it.update()
successAction?.invoke()
} }
} }
} }
@@ -598,7 +598,7 @@ class ReadBookActivity : BaseReadBookActivity(),
} }
R.id.menu_cover_progress -> ReadBook.book?.let { R.id.menu_cover_progress -> ReadBook.book?.let {
ReadBook.uploadProgress { toastOnUi(R.string.upload_book_success) } ReadBook.uploadProgress(true) { toastOnUi(R.string.upload_book_success) }
} }
R.id.menu_same_title_removed -> { R.id.menu_same_title_removed -> {
@@ -140,3 +140,7 @@ fun String.escapeRegex(): String {
} }
fun String.encodeURI(): String = URLEncodeUtil.encodeQuery(this) fun String.encodeURI(): String = URLEncodeUtil.encodeQuery(this)
fun String.normalizeFileName(): String {
return replace(AppPattern.fileNameRegex2, "_")
}
+1 -1
View File
@@ -50,7 +50,7 @@ viewpager2 = "1.0.0"
webkit = "1.13.0" webkit = "1.13.0"
collection = "1.5.0" collection = "1.5.0"
zxingLite = "3.2.0" zxingLite = "3.3.0"
[libraries] [libraries]