|
|
@ -1,8 +1,9 @@ |
|
|
|
package io.legado.app.api.controller |
|
|
|
package io.legado.app.api.controller |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import android.net.Uri |
|
|
|
import android.util.Base64 |
|
|
|
import android.util.Base64 |
|
|
|
import androidx.core.graphics.drawable.toBitmap |
|
|
|
import androidx.core.graphics.drawable.toBitmap |
|
|
|
import io.legado.app.R |
|
|
|
import androidx.documentfile.provider.DocumentFile |
|
|
|
import io.legado.app.api.ReturnData |
|
|
|
import io.legado.app.api.ReturnData |
|
|
|
import io.legado.app.constant.PreferKey |
|
|
|
import io.legado.app.constant.PreferKey |
|
|
|
import io.legado.app.data.appDb |
|
|
|
import io.legado.app.data.appDb |
|
|
@ -22,7 +23,8 @@ import io.legado.app.model.webBook.WebBook |
|
|
|
import io.legado.app.utils.* |
|
|
|
import io.legado.app.utils.* |
|
|
|
import kotlinx.coroutines.runBlocking |
|
|
|
import kotlinx.coroutines.runBlocking |
|
|
|
import splitties.init.appCtx |
|
|
|
import splitties.init.appCtx |
|
|
|
import timber.log.Timber |
|
|
|
import java.io.File |
|
|
|
|
|
|
|
import java.io.FileOutputStream |
|
|
|
|
|
|
|
|
|
|
|
object BookController { |
|
|
|
object BookController { |
|
|
|
|
|
|
|
|
|
|
@ -202,36 +204,55 @@ object BookController { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
fun addLocalBook(parameters: Map<String, List<String>>): ReturnData { |
|
|
|
fun addLocalBook(parameters: Map<String, List<String>>): ReturnData { |
|
|
|
val returnData = ReturnData() |
|
|
|
val returnData = ReturnData() |
|
|
|
try { |
|
|
|
val fileName = parameters["fileName"]?.firstOrNull() |
|
|
|
val fileName = parameters["fileName"]?.firstOrNull() |
|
|
|
?: return returnData.setErrorMsg("fileName 不能为空") |
|
|
|
?: return returnData.setErrorMsg("fileName 不能为空") |
|
|
|
val fileData = parameters["fileData"]?.firstOrNull() |
|
|
|
val fileData = parameters["fileData"]?.firstOrNull() |
|
|
|
?: return returnData.setErrorMsg("fileData 不能为空") |
|
|
|
?: return returnData.setErrorMsg("fileData 不能为空") |
|
|
|
kotlin.runCatching { |
|
|
|
if (AppConfig.defaultBookTreeUri == null) return returnData.setErrorMsg("没有设置书籍保存位置!") |
|
|
|
val defaultBookTreeUri = AppConfig.defaultBookTreeUri |
|
|
|
val bookFolder = FileUtils.createFolderIfNotExist(AppConfig.defaultBookTreeUri!!) |
|
|
|
if (defaultBookTreeUri.isNullOrBlank()) return returnData.setErrorMsg("没有设置书籍保存位置!") |
|
|
|
val file = FileUtils.createFileIfNotExist(bookFolder, fileName) |
|
|
|
val treeUri = Uri.parse(defaultBookTreeUri) |
|
|
|
val fileBytes = Base64.decode(fileData.substringAfter("base64,"), Base64.DEFAULT) |
|
|
|
val fileBytes = |
|
|
|
file.writeBytes(fileBytes) |
|
|
|
Base64.decode(fileData.substringAfter("base64,"), Base64.DEFAULT) |
|
|
|
|
|
|
|
val uri = if (treeUri.isContentScheme()) { |
|
|
|
|
|
|
|
val treeDoc = DocumentFile.fromTreeUri(appCtx, treeUri) |
|
|
|
|
|
|
|
var doc = treeDoc!!.findFile(fileName) |
|
|
|
|
|
|
|
if (doc == null) { |
|
|
|
|
|
|
|
doc = treeDoc.createFile(FileUtils.getMimeType(fileName), fileName) |
|
|
|
|
|
|
|
?: throw SecurityException("Permission Denial") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
appCtx.contentResolver.openOutputStream(doc.uri)!!.use { oStream -> |
|
|
|
|
|
|
|
oStream.write(fileBytes) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
doc.uri |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
val treeFile = File(treeUri.path!!) |
|
|
|
|
|
|
|
val file = treeFile.getFile(fileName) |
|
|
|
|
|
|
|
FileOutputStream(file).use { oStream -> |
|
|
|
|
|
|
|
oStream.write(fileBytes) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Uri.fromFile(file) |
|
|
|
|
|
|
|
} |
|
|
|
val nameAuthor = LocalBook.analyzeNameAuthor(fileName) |
|
|
|
val nameAuthor = LocalBook.analyzeNameAuthor(fileName) |
|
|
|
val book = Book( |
|
|
|
val book = Book( |
|
|
|
bookUrl = file.absolutePath, |
|
|
|
bookUrl = uri.toString(), |
|
|
|
name = nameAuthor.first, |
|
|
|
name = nameAuthor.first, |
|
|
|
author = nameAuthor.second, |
|
|
|
author = nameAuthor.second, |
|
|
|
originName = fileName, |
|
|
|
originName = fileName, |
|
|
|
coverUrl = FileUtils.getPath( |
|
|
|
coverUrl = FileUtils.getPath( |
|
|
|
appCtx.externalFiles, |
|
|
|
appCtx.externalFiles, |
|
|
|
"covers", |
|
|
|
"covers", |
|
|
|
"${MD5Utils.md5Encode16(file.absolutePath)}.jpg" |
|
|
|
"${MD5Utils.md5Encode16(uri.toString())}.jpg" |
|
|
|
) |
|
|
|
) |
|
|
|
) |
|
|
|
) |
|
|
|
if (book.isEpub()) EpubFile.upBookInfo(book) |
|
|
|
if (book.isEpub()) EpubFile.upBookInfo(book) |
|
|
|
if (book.isUmd()) UmdFile.upBookInfo(book) |
|
|
|
if (book.isUmd()) UmdFile.upBookInfo(book) |
|
|
|
appDb.bookDao.insert(book) |
|
|
|
appDb.bookDao.insert(book) |
|
|
|
} catch (e: Exception) { |
|
|
|
}.onFailure { |
|
|
|
Timber.e(e) |
|
|
|
return when (it) { |
|
|
|
return returnData.setErrorMsg( |
|
|
|
is SecurityException -> returnData.setErrorMsg("需重新设置书籍保存位置!") |
|
|
|
e.localizedMessage ?: appCtx.getString(R.string.unknown_error) |
|
|
|
else -> returnData.setErrorMsg("保存书籍错误\n${it.localizedMessage}") |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return returnData.setData(true) |
|
|
|
return returnData.setData(true) |
|
|
|
} |
|
|
|
} |
|
|
|