Added VideoNormalEvent (21) and VideoShortEvent (22)

Updated Account to post events as new 21 / 22 kinds.
Keep showing old event kinds for backwards compatibility
This commit is contained in:
David Kaspar
2025-08-20 11:16:02 +01:00
parent 667c15b3a1
commit 1bbc67fed7
9 changed files with 207 additions and 8 deletions

View File

@@ -184,9 +184,9 @@ import com.vitorpamplona.quartz.nip65RelayList.tags.AdvertisedRelayInfo
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
import com.vitorpamplona.quartz.nip68Picture.PictureMeta
import com.vitorpamplona.quartz.nip68Picture.pictureIMeta
import com.vitorpamplona.quartz.nip71Video.VideoHorizontalEvent
import com.vitorpamplona.quartz.nip71Video.VideoMeta
import com.vitorpamplona.quartz.nip71Video.VideoVerticalEvent
import com.vitorpamplona.quartz.nip71Video.VideoNormalEvent
import com.vitorpamplona.quartz.nip71Video.VideoShortEvent
import com.vitorpamplona.quartz.nip90Dvms.NIP90ContentDiscoveryRequestEvent
import com.vitorpamplona.quartz.nip92IMeta.IMetaTag
import com.vitorpamplona.quartz.nip92IMeta.imetas
@@ -213,8 +213,6 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import java.math.BigDecimal
import java.util.Locale
import kotlin.collections.forEach
import kotlin.collections.ifEmpty
@OptIn(DelicateCoroutinesApi::class)
@Stable
@@ -1070,11 +1068,11 @@ class Account(
)
if (headerInfo.dim.height > headerInfo.dim.width) {
VideoVerticalEvent.build(videoMeta, alt ?: "") {
VideoShortEvent.build(videoMeta, alt ?: "") {
contentWarningReason?.let { contentWarning(contentWarningReason) }
}
} else {
VideoHorizontalEvent.build(videoMeta, alt ?: "") {
VideoNormalEvent.build(videoMeta, alt ?: "") {
contentWarningReason?.let { contentWarning(contentWarningReason) }
}
}

View File

@@ -161,6 +161,8 @@ import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
import com.vitorpamplona.quartz.nip71Video.VideoHorizontalEvent
import com.vitorpamplona.quartz.nip71Video.VideoNormalEvent
import com.vitorpamplona.quartz.nip71Video.VideoShortEvent
import com.vitorpamplona.quartz.nip71Video.VideoVerticalEvent
import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent
import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent
@@ -1036,6 +1038,18 @@ object LocalCache : ILocalCache {
wasVerified: Boolean,
) = consumeBaseReplaceable(event, relay, wasVerified)
private fun consume(
event: VideoNormalEvent,
relay: NormalizedRelayUrl?,
wasVerified: Boolean,
) = consumeBaseReplaceable(event, relay, wasVerified)
private fun consume(
event: VideoShortEvent,
relay: NormalizedRelayUrl?,
wasVerified: Boolean,
) = consumeBaseReplaceable(event, relay, wasVerified)
fun consume(
event: StatusEvent,
relay: NormalizedRelayUrl?,
@@ -2809,7 +2823,9 @@ object LocalCache : ILocalCache {
is TorrentCommentEvent -> consume(event, relay, wasVerified)
is TrustedRelayListEvent -> consume(event, relay, wasVerified)
is VideoHorizontalEvent -> consume(event, relay, wasVerified)
is VideoNormalEvent -> consume(event, relay, wasVerified)
is VideoVerticalEvent -> consume(event, relay, wasVerified)
is VideoShortEvent -> consume(event, relay, wasVerified)
is VoiceEvent -> consume(event, relay, wasVerified)
is VoiceReplyEvent -> consume(event, relay, wasVerified)
is WikiNoteEvent -> consume(event, relay, wasVerified)

View File

@@ -208,6 +208,8 @@ import com.vitorpamplona.quartz.nip58Badges.BadgeDefinitionEvent
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
import com.vitorpamplona.quartz.nip71Video.VideoHorizontalEvent
import com.vitorpamplona.quartz.nip71Video.VideoNormalEvent
import com.vitorpamplona.quartz.nip71Video.VideoShortEvent
import com.vitorpamplona.quartz.nip71Video.VideoVerticalEvent
import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent
import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent
@@ -793,6 +795,8 @@ private fun RenderNoteRow(
is FileHeaderEvent -> FileHeaderDisplay(baseNote, true, ContentScale.FillWidth, accountViewModel)
is VideoHorizontalEvent -> VideoDisplay(baseNote, makeItShort, canPreview, backgroundColor, ContentScale.FillWidth, accountViewModel, nav)
is VideoVerticalEvent -> VideoDisplay(baseNote, makeItShort, canPreview, backgroundColor, ContentScale.FillWidth, accountViewModel, nav)
is VideoNormalEvent -> VideoDisplay(baseNote, makeItShort, canPreview, backgroundColor, ContentScale.FillWidth, accountViewModel, nav)
is VideoShortEvent -> VideoDisplay(baseNote, makeItShort, canPreview, backgroundColor, ContentScale.FillWidth, accountViewModel, nav)
is PictureEvent -> PictureDisplay(baseNote, true, ContentScale.FillWidth, PaddingValues(vertical = 5.dp), backgroundColor, accountViewModel, nav)
is BaseVoiceEvent -> RenderVoiceTrack(baseNote, ContentScale.FillWidth, accountViewModel, nav)
is FileStorageHeaderEvent -> FileStorageHeaderDisplay(baseNote, true, ContentScale.FillWidth, accountViewModel)

View File

@@ -28,6 +28,8 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
import com.vitorpamplona.quartz.nip71Video.VideoHorizontalEvent
import com.vitorpamplona.quartz.nip71Video.VideoNormalEvent
import com.vitorpamplona.quartz.nip71Video.VideoShortEvent
import com.vitorpamplona.quartz.nip71Video.VideoVerticalEvent
val UserProfileMediaKinds =
@@ -36,6 +38,8 @@ val UserProfileMediaKinds =
ProfileGalleryEntryEvent.KIND,
VideoVerticalEvent.KIND,
VideoHorizontalEvent.KIND,
VideoNormalEvent.KIND,
VideoShortEvent.KIND,
)
fun filterUserProfileMedia(

View File

@@ -37,6 +37,8 @@ import com.vitorpamplona.quartz.nip68Picture.PictureEvent
import com.vitorpamplona.quartz.nip68Picture.PictureMeta
import com.vitorpamplona.quartz.nip71Video.VideoHorizontalEvent
import com.vitorpamplona.quartz.nip71Video.VideoMeta
import com.vitorpamplona.quartz.nip71Video.VideoNormalEvent
import com.vitorpamplona.quartz.nip71Video.VideoShortEvent
import com.vitorpamplona.quartz.nip71Video.VideoVerticalEvent
import com.vitorpamplona.quartz.nip94FileMetadata.FileHeaderEvent
@@ -97,6 +99,10 @@ class VideoFeedFilter(
fun acceptanceEvent(noteEvent: VideoHorizontalEvent) = acceptableVideoiMetas(noteEvent.imetaTags())
fun acceptanceEvent(noteEvent: VideoNormalEvent) = acceptableVideoiMetas(noteEvent.imetaTags())
fun acceptanceEvent(noteEvent: VideoShortEvent) = acceptableVideoiMetas(noteEvent.imetaTags())
fun acceptableEvent(
note: Note,
params: FilterByListParams,
@@ -111,6 +117,8 @@ class VideoFeedFilter(
(noteEvent is FileHeaderEvent && acceptanceEvent(noteEvent)) ||
(noteEvent is VideoVerticalEvent && acceptanceEvent(noteEvent)) ||
(noteEvent is VideoHorizontalEvent && acceptanceEvent(noteEvent)) ||
(noteEvent is VideoNormalEvent && acceptanceEvent(noteEvent)) ||
(noteEvent is VideoShortEvent && acceptanceEvent(noteEvent)) ||
(noteEvent is FileStorageHeaderEvent && noteEvent.isOneOf(SUPPORTED_VIDEO_FEED_MIME_TYPES_SET)) ||
(noteEvent is PictureEvent && acceptanceEvent(noteEvent))
) &&

View File

@@ -23,15 +23,31 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.video.datasource
import com.vitorpamplona.quartz.experimental.nip95.header.FileStorageHeaderEvent
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
import com.vitorpamplona.quartz.nip71Video.VideoHorizontalEvent
import com.vitorpamplona.quartz.nip71Video.VideoNormalEvent
import com.vitorpamplona.quartz.nip71Video.VideoShortEvent
import com.vitorpamplona.quartz.nip71Video.VideoVerticalEvent
import com.vitorpamplona.quartz.nip94FileMetadata.FileHeaderEvent
val SUPPORTED_VIDEO_FEED_MIME_TYPES = listOf("image/jpeg", "image/gif", "image/png", "image/webp", "video/mp4", "video/mpeg", "video/webm", "audio/aac", "audio/mpeg", "audio/webm", "audio/wav", "image/avif")
val SUPPORTED_VIDEO_FEED_MIME_TYPES_SET = SUPPORTED_VIDEO_FEED_MIME_TYPES.toSet()
val PictureAndVideoKinds = listOf(PictureEvent.KIND, VideoHorizontalEvent.KIND, VideoVerticalEvent.KIND)
val PictureAndVideoKTags = listOf(PictureEvent.KIND.toString(), VideoHorizontalEvent.KIND.toString(), VideoVerticalEvent.KIND.toString())
val PictureAndVideoKinds =
listOf(
PictureEvent.KIND,
VideoHorizontalEvent.KIND,
VideoVerticalEvent.KIND,
VideoNormalEvent.KIND,
VideoShortEvent.KIND,
)
val PictureAndVideoKTags =
listOf(
PictureEvent.KIND.toString(),
VideoHorizontalEvent.KIND.toString(),
VideoVerticalEvent.KIND.toString(),
VideoNormalEvent.KIND.toString(),
VideoShortEvent.KIND.toString(),
)
val PictureAndVideoLegacyKinds = listOf(FileHeaderEvent.KIND, FileStorageHeaderEvent.KIND)
val PictureAndVideoLegacyKTags = listOf(FileHeaderEvent.KIND.toString(), FileStorageHeaderEvent.KIND.toString())
val LegacyMimeTypes = SUPPORTED_VIDEO_FEED_MIME_TYPES

View File

@@ -108,6 +108,8 @@ import com.vitorpamplona.quartz.nip62RequestToVanish.RequestToVanishEvent
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.nip68Picture.PictureEvent
import com.vitorpamplona.quartz.nip71Video.VideoHorizontalEvent
import com.vitorpamplona.quartz.nip71Video.VideoNormalEvent
import com.vitorpamplona.quartz.nip71Video.VideoShortEvent
import com.vitorpamplona.quartz.nip71Video.VideoVerticalEvent
import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent
import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent
@@ -286,6 +288,8 @@ class EventFactory {
TrustedRelayListEvent.KIND -> TrustedRelayListEvent(id, pubKey, createdAt, tags, content, sig)
VideoHorizontalEvent.KIND -> VideoHorizontalEvent(id, pubKey, createdAt, tags, content, sig)
VideoVerticalEvent.KIND -> VideoVerticalEvent(id, pubKey, createdAt, tags, content, sig)
VideoNormalEvent.KIND -> VideoNormalEvent(id, pubKey, createdAt, tags, content, sig)
VideoShortEvent.KIND -> VideoShortEvent(id, pubKey, createdAt, tags, content, sig)
VoiceEvent.KIND -> VoiceEvent(id, pubKey, createdAt, tags, content, sig)
VoiceReplyEvent.KIND -> VoiceReplyEvent(id, pubKey, createdAt, tags, content, sig)
WikiNoteEvent.KIND -> WikiNoteEvent(id, pubKey, createdAt, tags, content, sig)

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip71Video
import androidx.compose.runtime.Immutable
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag
import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.utils.TimeUtils
import java.util.UUID
@Immutable
class VideoNormalEvent(
id: HexKey,
pubKey: HexKey,
createdAt: Long,
tags: Array<Array<String>>,
content: String,
sig: HexKey,
) : VideoEvent(id, pubKey, createdAt, KIND, tags, content, sig),
RootScope {
companion object {
const val KIND = 21
const val ALT_DESCRIPTION = "Horizontal Video"
fun build(
video: VideoMeta,
description: String,
dTag: String = UUID.randomUUID().toString(),
createdAt: Long = TimeUtils.now(),
initializer: TagArrayBuilder<VideoNormalEvent>.() -> Unit = {},
) = build(description, dTag, createdAt) {
videoIMeta(video)
initializer()
}
fun build(
video: List<VideoMeta>,
description: String,
dTag: String = UUID.randomUUID().toString(),
createdAt: Long = TimeUtils.now(),
initializer: TagArrayBuilder<VideoNormalEvent>.() -> Unit = {},
) = build(description, dTag, createdAt) {
videoIMetas(video)
initializer()
}
fun build(
description: String,
dTag: String = UUID.randomUUID().toString(),
createdAt: Long = TimeUtils.now(),
initializer: TagArrayBuilder<VideoNormalEvent>.() -> Unit = {},
) = eventTemplate(KIND, description, createdAt) {
dTag(dTag)
alt(ALT_DESCRIPTION)
initializer()
}
}
}

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip71Video
import androidx.compose.runtime.Immutable
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
import com.vitorpamplona.quartz.nip01Core.tags.dTags.dTag
import com.vitorpamplona.quartz.nip22Comments.RootScope
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.utils.TimeUtils
import java.util.UUID
@Immutable
class VideoShortEvent(
id: HexKey,
pubKey: HexKey,
createdAt: Long,
tags: Array<Array<String>>,
content: String,
sig: HexKey,
) : VideoEvent(id, pubKey, createdAt, KIND, tags, content, sig),
RootScope {
companion object {
const val KIND = 22
const val ALT_DESCRIPTION = "Vertical Video"
fun build(
video: VideoMeta,
description: String,
dTag: String = UUID.randomUUID().toString(),
createdAt: Long = TimeUtils.now(),
initializer: TagArrayBuilder<VideoShortEvent>.() -> Unit = {},
) = build(description, dTag, createdAt) {
videoIMeta(video)
initializer()
}
fun build(
description: String,
dTag: String = UUID.randomUUID().toString(),
createdAt: Long = TimeUtils.now(),
initializer: TagArrayBuilder<VideoShortEvent>.() -> Unit = {},
) = eventTemplate(KIND, description, createdAt) {
dTag(dTag)
alt(ALT_DESCRIPTION)
initializer()
}
}
}