diff --git a/app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt b/app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt index c8803f82d..bdcbca26d 100644 --- a/app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt +++ b/app/src/androidTest/java/com/vitorpamplona/amethyst/ImageUploadTesting.kt @@ -9,7 +9,6 @@ import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.fail import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import java.util.Base64 @@ -21,12 +20,12 @@ class ImageUploadTesting { @Test() fun testImgurUpload() = runBlocking { - val inputStream = Base64.getDecoder().decode(image).inputStream() - - println("Uploading") + val bytes = Base64.getDecoder().decode(image) + val inputStream = bytes.inputStream() ImageUploader.uploadImage( inputStream, + bytes.size.toLong(), "image/gif", ImgurServer(), onSuccess = { url, contentType -> @@ -43,14 +42,13 @@ class ImageUploadTesting { } @Test() - @Ignore fun testNostrBuildUpload() = runBlocking { - val inputStream = Base64.getDecoder().decode(image).inputStream() - - println("Uploading") + val bytes = Base64.getDecoder().decode(image) + val inputStream = bytes.inputStream() ImageUploader.uploadImage( inputStream, + bytes.size.toLong(), "image/gif", NostrBuildServer(), onSuccess = { url, contentType -> @@ -68,12 +66,12 @@ class ImageUploadTesting { @Test() fun testNostrImgUpload() = runBlocking { - val inputStream = Base64.getDecoder().decode(image).inputStream() - - println("Uploading") + val bytes = Base64.getDecoder().decode(image) + val inputStream = bytes.inputStream() ImageUploader.uploadImage( inputStream, + bytes.size.toLong(), "image/gif", NostrImgServer(), onSuccess = { url, contentType -> diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt index 766056a87..10de05922 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt @@ -10,7 +10,6 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.BuildConfig import okhttp3.* import okhttp3.MediaType.Companion.toMediaType -import okhttp3.RequestBody.Companion.asRequestBody import okio.BufferedSink import okio.source import java.io.File @@ -27,13 +26,19 @@ object ImageUploader { fun uploadImage( uri: Uri, server: ServersAvailable, - context: Context, contentResolver: ContentResolver, onSuccess: (String, String?) -> Unit, onError: (Throwable) -> Unit ) { val contentType = contentResolver.getType(uri) val imageInputStream = contentResolver.openInputStream(uri) + + val length = contentResolver.query(uri, null, null, null, null)?.use { + it.moveToFirst() + val sizeIndex = it.getColumnIndex(OpenableColumns.SIZE) + it.getLong(sizeIndex) + } ?: 0 + checkNotNull(imageInputStream) { "Can't open the image input stream" } @@ -47,23 +52,17 @@ object ImageUploader { ImgurServer() } - val file = getRealPathFromURI(uri, context)?.let { File(it) } // create path from uri - if (file != null) { - uploadImage(file, imageInputStream, contentType, myServer, server, onSuccess, onError) - } + uploadImage(imageInputStream, length, contentType, myServer, onSuccess, onError) } fun uploadImage( - file: File, inputStream: InputStream, + length: Long, contentType: String?, server: FileServer, - serverType: ServersAvailable, onSuccess: (String, String?) -> Unit, onError: (Throwable) -> Unit ) { - val category = contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image" - val fileName = randomChars() val extension = contentType?.let { MimeTypeMap.getSingleton().getExtensionFromMimeType(it) } ?: "" @@ -71,35 +70,23 @@ object ImageUploader { val requestBody: RequestBody val requestBuilder = Request.Builder() - if (serverType == ServersAvailable.NOSTR_BUILD) { - requestBuilder.addHeader("Content-Type", "multipart/form-data") - requestBody = MultipartBody.Builder() - .setType(MultipartBody.FORM) - .addFormDataPart( - "fileToUpload", - "$fileName.$extension", - file.asRequestBody(contentType?.toMediaType()) + requestBody = MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart( + server.inputParameterName(contentType), + "$fileName.$extension", - ) - .build() - } else { - requestBody = MultipartBody.Builder() - .setType(MultipartBody.FORM) - .addFormDataPart( - category, - "$fileName.$extension", + object : RequestBody() { + override fun contentType() = contentType?.toMediaType() - object : RequestBody() { - override fun contentType(): MediaType? = - contentType?.toMediaType() + override fun contentLength() = length - override fun writeTo(sink: BufferedSink) { - inputStream.source().use(sink::writeAll) - } + override fun writeTo(sink: BufferedSink) { + inputStream.source().use(sink::writeAll) } - ) - .build() - } + } + ) + .build() server.clientID()?.let { requestBuilder.addHeader("Authorization", it) @@ -172,6 +159,7 @@ fun getRealPathFromURI(uri: Uri, context: Context): String? { abstract class FileServer { abstract fun postUrl(contentType: String?): String abstract fun parseUrlFromSucess(body: String): String? + abstract fun inputParameterName(contentType: String?): String open fun clientID(): String? = null } @@ -185,6 +173,10 @@ class NostrImgServer : FileServer() { return url } + override fun inputParameterName(contentType: String?): String { + return contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image" + } + override fun clientID() = null } @@ -200,6 +192,10 @@ class ImgurServer : FileServer() { return url } + override fun inputParameterName(contentType: String?): String { + return contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image" + } + override fun clientID() = "Client-ID e6aea87296f3f96" } @@ -210,5 +206,9 @@ class NostrBuildServer : FileServer() { return url.toString().replace("\"", "") } + override fun inputParameterName(contentType: String?): String { + return "fileToUpload" + } + override fun clientID() = null } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt index ac812b2c2..d15fa0c8a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewMediaModel.kt @@ -77,7 +77,6 @@ open class NewMediaModel : ViewModel() { ImageUploader.uploadImage( uri = uri, server = serverToUse, - context = context, contentResolver = contentResolver, onSuccess = { imageUrl, mimeType -> createNIP94Record(imageUrl, mimeType, description) @@ -115,18 +114,24 @@ open class NewMediaModel : ViewModel() { uploadingDescription.value = "Server Processing" // Images don't seem to be ready immediately after upload - if (mimeType?.startsWith("image/") == true) { - delay(2000) - } else { - delay(15000) + var imageData: ByteArray? = null + var tentatives = 0 + + // Servers are usually not ready.. so tries to download it for 15 times/seconds. + while (imageData == null && tentatives < 15) { + imageData = try { + URL(imageUrl).readBytes() + } catch (e: Exception) { + tentatives++ + delay(1000) + null + } } uploadingDescription.value = "Downloading" uploadingPercentage.value = 0.60f - try { - val imageData = URL(imageUrl).readBytes() - + if (imageData != null) { uploadingPercentage.value = 0.80f uploadingDescription.value = "Hashing" @@ -154,8 +159,8 @@ open class NewMediaModel : ViewModel() { } } ) - } catch (e: Exception) { - Log.e("ImageDownload", "Couldn't download image from server: ${e.message}") + } else { + Log.e("ImageDownload", "Couldn't download image from server") cancel() uploadingPercentage.value = 0.00f uploadingDescription.value = null diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index 42590becc..488a9ce1a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -145,7 +145,6 @@ open class NewPostViewModel : ViewModel() { ImageUploader.uploadImage( uri = it, server = server, - context = context, contentResolver = contentResolver, onSuccess = { imageUrl, mimeType -> if (server == ServersAvailable.IMGUR_NIP_94 || server == ServersAvailable.NOSTRIMG_NIP_94 || server == ServersAvailable.NOSTR_BUILD_NIP_94) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt index 80abdf2cf..269f22871 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt @@ -171,7 +171,6 @@ class NewUserMetadataViewModel : ViewModel() { ImageUploader.uploadImage( uri = it, server = account.defaultFileServer, - context = context, contentResolver = context.contentResolver, onSuccess = { imageUrl, mimeType -> onUploading(false)