Fixing NostrFiles dev downloader

This commit is contained in:
Vitor Pamplona
2023-05-08 09:39:44 -04:00
parent d6d273e34c
commit ae268cc197
8 changed files with 87 additions and 45 deletions
@@ -4,6 +4,7 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.util.Log import android.util.Log
import com.vitorpamplona.amethyst.model.toHexKey import com.vitorpamplona.amethyst.model.toHexKey
import com.vitorpamplona.amethyst.ui.actions.ImageDownloader
import io.trbl.blurhash.BlurHash import io.trbl.blurhash.BlurHash
import java.net.URL import java.net.URL
import java.security.MessageDigest import java.security.MessageDigest
@@ -19,11 +20,15 @@ class FileHeader(
val description: String? = null val description: String? = null
) { ) {
companion object { companion object {
fun prepare(fileUrl: String, mimeType: String?, description: String?, onReady: (FileHeader) -> Unit, onError: () -> Unit) { suspend fun prepare(fileUrl: String, mimeType: String?, description: String?, onReady: (FileHeader) -> Unit, onError: () -> Unit) {
try { try {
val imageData = URL(fileUrl).readBytes() val imageData: ByteArray? = ImageDownloader().waitAndGetImage(fileUrl)
if (imageData != null)
prepare(imageData, fileUrl, mimeType, description, onReady, onError) prepare(imageData, fileUrl, mimeType, description, onReady, onError)
else {
onError()
}
} catch (e: Exception) { } catch (e: Exception) {
Log.e("ImageDownload", "Couldn't download image from server: ${e.message}") Log.e("ImageDownload", "Couldn't download image from server: ${e.message}")
onError() onError()
@@ -0,0 +1,47 @@
package com.vitorpamplona.amethyst.ui.actions
import kotlinx.coroutines.delay
import java.net.HttpURLConnection
import java.net.URL
class ImageDownloader {
suspend fun waitAndGetImage(imageUrl: String): ByteArray? {
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 {
HttpURLConnection.setFollowRedirects(true)
var url = URL(imageUrl)
var huc = url.openConnection() as HttpURLConnection
huc.instanceFollowRedirects = true
var responseCode = huc.responseCode
if (responseCode in 300..400) {
val newUrl: String = huc.getHeaderField("Location")
// open the new connnection again
url = URL(newUrl)
huc = url.openConnection() as HttpURLConnection
responseCode = huc.responseCode
}
if (responseCode in 200..300) {
huc.inputStream.use { it.readBytes() }
} else {
tentatives++
delay(1000)
null
}
} catch (e: Exception) {
tentatives++
delay(1000)
null
}
}
return imageData
}
}
@@ -38,17 +38,23 @@ object ImageUploader {
checkNotNull(imageInputStream) { checkNotNull(imageInputStream) {
"Can't open the image input stream" "Can't open the image input stream"
} }
val myServer = if (server == ServersAvailable.IMGUR) { val myServer = when (server) {
ServersAvailable.IMGUR, ServersAvailable.IMGUR_NIP_94 -> {
ImgurServer() ImgurServer()
} else if (server == ServersAvailable.NOSTRIMG) { }
ServersAvailable.NOSTRIMG, ServersAvailable.NOSTRIMG_NIP_94 -> {
NostrImgServer() NostrImgServer()
} else if (server == ServersAvailable.NOSTR_BUILD) { }
ServersAvailable.NOSTR_BUILD, ServersAvailable.NOSTR_BUILD_NIP_94 -> {
NostrBuildServer() NostrBuildServer()
} else if (server == ServersAvailable.NOSTRFILES_DEV) { }
ServersAvailable.NOSTRFILES_DEV, ServersAvailable.NOSTRFILES_DEV_NIP_94 -> {
NostrFilesDevServer() NostrFilesDevServer()
} else { }
else -> {
ImgurServer() ImgurServer()
} }
}
uploadImage(imageInputStream, length, contentType, myServer, onSuccess, onError) uploadImage(imageInputStream, length, contentType, myServer, onSuccess, onError)
} }
@@ -101,7 +107,7 @@ object ImageUploader {
try { try {
check(response.isSuccessful) check(response.isSuccessful)
response.body.use { body -> response.body.use { body ->
val url = server.parseUrlFromSucess(body.string()) val url = server.parseUrlFromSuccess(body.string())
checkNotNull(url) { checkNotNull(url) {
"There must be an uploaded image URL in the response" "There must be an uploaded image URL in the response"
} }
@@ -124,7 +130,7 @@ object ImageUploader {
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 parseUrlFromSuccess(body: String): String?
abstract fun inputParameterName(contentType: String?): String abstract fun inputParameterName(contentType: String?): String
open fun clientID(): String? = null open fun clientID(): String? = null
@@ -133,7 +139,7 @@ abstract class FileServer {
class NostrImgServer : FileServer() { class NostrImgServer : FileServer() {
override fun postUrl(contentType: String?) = "https://nostrimg.com/api/upload" override fun postUrl(contentType: String?) = "https://nostrimg.com/api/upload"
override fun parseUrlFromSucess(body: String): String? { override fun parseUrlFromSuccess(body: String): String? {
val tree = jacksonObjectMapper().readTree(body) val tree = jacksonObjectMapper().readTree(body)
val url = tree?.get("data")?.get("link")?.asText() val url = tree?.get("data")?.get("link")?.asText()
return url return url
@@ -152,7 +158,7 @@ class ImgurServer : FileServer() {
return if (category == "image") "https://api.imgur.com/3/image" else "https://api.imgur.com/3/upload" return if (category == "image") "https://api.imgur.com/3/image" else "https://api.imgur.com/3/upload"
} }
override fun parseUrlFromSucess(body: String): String? { override fun parseUrlFromSuccess(body: String): String? {
val tree = jacksonObjectMapper().readTree(body) val tree = jacksonObjectMapper().readTree(body)
val url = tree?.get("data")?.get("link")?.asText() val url = tree?.get("data")?.get("link")?.asText()
return url return url
@@ -167,7 +173,7 @@ class ImgurServer : FileServer() {
class NostrBuildServer : FileServer() { class NostrBuildServer : FileServer() {
override fun postUrl(contentType: String?) = "https://nostr.build/api/upload/android.php" override fun postUrl(contentType: String?) = "https://nostr.build/api/upload/android.php"
override fun parseUrlFromSucess(body: String): String? { override fun parseUrlFromSuccess(body: String): String? {
val url = jacksonObjectMapper().readTree(body) // return url.toString() val url = jacksonObjectMapper().readTree(body) // return url.toString()
return url.toString().replace("\"", "") return url.toString().replace("\"", "")
} }
@@ -181,10 +187,9 @@ class NostrBuildServer : FileServer() {
class NostrFilesDevServer : FileServer() { class NostrFilesDevServer : FileServer() {
override fun postUrl(contentType: String?) = "https://nostrfiles.dev/upload_image" override fun postUrl(contentType: String?) = "https://nostrfiles.dev/upload_image"
override fun parseUrlFromSucess(body: String): String? { override fun parseUrlFromSuccess(body: String): String? {
val tree = jacksonObjectMapper().readTree(body) val tree = jacksonObjectMapper().readTree(body)
val url = tree?.get("url")?.asText() return tree?.get("url")?.asText()
return url
} }
override fun inputParameterName(contentType: String?): String { override fun inputParameterName(contentType: String?): String {
@@ -14,8 +14,10 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.net.HttpURLConnection
import java.net.URL import java.net.URL
open class NewMediaModel : ViewModel() { open class NewMediaModel : ViewModel() {
var account: Account? = null var account: Account? = null
@@ -116,19 +118,7 @@ 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
var imageData: ByteArray? = null val imageData: ByteArray? = ImageDownloader().waitAndGetImage(imageUrl)
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" uploadingDescription.value = "Downloading"
uploadingPercentage.value = 0.60f uploadingPercentage.value = 0.60f
@@ -110,7 +110,10 @@ fun NewMediaView(uri: Uri, onClose: () -> Unit, postViewModel: NewMediaModel, ac
} }
fun isNIP94Server(selectedServer: ServersAvailable?): Boolean { fun isNIP94Server(selectedServer: ServersAvailable?): Boolean {
return selectedServer == ServersAvailable.NOSTRIMG_NIP_94 || selectedServer == ServersAvailable.IMGUR_NIP_94 || selectedServer == ServersAvailable.NOSTR_BUILD_NIP_94 || selectedServer == ServersAvailable.NOSTRFILES_DEV_NIP_94 return selectedServer == ServersAvailable.NOSTRIMG_NIP_94
|| selectedServer == ServersAvailable.IMGUR_NIP_94
|| selectedServer == ServersAvailable.NOSTR_BUILD_NIP_94
|| selectedServer == ServersAvailable.NOSTRFILES_DEV_NIP_94
} }
@Composable @Composable
@@ -614,11 +614,11 @@ fun ImageVideoDescription(
Triple(ServersAvailable.IMGUR, stringResource(id = R.string.upload_server_imgur), stringResource(id = R.string.upload_server_imgur_explainer)), Triple(ServersAvailable.IMGUR, stringResource(id = R.string.upload_server_imgur), stringResource(id = R.string.upload_server_imgur_explainer)),
Triple(ServersAvailable.NOSTRIMG, stringResource(id = R.string.upload_server_nostrimg), stringResource(id = R.string.upload_server_nostrimg_explainer)), Triple(ServersAvailable.NOSTRIMG, stringResource(id = R.string.upload_server_nostrimg), stringResource(id = R.string.upload_server_nostrimg_explainer)),
Triple(ServersAvailable.NOSTR_BUILD, stringResource(id = R.string.upload_server_nostrbuild), stringResource(id = R.string.upload_server_nostrbuild_explainer)), Triple(ServersAvailable.NOSTR_BUILD, stringResource(id = R.string.upload_server_nostrbuild), stringResource(id = R.string.upload_server_nostrbuild_explainer)),
// Triple(ServersAvailable.NOSTRFILES_DEV, stringResource(id = R.string.upload_server_nostrfilesdev), stringResource(id = R.string.upload_server_nostrfilesdev_explainer)), Triple(ServersAvailable.NOSTRFILES_DEV, stringResource(id = R.string.upload_server_nostrfilesdev), stringResource(id = R.string.upload_server_nostrfilesdev_explainer)),
Triple(ServersAvailable.IMGUR_NIP_94, stringResource(id = R.string.upload_server_imgur_nip94), stringResource(id = R.string.upload_server_imgur_nip94_explainer)), Triple(ServersAvailable.IMGUR_NIP_94, stringResource(id = R.string.upload_server_imgur_nip94), stringResource(id = R.string.upload_server_imgur_nip94_explainer)),
Triple(ServersAvailable.NOSTRIMG_NIP_94, stringResource(id = R.string.upload_server_nostrimg_nip94), stringResource(id = R.string.upload_server_nostrimg_nip94_explainer)), Triple(ServersAvailable.NOSTRIMG_NIP_94, stringResource(id = R.string.upload_server_nostrimg_nip94), stringResource(id = R.string.upload_server_nostrimg_nip94_explainer)),
Triple(ServersAvailable.NOSTR_BUILD_NIP_94, stringResource(id = R.string.upload_server_nostrbuild_nip94), stringResource(id = R.string.upload_server_nostrbuild_nip94_explainer)), Triple(ServersAvailable.NOSTR_BUILD_NIP_94, stringResource(id = R.string.upload_server_nostrbuild_nip94), stringResource(id = R.string.upload_server_nostrbuild_nip94_explainer)),
// Triple(ServersAvailable.NOSTRFILES_DEV_NIP_94, stringResource(id = R.string.upload_server_nostrfilesdev_nip94), stringResource(id = R.string.upload_server_nostrfilesdev_nip94_explainer)), Triple(ServersAvailable.NOSTRFILES_DEV_NIP_94, stringResource(id = R.string.upload_server_nostrfilesdev_nip94), stringResource(id = R.string.upload_server_nostrfilesdev_nip94_explainer)),
Triple(ServersAvailable.NIP95, stringResource(id = R.string.upload_server_relays_nip95), stringResource(id = R.string.upload_server_relays_nip95_explainer)) Triple(ServersAvailable.NIP95, stringResource(id = R.string.upload_server_relays_nip95), stringResource(id = R.string.upload_server_relays_nip95_explainer))
) )
@@ -287,13 +287,6 @@ open class NewPostViewModel : ViewModel() {
fun createNIP94Record(imageUrl: String, mimeType: String?, description: String) { fun createNIP94Record(imageUrl: String, mimeType: String?, description: String) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
// 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) {
delay(2000)
} else {
delay(5000)
}
FileHeader.prepare( FileHeader.prepare(
imageUrl, imageUrl,
mimeType, mimeType,
@@ -259,7 +259,6 @@ private fun UrlImageView(
content: ZoomableUrlImage, content: ZoomableUrlImage,
mainImageModifier: Modifier mainImageModifier: Modifier
) { ) {
println("UrlImageView")
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val context = LocalContext.current val context = LocalContext.current