feat: multiple media chat export

- optimize message exporter download
- optimize zip download/extract
This commit is contained in:
rhunk
2023-09-16 11:56:41 +02:00
parent 5a47e04093
commit 9cb9bd7a26
10 changed files with 289 additions and 323 deletions

View File

@@ -23,17 +23,14 @@ import me.rhunk.snapenhance.core.download.data.DownloadMetadata
import me.rhunk.snapenhance.core.download.data.DownloadRequest
import me.rhunk.snapenhance.core.download.data.DownloadStage
import me.rhunk.snapenhance.core.download.data.InputMedia
import me.rhunk.snapenhance.core.download.data.MediaEncryptionKeyPair
import me.rhunk.snapenhance.core.download.data.SplitMediaAssetType
import me.rhunk.snapenhance.core.util.download.RemoteMediaResolver
import me.rhunk.snapenhance.core.util.snap.MediaDownloaderHelper
import java.io.File
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL
import java.util.zip.ZipInputStream
import javax.crypto.Cipher
import javax.crypto.CipherInputStream
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
@@ -110,14 +107,6 @@ class DownloadProcessor (
return files
}
private fun decryptInputStream(inputStream: InputStream, encryption: MediaEncryptionKeyPair): InputStream {
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
val key = Base64.UrlSafe.decode(encryption.key)
val iv = Base64.UrlSafe.decode(encryption.iv)
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv))
return CipherInputStream(inputStream, cipher)
}
@SuppressLint("UnspecifiedRegisterReceiverFlag")
private suspend fun saveMediaToGallery(inputFile: File, downloadObject: DownloadObject) {
if (coroutineContext.job.isCancelled) return
@@ -202,24 +191,16 @@ class DownloadProcessor (
downloadRequest.inputMedias.forEach { inputMedia ->
fun handleInputStream(inputStream: InputStream) {
createMediaTempFile().apply {
if (inputMedia.encryption != null) {
decryptInputStream(inputStream,
inputMedia.encryption!!
).use { decryptedInputStream ->
decryptedInputStream.copyTo(outputStream())
}
} else {
inputStream.copyTo(outputStream())
}
(inputMedia.encryption?.decryptInputStream(inputStream) ?: inputStream).copyTo(outputStream())
}.also { downloadedMedias[inputMedia] = it }
}
launch {
when (inputMedia.type) {
DownloadMediaType.PROTO_MEDIA -> {
RemoteMediaResolver.downloadBoltMedia(Base64.UrlSafe.decode(inputMedia.content))?.let { inputStream ->
handleInputStream(inputStream)
}
RemoteMediaResolver.downloadBoltMedia(Base64.UrlSafe.decode(inputMedia.content), decryptionCallback = { it }, resultCallback = {
handleInputStream(it)
})
}
DownloadMediaType.DIRECT_MEDIA -> {
val decoded = Base64.UrlSafe.decode(inputMedia.content)
@@ -359,20 +340,26 @@ class DownloadProcessor (
var shouldMergeOverlay = downloadRequest.shouldMergeOverlay
//if there is a zip file, extract it and replace the downloaded media with the extracted ones
downloadedMedias.values.find { it.fileType == FileType.ZIP }?.let { entry ->
val extractedMedias = extractZip(entry.file.inputStream()).map {
InputMedia(
type = DownloadMediaType.LOCAL_MEDIA,
content = it.absolutePath
) to DownloadedFile(it, FileType.fromFile(it))
downloadedMedias.values.find { it.fileType == FileType.ZIP }?.let { zipFile ->
val oldDownloadedMedias = downloadedMedias.toMap()
downloadedMedias.clear()
MediaDownloaderHelper.getSplitElements(zipFile.file.inputStream()) { type, inputStream ->
createMediaTempFile().apply {
inputStream.copyTo(outputStream())
}.also {
downloadedMedias[InputMedia(
type = DownloadMediaType.LOCAL_MEDIA,
content = it.absolutePath,
isOverlay = type == SplitMediaAssetType.OVERLAY
)] = DownloadedFile(it, FileType.fromFile(it))
}
}
downloadedMedias.values.removeIf {
it.file.delete()
true
oldDownloadedMedias.forEach { (_, value) ->
value.file.delete()
}
downloadedMedias.putAll(extractedMedias)
shouldMergeOverlay = true
}