Massive refactoring of Quartz to:
- Define each tag in their own class. - Allow extension functions to additional responsibilities to other classes - Migrate from hardcoded tag filters in events to the Tag's parser and assemble functions. - Migrate hardcoded event.create to builders that use extension functions - Restructures threading infrastructure for NIP-10 - Decouple the event signing from the Event building functions via event templates - Create classes to represent Tags and TagArrays and use extension functions to add domain-related methods to the tag array of each nip. - Uses external functions on event template builders to better point to which functions and which tags can be used in which event kinds. - Separates Event kinds in packages inside each nip. - Improves support for NIP-89 - Correctly establishes which imeta params can be used in each nip (video, picture, files) - Decouples the iMeta builder from any nip. - Fixes mute list word and user removal when inserted from a different client. - Migrates the Account class to avoiding having to build each Event inside of it
This commit is contained in:
+10
-10
@@ -21,13 +21,13 @@
|
||||
package com.vitorpamplona.amethyst.commons.richtext
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.Dimension
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag
|
||||
import java.io.File
|
||||
|
||||
@Immutable
|
||||
abstract class BaseMediaContent(
|
||||
val description: String? = null,
|
||||
val dim: Dimension? = null,
|
||||
val dim: DimensionTag? = null,
|
||||
val blurhash: String? = null,
|
||||
)
|
||||
|
||||
@@ -36,7 +36,7 @@ abstract class MediaUrlContent(
|
||||
val url: String,
|
||||
description: String? = null,
|
||||
val hash: String? = null,
|
||||
dim: Dimension? = null,
|
||||
dim: DimensionTag? = null,
|
||||
blurhash: String? = null,
|
||||
val uri: String? = null,
|
||||
val mimeType: String? = null,
|
||||
@@ -48,7 +48,7 @@ open class MediaUrlImage(
|
||||
description: String? = null,
|
||||
hash: String? = null,
|
||||
blurhash: String? = null,
|
||||
dim: Dimension? = null,
|
||||
dim: DimensionTag? = null,
|
||||
uri: String? = null,
|
||||
val contentWarning: String? = null,
|
||||
mimeType: String? = null,
|
||||
@@ -59,7 +59,7 @@ class EncryptedMediaUrlImage(
|
||||
description: String? = null,
|
||||
hash: String? = null,
|
||||
blurhash: String? = null,
|
||||
dim: Dimension? = null,
|
||||
dim: DimensionTag? = null,
|
||||
uri: String? = null,
|
||||
contentWarning: String? = null,
|
||||
mimeType: String? = null,
|
||||
@@ -73,7 +73,7 @@ open class MediaUrlVideo(
|
||||
url: String,
|
||||
description: String? = null,
|
||||
hash: String? = null,
|
||||
dim: Dimension? = null,
|
||||
dim: DimensionTag? = null,
|
||||
uri: String? = null,
|
||||
val artworkUri: String? = null,
|
||||
val authorName: String? = null,
|
||||
@@ -87,7 +87,7 @@ class EncryptedMediaUrlVideo(
|
||||
url: String,
|
||||
description: String? = null,
|
||||
hash: String? = null,
|
||||
dim: Dimension? = null,
|
||||
dim: DimensionTag? = null,
|
||||
uri: String? = null,
|
||||
artworkUri: String? = null,
|
||||
authorName: String? = null,
|
||||
@@ -105,7 +105,7 @@ abstract class MediaPreloadedContent(
|
||||
description: String? = null,
|
||||
val mimeType: String? = null,
|
||||
val isVerified: Boolean? = null,
|
||||
dim: Dimension? = null,
|
||||
dim: DimensionTag? = null,
|
||||
blurhash: String? = null,
|
||||
val uri: String,
|
||||
val id: String? = null,
|
||||
@@ -118,7 +118,7 @@ class MediaLocalImage(
|
||||
localFile: File?,
|
||||
mimeType: String? = null,
|
||||
description: String? = null,
|
||||
dim: Dimension? = null,
|
||||
dim: DimensionTag? = null,
|
||||
blurhash: String? = null,
|
||||
isVerified: Boolean? = null,
|
||||
uri: String,
|
||||
@@ -129,7 +129,7 @@ class MediaLocalVideo(
|
||||
localFile: File?,
|
||||
mimeType: String? = null,
|
||||
description: String? = null,
|
||||
dim: Dimension? = null,
|
||||
dim: DimensionTag? = null,
|
||||
blurhash: String? = null,
|
||||
isVerified: Boolean? = null,
|
||||
uri: String,
|
||||
|
||||
+25
-19
@@ -27,10 +27,14 @@ import com.linkedin.urls.detection.UrlDetectorOptions
|
||||
import com.vitorpamplona.quartz.experimental.inlineMetadata.Nip54InlineMetadata
|
||||
import com.vitorpamplona.quartz.nip02FollowList.ImmutableListOfLists
|
||||
import com.vitorpamplona.quartz.nip30CustomEmoji.CustomEmoji
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.CONTENT_WARNING
|
||||
import com.vitorpamplona.quartz.nip92IMeta.Nip92MediaAttachments
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.Dimension
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.FileHeaderEvent
|
||||
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||
import com.vitorpamplona.quartz.nip36SensitiveContent.ContentWarningTag
|
||||
import com.vitorpamplona.quartz.nip92IMeta.IMetaTag
|
||||
import com.vitorpamplona.quartz.nip92IMeta.imetasByUrl
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.BlurhashTag
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.DimensionTag
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.HashTag
|
||||
import com.vitorpamplona.quartz.nip94FileMetadata.tags.MimeTypeTag
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
@@ -46,14 +50,15 @@ import kotlin.coroutines.cancellation.CancellationException
|
||||
class RichTextParser {
|
||||
fun createMediaContent(
|
||||
fullUrl: String,
|
||||
eventTags: ImmutableListOfLists<String>,
|
||||
eventTags: Map<String, IMetaTag>,
|
||||
description: String?,
|
||||
callbackUri: String? = null,
|
||||
): MediaUrlContent? {
|
||||
val frags = Nip54InlineMetadata().parse(fullUrl)
|
||||
val tags = Nip92MediaAttachments.parse(fullUrl, eventTags.lists)
|
||||
|
||||
val contentType = frags[FileHeaderEvent.MIME_TYPE] ?: tags[FileHeaderEvent.MIME_TYPE]
|
||||
val tags = eventTags.get(fullUrl)?.properties ?: emptyMap()
|
||||
|
||||
val contentType = frags[MimeTypeTag.TAG_NAME] ?: tags[MimeTypeTag.TAG_NAME]?.firstOrNull()
|
||||
|
||||
val isImage: Boolean
|
||||
val isVideo: Boolean
|
||||
@@ -73,22 +78,22 @@ class RichTextParser {
|
||||
return if (isImage) {
|
||||
MediaUrlImage(
|
||||
url = fullUrl,
|
||||
description = description ?: frags[FileHeaderEvent.ALT] ?: tags[FileHeaderEvent.ALT],
|
||||
hash = frags[FileHeaderEvent.HASH] ?: tags[FileHeaderEvent.HASH],
|
||||
blurhash = frags[FileHeaderEvent.BLUR_HASH] ?: tags[FileHeaderEvent.BLUR_HASH],
|
||||
dim = frags[FileHeaderEvent.DIMENSION]?.let { Dimension.parse(it) } ?: tags[FileHeaderEvent.DIMENSION]?.let { Dimension.parse(it) },
|
||||
contentWarning = frags[CONTENT_WARNING] ?: tags[CONTENT_WARNING],
|
||||
description = description ?: frags[AltTag.TAG_NAME] ?: tags[AltTag.TAG_NAME]?.firstOrNull(),
|
||||
hash = frags[HashTag.TAG_NAME] ?: tags[HashTag.TAG_NAME]?.firstOrNull(),
|
||||
blurhash = frags[BlurhashTag.TAG_NAME] ?: tags[BlurhashTag.TAG_NAME]?.firstOrNull(),
|
||||
dim = frags[DimensionTag.TAG_NAME]?.let { DimensionTag.parse(it) } ?: tags[DimensionTag.TAG_NAME]?.firstOrNull()?.let { DimensionTag.parse(it) },
|
||||
contentWarning = frags[ContentWarningTag.TAG_NAME] ?: tags[ContentWarningTag.TAG_NAME]?.firstOrNull(),
|
||||
uri = callbackUri,
|
||||
mimeType = contentType,
|
||||
)
|
||||
} else if (isVideo) {
|
||||
MediaUrlVideo(
|
||||
url = fullUrl,
|
||||
description = description ?: frags[FileHeaderEvent.ALT] ?: tags[FileHeaderEvent.ALT],
|
||||
hash = frags[FileHeaderEvent.HASH] ?: tags[FileHeaderEvent.HASH],
|
||||
blurhash = frags[FileHeaderEvent.BLUR_HASH] ?: tags[FileHeaderEvent.BLUR_HASH],
|
||||
dim = frags[FileHeaderEvent.DIMENSION]?.let { Dimension.parse(it) } ?: tags[FileHeaderEvent.DIMENSION]?.let { Dimension.parse(it) },
|
||||
contentWarning = frags[CONTENT_WARNING] ?: tags[CONTENT_WARNING],
|
||||
description = description ?: frags[AltTag.TAG_NAME] ?: tags[AltTag.TAG_NAME]?.firstOrNull(),
|
||||
hash = frags[HashTag.TAG_NAME] ?: tags[HashTag.TAG_NAME]?.firstOrNull(),
|
||||
blurhash = frags[BlurhashTag.TAG_NAME] ?: tags[BlurhashTag.TAG_NAME]?.firstOrNull(),
|
||||
dim = frags[DimensionTag.TAG_NAME]?.let { DimensionTag.parse(it) } ?: tags[DimensionTag.TAG_NAME]?.firstOrNull()?.let { DimensionTag.parse(it) },
|
||||
contentWarning = frags[ContentWarningTag.TAG_NAME] ?: tags[ContentWarningTag.TAG_NAME]?.firstOrNull(),
|
||||
uri = callbackUri,
|
||||
mimeType = contentType,
|
||||
)
|
||||
@@ -131,10 +136,11 @@ class RichTextParser {
|
||||
tags: ImmutableListOfLists<String>,
|
||||
callbackUri: String?,
|
||||
): RichTextViewerState {
|
||||
val imetas = tags.lists.imetasByUrl()
|
||||
val urlSet = parseValidUrls(content)
|
||||
|
||||
val imagesForPager =
|
||||
urlSet.mapNotNull { fullUrl -> createMediaContent(fullUrl, tags, content, callbackUri) }.associateBy { it.url }
|
||||
urlSet.mapNotNull { fullUrl -> createMediaContent(fullUrl, imetas, content, callbackUri) }.associateBy { it.url }
|
||||
|
||||
val emojiMap = CustomEmoji.createEmojiMap(tags)
|
||||
|
||||
@@ -145,7 +151,7 @@ class RichTextParser {
|
||||
val imagesForPagerWithBase64 =
|
||||
imagesForPager +
|
||||
base64Images
|
||||
.mapNotNull { createMediaContent(it.segmentText, tags, content, callbackUri) }
|
||||
.mapNotNull { createMediaContent(it.segmentText, emptyMap(), content, callbackUri) }
|
||||
.associateBy { it.url }
|
||||
|
||||
return RichTextViewerState(
|
||||
|
||||
Reference in New Issue
Block a user