Horis 4 ani în urmă
părinte
comite
1fa3cb898d

+ 12 - 2
app/src/main/java/io/legado/app/ui/association/BaseAssociationViewModel.kt

@@ -1,19 +1,29 @@
 package io.legado.app.ui.association
 
 import android.app.Application
+import android.net.Uri
 import androidx.lifecycle.MutableLiveData
 import io.legado.app.base.BaseViewModel
+import io.legado.app.utils.contains
+import io.legado.app.utils.inputStream
+import io.legado.app.utils.readText
 
 abstract class BaseAssociationViewModel(application: Application) : BaseViewModel(application) {
 
     val successLive = MutableLiveData<Pair<String, String>>()
     val errorLive = MutableLiveData<String>()
 
+    fun importJson(uri: Uri) {
+        when {
+            uri.inputStream(context).contains("bookSourceUrl") ->
+                successLive.postValue(Pair("bookSource", uri.toString()))
+            else -> importJson(uri.readText(context))
+        }
+    }
+
     fun importJson(json: String) {
         //暂时根据文件内容判断属于什么
         when {
-            json.contains("bookSourceUrl") ->
-                successLive.postValue(Pair("bookSource", json))
             json.contains("sourceUrl") ->
                 successLive.postValue(Pair("rssSource", json))
             json.contains("pattern") ->

+ 8 - 10
app/src/main/java/io/legado/app/ui/association/FileAssociationViewModel.kt

@@ -7,7 +7,9 @@ import androidx.lifecycle.MutableLiveData
 import io.legado.app.constant.AppLog
 import io.legado.app.constant.AppPattern.bookFileRegex
 import io.legado.app.exception.NoStackTraceException
+import io.legado.app.help.IntentData
 import io.legado.app.model.localBook.LocalBook
+import io.legado.app.utils.inputStream
 import io.legado.app.utils.isJson
 import io.legado.app.utils.printOnDebug
 import java.io.File
@@ -23,24 +25,19 @@ class FileAssociationViewModel(application: Application) : BaseAssociationViewMo
     fun dispatchIndent(uri: Uri) {
         execute {
             lateinit var fileName: String
-            lateinit var content: String
-            lateinit var fileStream: InputStream
             //如果是普通的url,需要根据返回的内容判断是什么
             if (uri.scheme == "file" || uri.scheme == "content") {
-                if (uri.scheme == "file") {
+                fileName = if (uri.scheme == "file") {
                     val file = File(uri.path.toString())
-                    fileStream = file.inputStream()
-                    fileName = file.name
+                    file.name
                 } else {
                     val file = DocumentFile.fromSingleUri(context, uri)
                     if (file?.exists() != true) throw NoStackTraceException("文件不存在")
-                    fileStream = context.contentResolver.openInputStream(uri)!!
-                    fileName = file.name ?: ""
+                    file.name ?: ""
                 }
                 kotlin.runCatching {
-                    content = fileStream.reader(Charsets.UTF_8).use { it.readText() }
-                    if (content.isJson()) {
-                        importJson(content)
+                    if (uri.inputStream(context).isJson()) {
+                        importJson(uri)
                         return@execute
                     }
                 }.onFailure {
@@ -58,6 +55,7 @@ class FileAssociationViewModel(application: Application) : BaseAssociationViewMo
         }.onError {
             it.printOnDebug()
             errorLive.postValue(it.localizedMessage)
+            AppLog.put("无法打开文件\n${it.localizedMessage}", it)
         }
     }
 

+ 7 - 0
app/src/main/java/io/legado/app/ui/association/ImportBookSourceViewModel.kt

@@ -1,6 +1,7 @@
 package io.legado.app.ui.association
 
 import android.app.Application
+import android.net.Uri
 import androidx.lifecycle.MutableLiveData
 import com.jayway.jsonpath.JsonPath
 import io.legado.app.R
@@ -109,6 +110,12 @@ class ImportBookSourceViewModel(app: Application) : BaseViewModel(app) {
                 mText.isAbsUrl() -> {
                     importSourceUrl(mText)
                 }
+                mText.isUri() -> {
+                    val uri = Uri.parse(mText)
+                    uri.inputStream(context)?.let {
+                        allSources.addAll(BookSource.fromJsonArray(it).getOrThrow())
+                    }
+                }
                 else -> throw NoStackTraceException(context.getString(R.string.wrong_format))
             }
         }.onError {

+ 2 - 5
app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt

@@ -21,6 +21,7 @@ import io.legado.app.data.entities.BookSource
 import io.legado.app.databinding.ActivityBookSourceBinding
 import io.legado.app.databinding.DialogEditTextBinding
 import io.legado.app.help.DirectLinkUpload
+import io.legado.app.help.IntentData
 import io.legado.app.help.config.LocalConfig
 import io.legado.app.lib.dialogs.alert
 import io.legado.app.lib.theme.primaryColor
@@ -77,11 +78,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
     }
     private val importDoc = registerForActivityResult(HandleFileContract()) {
         it.uri?.let { uri ->
-            try {
-                showDialogFragment(ImportBookSourceDialog(uri.readText(this)))
-            } catch (e: Exception) {
-                toastOnUi("readTextError:${e.localizedMessage}")
-            }
+            showDialogFragment(ImportBookSourceDialog(uri.toString()))
         }
     }
     private val exportDir = registerForActivityResult(HandleFileContract()) {

+ 25 - 0
app/src/main/java/io/legado/app/utils/InputStreamExtensions.kt

@@ -0,0 +1,25 @@
+package io.legado.app.utils
+
+import java.io.InputStream
+import java.util.*
+
+fun InputStream?.isJson(): Boolean {
+    this ?: return false
+    this.use {
+        val byteArray = ByteArray(128)
+        it.read(byteArray)
+        val a = String(byteArray).trim()
+        it.skip(it.available() - 128L)
+        it.read(byteArray)
+        val b = String(byteArray).trim()
+        return (a + b).isJson()
+    }
+}
+
+fun InputStream?.contains(str: String): Boolean {
+    this ?: return false
+    this.use {
+        val scanner = Scanner(it)
+        return scanner.findWithinHorizon(str, 0) != null
+    }
+}

+ 5 - 0
app/src/main/java/io/legado/app/utils/StringExtensions.kt

@@ -24,6 +24,11 @@ fun String.parseToUri(): Uri {
     }
 }
 
+fun String?.isUri(): Boolean {
+    this ?: return false
+    return this.startsWith("file://", true) || isContentScheme()
+}
+
 fun String?.isAbsUrl() =
     this?.let {
         it.startsWith("http://", true) || it.startsWith("https://", true)

+ 22 - 0
app/src/main/java/io/legado/app/utils/UriExtensions.kt

@@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity
 import androidx.documentfile.provider.DocumentFile
 import androidx.fragment.app.Fragment
 import io.legado.app.R
+import io.legado.app.constant.AppLog
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.lib.permission.Permissions
 import io.legado.app.lib.permission.PermissionsCompat
@@ -153,4 +154,25 @@ fun Uri.writeBytes(
         return true
     }
     return false
+}
+
+fun Uri.inputStream(context: Context): InputStream? {
+    val uri = this
+    try {
+        if (isContentScheme()) {
+            val doc = DocumentFile.fromSingleUri(context, uri)
+            doc ?: throw NoStackTraceException("未获取到文件")
+            return context.contentResolver.openInputStream(uri)!!
+        } else {
+            RealPathUtil.getPath(context, uri)?.let { path ->
+                val file = File(path)
+                return FileInputStream(file)
+            }
+        }
+    } catch (e: Exception) {
+        e.printOnDebug()
+        context.toastOnUi("读取inputStream失败:${e.localizedMessage}")
+        AppLog.put("读取inputStream失败:${e.localizedMessage}", e)
+    }
+    return null
 }