diff --git a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt index 4523d1340..53c57add3 100644 --- a/app/src/main/java/io/legado/app/help/book/BookExtensions.kt +++ b/app/src/main/java/io/legado/app/help/book/BookExtensions.kt @@ -121,6 +121,29 @@ fun Book.contains(word: String?): Boolean { || intro?.contains(word) == true } +/** + * 仅在目标bookUrl未被其他书占用,或判定为同一本书时,允许迁移主键。 + */ +fun Book.canSafelyRebindTo(newBookUrl: String): Boolean { + if (newBookUrl == bookUrl) return true + val targetBook = appDb.bookDao.getBook(newBookUrl) ?: return true + + val sameOriginName = originName.isNotBlank() && originName == targetBook.originName + val sameNameAuthor = name.isNotBlank() && author.isNotBlank() + && name == targetBook.name && author == targetBook.author + val sameOrigin = origin.isNotBlank() && origin == targetBook.origin + val canMerge = sameOriginName && (sameNameAuthor || sameOrigin) + if (!canMerge) { + AppLog.put( + "书籍重定位冲突,已跳过迁移\n" + + "old=$bookUrl\nnew=$newBookUrl\n" + + "oldName=$name oldAuthor=$author oldOriginName=$originName\n" + + "targetName=${targetBook.name} targetAuthor=${targetBook.author} targetOriginName=${targetBook.originName}" + ) + } + return canMerge +} + private val localUriCache by lazy { ConcurrentHashMap() } @@ -150,17 +173,31 @@ fun Book.getLocalUri(): Uri { // 查找书籍保存目录 if (!defaultBookDir.isNullOrBlank()) { - val treeUri = Uri.parse(defaultBookDir) + val treeUri = defaultBookDir.toUri() val treeFileDoc = FileDoc.fromUri(treeUri, true) + if (!treeFileDoc.exists()) { appCtx.toastOnUi("书籍保存目录失效,请重新设置!") } else { val fileDoc = treeFileDoc.find(originName, 5, 100) if (fileDoc != null) { - localUriCache[bookUrl] = fileDoc.uri - //更新bookUrl 重启不用再找一遍 - bookUrl = fileDoc.toString() - save() + val newBookUrl = fileDoc.toString() + val oldBook = copy() + if (!oldBook.canSafelyRebindTo(newBookUrl)) { + return fileDoc.uri + } + appDb.runInTransaction { + + if (oldBook.bookUrl == newBookUrl) { + save() + } else { + val newBook = oldBook.copy(bookUrl = newBookUrl) + appDb.bookDao.replace(oldBook, newBook) + BookHelp.updateCacheFolder(oldBook, newBook) + this.bookUrl = newBookUrl + } + } + localUriCache[newBookUrl] = fileDoc.uri return fileDoc.uri } } @@ -176,9 +213,23 @@ fun Book.getLocalUri(): Uri { val treeFileDoc = FileDoc.fromUri(treeUri, true) val fileDoc = treeFileDoc.find(originName, 5, 100) if (fileDoc != null) { - localUriCache[bookUrl] = fileDoc.uri - bookUrl = fileDoc.toString() - save() + val newBookUrl = fileDoc.toString() + val oldBook = copy() + if (!oldBook.canSafelyRebindTo(newBookUrl)) { + return fileDoc.uri + } + + appDb.runInTransaction { + if (oldBook.bookUrl == newBookUrl) { + save() + } else { + val newBook = oldBook.copy(bookUrl = newBookUrl) + appDb.bookDao.replace(oldBook, newBook) + BookHelp.updateCacheFolder(oldBook, newBook) + this.bookUrl = newBookUrl + } + } + localUriCache[newBookUrl] = fileDoc.uri return fileDoc.uri } } @@ -438,4 +489,4 @@ fun tryParesExportFileName(jsStr: String): Boolean { RhinoScriptEngine.eval(jsStr, bindings) true }.getOrDefault(false) -} \ No newline at end of file +} diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index e95ef0de4..12149714a 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -23,6 +23,8 @@ import io.legado.app.help.book.BookHelp import io.legado.app.help.book.ContentProcessor import io.legado.app.help.book.addType import io.legado.app.help.book.archiveName +import io.legado.app.help.book.cacheLocalUri +import io.legado.app.help.book.canSafelyRebindTo import io.legado.app.help.book.getArchiveUri import io.legado.app.help.book.getLocalUri import io.legado.app.help.book.getRemoteUrl @@ -37,6 +39,7 @@ import io.legado.app.help.config.AppConfig import io.legado.app.lib.webdav.WebDav import io.legado.app.lib.webdav.WebDavException import io.legado.app.model.analyzeRule.AnalyzeUrl +import io.legado.app.model.analyzeRule.CustomUrl import io.legado.app.utils.ArchiveUtils import io.legado.app.utils.FileDoc import io.legado.app.utils.FileUtils @@ -50,6 +53,7 @@ import io.legado.app.utils.isAbsUrl import io.legado.app.utils.isContentScheme import io.legado.app.utils.isDataUrl import io.legado.app.utils.printOnDebug +import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.runBlocking import org.apache.commons.text.StringEscapeUtils import splitties.init.appCtx @@ -60,7 +64,6 @@ import java.io.FileNotFoundException import java.io.FileOutputStream import java.io.InputStream import java.util.regex.Pattern -import kotlin.coroutines.coroutineContext /** * 书籍文件导入 目录正文解析 @@ -403,7 +406,7 @@ object LocalBook { val inputStream = when { str.isAbsUrl() -> AnalyzeUrl( str, source = source, callTimeout = 0, - coroutineContext = coroutineContext + coroutineContext = currentCoroutineContext() ).getInputStreamAwait() str.isDataUrl() -> ByteArrayInputStream( @@ -458,7 +461,7 @@ object LocalBook { fun isOnBookShelf( fileName: String ): Boolean { - return appDb.bookDao.hasFile(fileName) == true + return appDb.bookDao.hasFile(fileName) } //文件类书源 合并在线书籍信息 在线 > 本地 @@ -501,9 +504,31 @@ object LocalBook { localBook.bookUrl = newBook.bookUrl } else { // txt epub pdf umd + val oldBook = localBook.copy() val fileUri = saveBookFile(it, localBook.originName) - localBook.bookUrl = FileDoc.fromUri(fileUri, false).toString() - localBook.save() + val newBookUrl = FileDoc.fromUri(fileUri, false).toString() + if (!oldBook.canSafelyRebindTo(newBookUrl)) { + localBook.cacheLocalUri(fileUri) + return true + } + + appDb.runInTransaction { + if (oldBook.bookUrl == newBookUrl) { + localBook.origin = + BookType.webDavTag + CustomUrl(webDavUrl).toString() + + localBook.save() + } else { + val newBook = oldBook.copy( + bookUrl = newBookUrl, + origin = BookType.webDavTag + CustomUrl(webDavUrl).toString() + ) + appDb.bookDao.replace(oldBook, newBook) + BookHelp.updateCacheFolder(oldBook, newBook) + localBook.bookUrl = newBookUrl + localBook.origin = newBook.origin + } + } } } return true