Adds iMeta tags to GIF urls
This commit is contained in:
@@ -105,7 +105,7 @@ class ImageUploadTesting {
|
|||||||
assertEquals("${server.baseUrl}/$initialHash", result.url?.removeSuffix(".png"))
|
assertEquals("${server.baseUrl}/$initialHash", result.url?.removeSuffix(".png"))
|
||||||
|
|
||||||
val imageData: ByteArray =
|
val imageData: ByteArray =
|
||||||
ImageDownloader().waitAndGetImage(result.url!!, false)
|
ImageDownloader().waitAndGetImage(result.url!!, false)?.bytes
|
||||||
?: run {
|
?: run {
|
||||||
fail("${server.name}: Should not be null")
|
fail("${server.name}: Should not be null")
|
||||||
return
|
return
|
||||||
@@ -148,7 +148,7 @@ class ImageUploadTesting {
|
|||||||
Assert.assertTrue("${server.name}: Invalid result url", url.startsWith("http"))
|
Assert.assertTrue("${server.name}: Invalid result url", url.startsWith("http"))
|
||||||
|
|
||||||
val imageData: ByteArray =
|
val imageData: ByteArray =
|
||||||
ImageDownloader().waitAndGetImage(url, false)
|
ImageDownloader().waitAndGetImage(url, false)?.bytes
|
||||||
?: run {
|
?: run {
|
||||||
fail("${server.name}: Should not be null")
|
fail("${server.name}: Should not be null")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -55,10 +55,10 @@ class FileHeader(
|
|||||||
forceProxy: Boolean,
|
forceProxy: Boolean,
|
||||||
): Result<FileHeader> =
|
): Result<FileHeader> =
|
||||||
try {
|
try {
|
||||||
val imageData: ByteArray? = ImageDownloader().waitAndGetImage(fileUrl, forceProxy)
|
val imageData: ImageDownloader.Blob? = ImageDownloader().waitAndGetImage(fileUrl, forceProxy)
|
||||||
|
|
||||||
if (imageData != null) {
|
if (imageData != null) {
|
||||||
prepare(imageData, mimeType, dimPrecomputed)
|
prepare(imageData.bytes, mimeType ?: imageData.contentType, dimPrecomputed)
|
||||||
} else {
|
} else {
|
||||||
Result.failure(UnableToDownload(fileUrl))
|
Result.failure(UnableToDownload(fileUrl))
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-4
@@ -29,12 +29,17 @@ import java.net.HttpURLConnection
|
|||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
class ImageDownloader {
|
class ImageDownloader {
|
||||||
|
class Blob(
|
||||||
|
val bytes: ByteArray,
|
||||||
|
val contentType: String?,
|
||||||
|
)
|
||||||
|
|
||||||
suspend fun waitAndGetImage(
|
suspend fun waitAndGetImage(
|
||||||
imageUrl: String,
|
imageUrl: String,
|
||||||
forceProxy: Boolean,
|
forceProxy: Boolean,
|
||||||
): ByteArray? =
|
): Blob? =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
var imageData: ByteArray? = null
|
var imageData: Blob? = null
|
||||||
var tentatives = 0
|
var tentatives = 0
|
||||||
|
|
||||||
// Servers are usually not ready.. so tries to download it for 15 times/seconds.
|
// Servers are usually not ready.. so tries to download it for 15 times/seconds.
|
||||||
@@ -59,7 +64,7 @@ class ImageDownloader {
|
|||||||
private suspend fun tryGetTheImage(
|
private suspend fun tryGetTheImage(
|
||||||
imageUrl: String,
|
imageUrl: String,
|
||||||
forceProxy: Boolean,
|
forceProxy: Boolean,
|
||||||
): ByteArray? =
|
): Blob? =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
// TODO: Migrate to OkHttp
|
// TODO: Migrate to OkHttp
|
||||||
HttpURLConnection.setFollowRedirects(true)
|
HttpURLConnection.setFollowRedirects(true)
|
||||||
@@ -88,7 +93,10 @@ class ImageDownloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return@withContext if (responseCode in 200..300) {
|
return@withContext if (responseCode in 200..300) {
|
||||||
huc.inputStream.use { it.readBytes() }
|
Blob(
|
||||||
|
huc.inputStream.use { it.readBytes() },
|
||||||
|
huc.headerFields.get("Content-Type")?.firstOrNull(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -224,15 +224,15 @@ class UploadOrchestrator {
|
|||||||
|
|
||||||
updateState(0.6, UploadingState.Downloading)
|
updateState(0.6, UploadingState.Downloading)
|
||||||
|
|
||||||
val imageData: ByteArray? = ImageDownloader().waitAndGetImage(uploadResult.url, forceProxy(uploadResult.url))
|
val imageData: ImageDownloader.Blob? = ImageDownloader().waitAndGetImage(uploadResult.url, forceProxy(uploadResult.url))
|
||||||
|
|
||||||
if (imageData != null) {
|
if (imageData != null) {
|
||||||
updateState(0.8, UploadingState.Hashing)
|
updateState(0.8, UploadingState.Hashing)
|
||||||
|
|
||||||
val result =
|
val result =
|
||||||
FileHeader.prepare(
|
FileHeader.prepare(
|
||||||
imageData,
|
imageData.bytes,
|
||||||
uploadResult.type ?: localContentType,
|
uploadResult.type ?: localContentType ?: imageData.contentType,
|
||||||
uploadResult.dimension,
|
uploadResult.dimension,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.actions
|
package com.vitorpamplona.amethyst.ui.actions
|
||||||
|
|
||||||
|
import android.R.attr.mimeType
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.webkit.MimeTypeMap
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
@@ -43,6 +45,7 @@ import com.vitorpamplona.amethyst.model.Note
|
|||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.service.LocationState
|
import com.vitorpamplona.amethyst.service.LocationState
|
||||||
import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource
|
import com.vitorpamplona.amethyst.service.NostrSearchEventOrUserDataSource
|
||||||
|
import com.vitorpamplona.amethyst.service.uploads.FileHeader
|
||||||
import com.vitorpamplona.amethyst.service.uploads.MediaCompressor
|
import com.vitorpamplona.amethyst.service.uploads.MediaCompressor
|
||||||
import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator
|
import com.vitorpamplona.amethyst.service.uploads.MultiOrchestrator
|
||||||
import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator
|
import com.vitorpamplona.amethyst.service.uploads.UploadOrchestrator
|
||||||
@@ -92,6 +95,7 @@ import kotlinx.coroutines.flow.flowOn
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.Locale
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
|
||||||
@@ -1228,6 +1232,28 @@ open class NewPostViewModel : ViewModel() {
|
|||||||
val lastWordStart = it.end - lastWord.length
|
val lastWordStart = it.end - lastWord.length
|
||||||
val wordToInsert = item.url.url + " "
|
val wordToInsert = item.url.url + " "
|
||||||
|
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val fileExtension: String = MimeTypeMap.getFileExtensionFromUrl(item.url.url)
|
||||||
|
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension.lowercase(Locale.getDefault()))
|
||||||
|
|
||||||
|
val forceProxy = accountViewModel?.account?.shouldUseTorForImageDownload() ?: false
|
||||||
|
val imeta =
|
||||||
|
FileHeader.prepare(item.url.url, mimeType, null, forceProxy).getOrNull()?.let {
|
||||||
|
IMetaTagBuilder(item.url.url)
|
||||||
|
.apply {
|
||||||
|
hash(it.hash)
|
||||||
|
size(it.size)
|
||||||
|
it.mimeType?.let { mimeType(it) }
|
||||||
|
it.dim?.let { dims(it) }
|
||||||
|
it.blurHash?.let { blurhash(it.blurhash) }
|
||||||
|
}.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imeta != null) {
|
||||||
|
iMetaAttachments += imeta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message =
|
message =
|
||||||
TextFieldValue(
|
TextFieldValue(
|
||||||
message.text.replaceRange(lastWordStart, it.end, wordToInsert),
|
message.text.replaceRange(lastWordStart, it.end, wordToInsert),
|
||||||
|
|||||||
Reference in New Issue
Block a user