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