Adds support for Stemstr

This commit is contained in:
Vitor Pamplona
2023-08-18 20:36:32 -04:00
parent 7a93f9956f
commit 58dd69091e
13 changed files with 181 additions and 18 deletions
@@ -1051,6 +1051,23 @@ object LocalCache {
refreshObservers(note) refreshObservers(note)
} }
fun consume(event: AudioHeaderEvent, relay: Relay?) {
val note = getOrCreateNote(event.id)
val author = getOrCreateUser(event.pubKey)
if (relay != null) {
author.addRelayBeingUsed(relay, event.createdAt)
note.addRelay(relay)
}
// Already processed this event.
if (note.event != null) return
note.loadEvent(event, author, emptyList())
refreshObservers(note)
}
fun consume(event: FileHeaderEvent, relay: Relay?) { fun consume(event: FileHeaderEvent, relay: Relay?) {
val note = getOrCreateNote(event.id) val note = getOrCreateNote(event.id)
val author = getOrCreateUser(event.pubKey) val author = getOrCreateUser(event.pubKey)
@@ -1284,7 +1301,7 @@ object LocalCache {
} }
return notes.values.filter { return notes.values.filter {
(it.event !is GenericRepostEvent && it.event !is RepostEvent && it.event !is CommunityPostApprovalEvent && it.event !is ReactionEvent) && (it.event !is GenericRepostEvent && it.event !is RepostEvent && it.event !is CommunityPostApprovalEvent && it.event !is ReactionEvent && it.event !is GiftWrapEvent) &&
( (
it.event?.content()?.contains(text, true) ?: false || it.event?.content()?.contains(text, true) ?: false ||
it.event?.matchTag1With(text) ?: false || it.event?.matchTag1With(text) ?: false ||
@@ -1292,7 +1309,7 @@ object LocalCache {
it.idNote().startsWith(text, true) it.idNote().startsWith(text, true)
) )
} + addressables.values.filter { } + addressables.values.filter {
(it.event !is GenericRepostEvent && it.event !is RepostEvent && it.event !is CommunityPostApprovalEvent && it.event !is ReactionEvent) && (it.event !is GenericRepostEvent && it.event !is RepostEvent && it.event !is CommunityPostApprovalEvent && it.event !is ReactionEvent && it.event !is GiftWrapEvent) &&
( (
it.event?.content()?.contains(text, true) ?: false || it.event?.content()?.contains(text, true) ?: false ||
it.event?.matchTag1With(text) ?: false || it.event?.matchTag1With(text) ?: false ||
@@ -1524,6 +1541,7 @@ object LocalCache {
is AdvertisedRelayListEvent -> consume(event) is AdvertisedRelayListEvent -> consume(event)
is AppDefinitionEvent -> consume(event) is AppDefinitionEvent -> consume(event)
is AppRecommendationEvent -> consume(event) is AppRecommendationEvent -> consume(event)
is AudioHeaderEvent -> consume(event, relay)
is AudioTrackEvent -> consume(event) is AudioTrackEvent -> consume(event)
is BadgeAwardEvent -> consume(event) is BadgeAwardEvent -> consume(event)
is BadgeDefinitionEvent -> consume(event) is BadgeDefinitionEvent -> consume(event)
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.service
import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES
import com.vitorpamplona.amethyst.service.relays.JsonFilter import com.vitorpamplona.amethyst.service.relays.JsonFilter
import com.vitorpamplona.amethyst.service.relays.TypedFilter import com.vitorpamplona.amethyst.service.relays.TypedFilter
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.AudioTrackEvent
import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent
import com.vitorpamplona.quartz.events.ClassifiedsEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent
@@ -26,7 +27,7 @@ object NostrGeohashDataSource : NostrDataSource("SingleGeoHashFeed") {
hashToLoad hashToLoad
) )
), ),
kinds = listOf(TextNoteEvent.kind, ChannelMessageEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind, LiveActivitiesChatMessageEvent.kind, ClassifiedsEvent.kind, HighlightEvent.kind, AudioTrackEvent.kind), kinds = listOf(TextNoteEvent.kind, ChannelMessageEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind, LiveActivitiesChatMessageEvent.kind, ClassifiedsEvent.kind, HighlightEvent.kind, AudioTrackEvent.kind, AudioHeaderEvent.kind),
limit = 200 limit = 200
) )
) )
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.service
import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES import com.vitorpamplona.amethyst.service.relays.COMMON_FEED_TYPES
import com.vitorpamplona.amethyst.service.relays.JsonFilter import com.vitorpamplona.amethyst.service.relays.JsonFilter
import com.vitorpamplona.amethyst.service.relays.TypedFilter import com.vitorpamplona.amethyst.service.relays.TypedFilter
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.AudioTrackEvent
import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent
import com.vitorpamplona.quartz.events.ClassifiedsEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent
@@ -29,7 +30,7 @@ object NostrHashtagDataSource : NostrDataSource("SingleHashtagFeed") {
hashToLoad.capitalize() hashToLoad.capitalize()
) )
), ),
kinds = listOf(TextNoteEvent.kind, ChannelMessageEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind, LiveActivitiesChatMessageEvent.kind, ClassifiedsEvent.kind, HighlightEvent.kind, AudioTrackEvent.kind), kinds = listOf(TextNoteEvent.kind, ChannelMessageEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind, LiveActivitiesChatMessageEvent.kind, ClassifiedsEvent.kind, HighlightEvent.kind, AudioTrackEvent.kind, AudioHeaderEvent.kind),
limit = 200 limit = 200
) )
) )
@@ -6,6 +6,7 @@ import com.vitorpamplona.amethyst.service.relays.EOSEAccount
import com.vitorpamplona.amethyst.service.relays.FeedType import com.vitorpamplona.amethyst.service.relays.FeedType
import com.vitorpamplona.amethyst.service.relays.JsonFilter import com.vitorpamplona.amethyst.service.relays.JsonFilter
import com.vitorpamplona.amethyst.service.relays.TypedFilter import com.vitorpamplona.amethyst.service.relays.TypedFilter
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.AudioTrackEvent
import com.vitorpamplona.quartz.events.ClassifiedsEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent
import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent import com.vitorpamplona.quartz.events.CommunityPostApprovalEvent
@@ -73,6 +74,7 @@ object NostrHomeDataSource : NostrDataSource("HomeFeed") {
PollNoteEvent.kind, PollNoteEvent.kind,
HighlightEvent.kind, HighlightEvent.kind,
AudioTrackEvent.kind, AudioTrackEvent.kind,
AudioHeaderEvent.kind,
PinListEvent.kind, PinListEvent.kind,
LiveActivitiesChatMessageEvent.kind, LiveActivitiesChatMessageEvent.kind,
LiveActivitiesEvent.kind LiveActivitiesEvent.kind
@@ -92,7 +94,7 @@ object NostrHomeDataSource : NostrDataSource("HomeFeed") {
return TypedFilter( return TypedFilter(
types = setOf(FeedType.FOLLOWS), types = setOf(FeedType.FOLLOWS),
filter = JsonFilter( filter = JsonFilter(
kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind, ClassifiedsEvent.kind, HighlightEvent.kind, AudioTrackEvent.kind, PinListEvent.kind), kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind, ClassifiedsEvent.kind, HighlightEvent.kind, AudioHeaderEvent.kind, AudioTrackEvent.kind, PinListEvent.kind),
tags = mapOf( tags = mapOf(
"t" to hashToLoad.map { "t" to hashToLoad.map {
listOf(it, it.lowercase(), it.uppercase(), it.capitalize()) listOf(it, it.lowercase(), it.uppercase(), it.capitalize())
@@ -112,7 +114,7 @@ object NostrHomeDataSource : NostrDataSource("HomeFeed") {
return TypedFilter( return TypedFilter(
types = setOf(FeedType.FOLLOWS), types = setOf(FeedType.FOLLOWS),
filter = JsonFilter( filter = JsonFilter(
kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind, ClassifiedsEvent.kind, HighlightEvent.kind, AudioTrackEvent.kind, PinListEvent.kind), kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind, ClassifiedsEvent.kind, HighlightEvent.kind, AudioHeaderEvent.kind, AudioTrackEvent.kind, PinListEvent.kind),
tags = mapOf( tags = mapOf(
"g" to hashToLoad.map { "g" to hashToLoad.map {
listOf(it, it.lowercase(), it.uppercase(), it.capitalize()) listOf(it, it.lowercase(), it.uppercase(), it.capitalize())
@@ -137,6 +139,7 @@ object NostrHomeDataSource : NostrDataSource("HomeFeed") {
LongTextNoteEvent.kind, LongTextNoteEvent.kind,
ClassifiedsEvent.kind, ClassifiedsEvent.kind,
HighlightEvent.kind, HighlightEvent.kind,
AudioHeaderEvent.kind,
AudioTrackEvent.kind, AudioTrackEvent.kind,
PinListEvent.kind, PinListEvent.kind,
CommunityPostApprovalEvent.kind CommunityPostApprovalEvent.kind
@@ -56,8 +56,9 @@ object NostrSearchEventOrUserDataSource : NostrDataSource("SearchEventFeed") {
filter = JsonFilter( filter = JsonFilter(
kinds = listOf( kinds = listOf(
TextNoteEvent.kind, LongTextNoteEvent.kind, BadgeDefinitionEvent.kind, TextNoteEvent.kind, LongTextNoteEvent.kind, BadgeDefinitionEvent.kind,
PeopleListEvent.kind, BookmarkListEvent.kind, AudioTrackEvent.kind, PinListEvent.kind, PeopleListEvent.kind, BookmarkListEvent.kind, AudioHeaderEvent.kind,
PollNoteEvent.kind, ChannelCreateEvent.kind AudioTrackEvent.kind, PinListEvent.kind, PollNoteEvent.kind,
ChannelCreateEvent.kind
), ),
search = mySearchString, search = mySearchString,
limit = 100 limit = 100
@@ -34,6 +34,7 @@ object NostrUserProfileDataSource : NostrDataSource("UserProfileFeed") {
RepostEvent.kind, RepostEvent.kind,
LongTextNoteEvent.kind, LongTextNoteEvent.kind,
AudioTrackEvent.kind, AudioTrackEvent.kind,
AudioHeaderEvent.kind,
PinListEvent.kind, PinListEvent.kind,
PollNoteEvent.kind, PollNoteEvent.kind,
HighlightEvent.kind HighlightEvent.kind
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.ui.dal
import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent
import com.vitorpamplona.quartz.events.LongTextNoteEvent import com.vitorpamplona.quartz.events.LongTextNoteEvent
import com.vitorpamplona.quartz.events.PrivateDmEvent import com.vitorpamplona.quartz.events.PrivateDmEvent
@@ -32,7 +33,8 @@ class GeoHashFeedFilter(val tag: String, val account: Account) : AdditiveFeedFil
it.event is TextNoteEvent || it.event is TextNoteEvent ||
it.event is LongTextNoteEvent || it.event is LongTextNoteEvent ||
it.event is ChannelMessageEvent || it.event is ChannelMessageEvent ||
it.event is PrivateDmEvent it.event is PrivateDmEvent ||
it.event is AudioHeaderEvent
) && ) &&
it.event?.isTaggedGeoHash(myTag) == true it.event?.isTaggedGeoHash(myTag) == true
} }
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.ui.dal
import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.ChannelMessageEvent import com.vitorpamplona.quartz.events.ChannelMessageEvent
import com.vitorpamplona.quartz.events.LongTextNoteEvent import com.vitorpamplona.quartz.events.LongTextNoteEvent
import com.vitorpamplona.quartz.events.PrivateDmEvent import com.vitorpamplona.quartz.events.PrivateDmEvent
@@ -32,7 +33,8 @@ class HashtagFeedFilter(val tag: String, val account: Account) : AdditiveFeedFil
it.event is TextNoteEvent || it.event is TextNoteEvent ||
it.event is LongTextNoteEvent || it.event is LongTextNoteEvent ||
it.event is ChannelMessageEvent || it.event is ChannelMessageEvent ||
it.event is PrivateDmEvent it.event is PrivateDmEvent ||
it.event is AudioHeaderEvent
) && ) &&
it.event?.isTaggedHash(myTag) == true it.event?.isTaggedHash(myTag) == true
} }
@@ -4,6 +4,7 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS import com.vitorpamplona.amethyst.model.GLOBAL_FOLLOWS
import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.AudioTrackEvent
import com.vitorpamplona.quartz.events.ClassifiedsEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent
import com.vitorpamplona.quartz.events.GenericRepostEvent import com.vitorpamplona.quartz.events.GenericRepostEvent
@@ -53,7 +54,7 @@ class HomeNewThreadFeedFilter(val account: Account) : AdditiveFeedFilter<Note>()
.filter { it -> .filter { it ->
val noteEvent = it.event val noteEvent = it.event
val isGlobalRelay = it.relays.any { gRelays.contains(it) } val isGlobalRelay = it.relays.any { gRelays.contains(it) }
(noteEvent is TextNoteEvent || noteEvent is ClassifiedsEvent || noteEvent is RepostEvent || noteEvent is GenericRepostEvent || noteEvent is LongTextNoteEvent || noteEvent is PollNoteEvent || noteEvent is HighlightEvent || noteEvent is AudioTrackEvent) && (noteEvent is TextNoteEvent || noteEvent is ClassifiedsEvent || noteEvent is RepostEvent || noteEvent is GenericRepostEvent || noteEvent is LongTextNoteEvent || noteEvent is PollNoteEvent || noteEvent is HighlightEvent || noteEvent is AudioTrackEvent || noteEvent is AudioHeaderEvent) &&
(!ignoreAddressables || noteEvent.kind() < 10000) && (!ignoreAddressables || noteEvent.kind() < 10000) &&
((isGlobal && isGlobalRelay) || it.author?.pubkeyHex in followingKeySet || noteEvent.isTaggedHashes(followingTagSet) || noteEvent.isTaggedGeoHashes(followingGeoSet) || noteEvent.isTaggedAddressableNotes(followingCommunities)) && ((isGlobal && isGlobalRelay) || it.author?.pubkeyHex in followingKeySet || noteEvent.isTaggedHashes(followingTagSet) || noteEvent.isTaggedGeoHashes(followingGeoSet) || noteEvent.isTaggedAddressableNotes(followingCommunities)) &&
// && account.isAcceptable(it) // This filter follows only. No need to check if acceptable // && account.isAcceptable(it) // This filter follows only. No need to check if acceptable
@@ -4,6 +4,7 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.AudioTrackEvent
import com.vitorpamplona.quartz.events.ClassifiedsEvent import com.vitorpamplona.quartz.events.ClassifiedsEvent
import com.vitorpamplona.quartz.events.GenericRepostEvent import com.vitorpamplona.quartz.events.GenericRepostEvent
@@ -41,7 +42,8 @@ class UserProfileNewThreadFeedFilter(val user: User, val account: Account) : Add
it.event is LongTextNoteEvent || it.event is LongTextNoteEvent ||
it.event is PollNoteEvent || it.event is PollNoteEvent ||
it.event is HighlightEvent || it.event is HighlightEvent ||
it.event is AudioTrackEvent it.event is AudioTrackEvent ||
it.event is AudioHeaderEvent
) && ) &&
it.isNewThread() && it.isNewThread() &&
account.isAcceptable(it) == true account.isAcceptable(it) == true
@@ -154,6 +154,7 @@ import com.vitorpamplona.amethyst.ui.theme.subtleBorder
import com.vitorpamplona.quartz.encoders.ATag import com.vitorpamplona.quartz.encoders.ATag
import com.vitorpamplona.quartz.encoders.toNpub import com.vitorpamplona.quartz.encoders.toNpub
import com.vitorpamplona.quartz.events.AppDefinitionEvent import com.vitorpamplona.quartz.events.AppDefinitionEvent
import com.vitorpamplona.quartz.events.AudioHeaderEvent
import com.vitorpamplona.quartz.events.AudioTrackEvent import com.vitorpamplona.quartz.events.AudioTrackEvent
import com.vitorpamplona.quartz.events.BadgeAwardEvent import com.vitorpamplona.quartz.events.BadgeAwardEvent
import com.vitorpamplona.quartz.events.BadgeDefinitionEvent import com.vitorpamplona.quartz.events.BadgeDefinitionEvent
@@ -1045,6 +1046,14 @@ private fun RenderNoteRow(
RenderAppDefinition(baseNote, accountViewModel, nav) RenderAppDefinition(baseNote, accountViewModel, nav)
} }
is AudioTrackEvent -> {
RenderAudioTrack(baseNote, accountViewModel, nav)
}
is AudioHeaderEvent -> {
RenderAudioHeader(baseNote, accountViewModel, nav)
}
is ReactionEvent -> { is ReactionEvent -> {
RenderReaction(baseNote, backgroundColor, accountViewModel, nav) RenderReaction(baseNote, backgroundColor, accountViewModel, nav)
} }
@@ -1077,10 +1086,6 @@ private fun RenderNoteRow(
DisplayRelaySet(baseNote, backgroundColor, accountViewModel, nav) DisplayRelaySet(baseNote, backgroundColor, accountViewModel, nav)
} }
is AudioTrackEvent -> {
RenderAudioTrack(baseNote, accountViewModel, nav)
}
is PinListEvent -> { is PinListEvent -> {
RenderPinListEvent(baseNote, backgroundColor, accountViewModel, nav) RenderPinListEvent(baseNote, backgroundColor, accountViewModel, nav)
} }
@@ -2251,6 +2256,17 @@ private fun RenderAudioTrack(
AudioTrackHeader(noteEvent, note, accountViewModel, nav) AudioTrackHeader(noteEvent, note, accountViewModel, nav)
} }
@Composable
private fun RenderAudioHeader(
note: Note,
accountViewModel: AccountViewModel,
nav: (String) -> Unit
) {
val noteEvent = note.event as? AudioHeaderEvent ?: return
AudioHeader(noteEvent, note, accountViewModel, nav)
}
@Composable @Composable
private fun RenderLongFormContent( private fun RenderLongFormContent(
note: Note, note: Note,
@@ -3343,8 +3359,7 @@ fun AudioTrackHeader(noteEvent: AudioTrackEvent, note: Note, accountViewModel: A
media?.let { media -> media?.let { media ->
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically
modifier = Modifier.padding(10.dp)
) { ) {
cover?.let { cover -> cover?.let { cover ->
LoadThumbAndThenVideoView( LoadThumbAndThenVideoView(
@@ -3368,6 +3383,62 @@ fun AudioTrackHeader(noteEvent: AudioTrackEvent, note: Note, accountViewModel: A
} }
} }
@Composable
fun AudioHeader(noteEvent: AudioHeaderEvent, note: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
val media = remember { noteEvent.stream() ?: noteEvent.download() }
val subject = remember { noteEvent.subject()?.ifBlank { null } }
val content = remember { noteEvent.content().ifBlank { null } }
Row(modifier = Modifier.padding(top = 5.dp)) {
Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
media?.let { media ->
Row(
verticalAlignment = Alignment.CenterVertically
) {
VideoView(
videoUri = media,
title = noteEvent.subject(),
authorName = note.author?.toBestDisplayName(),
accountViewModel = accountViewModel,
nostrUriCallback = note.toNostrUri()
)
}
}
Row() {
subject?.let {
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)) {
Text(
text = it,
fontWeight = FontWeight.Bold,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth()
)
}
}
}
Row() {
content?.let {
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)) {
Text(
text = it,
fontWeight = FontWeight.Bold,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth()
)
}
}
}
val hashtags = remember(noteEvent) { noteEvent.hashtags().toImmutableList() }
DisplayUncitedHashtags(hashtags, content ?: "", nav)
}
}
}
@Composable @Composable
fun RenderLiveActivityEvent(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) { fun RenderLiveActivityEvent(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
Row(modifier = Modifier.padding(top = 5.dp)) { Row(modifier = Modifier.padding(top = 5.dp)) {
@@ -0,0 +1,59 @@
package com.vitorpamplona.quartz.events
import androidx.compose.runtime.Immutable
import com.vitorpamplona.quartz.utils.TimeUtils
import com.vitorpamplona.quartz.encoders.toHexKey
import com.vitorpamplona.quartz.crypto.CryptoUtils
import com.vitorpamplona.quartz.encoders.HexKey
@Immutable
class AudioHeaderEvent(
id: HexKey,
pubKey: HexKey,
createdAt: Long,
tags: List<List<String>>,
content: String,
sig: HexKey
) : Event(id, pubKey, createdAt, kind, tags, content, sig) {
fun download() = tags.firstOrNull { it.size > 1 && it[0] == DOWNLOAD_URL }?.get(1)
fun stream() = tags.firstOrNull { it.size > 1 && it[0] == STREAM_URL }?.get(1)
fun wavefrom() = tags.firstOrNull { it.size > 1 && it[0] == WAVEFORM }?.get(1)
companion object {
const val kind = 1808
private const val DOWNLOAD_URL = "download_url"
private const val STREAM_URL = "stream_url"
private const val WAVEFORM = "waveform"
fun create(
description: String,
downloadUrl: String,
streamUrl: String? = null,
wavefront: String? = null,
sensitiveContent: Boolean? = null,
privateKey: ByteArray,
createdAt: Long = TimeUtils.now()
): AudioHeaderEvent {
val tags = listOfNotNull(
downloadUrl.let { listOf(DOWNLOAD_URL, it) },
streamUrl?.let { listOf(STREAM_URL, it) },
wavefront?.let { listOf(WAVEFORM, it) },
sensitiveContent?.let {
if (it) {
listOf("content-warning", "")
} else {
null
}
}
)
val content = description
val pubKey = CryptoUtils.pubkeyCreate(privateKey).toHexKey()
val id = generateId(pubKey, createdAt, kind, tags, content)
val sig = CryptoUtils.sign(id, privateKey)
return AudioHeaderEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey())
}
}
}
@@ -16,6 +16,7 @@ class EventFactory {
AdvertisedRelayListEvent.kind -> AdvertisedRelayListEvent(id, pubKey, createdAt, tags, content, sig) AdvertisedRelayListEvent.kind -> AdvertisedRelayListEvent(id, pubKey, createdAt, tags, content, sig)
AppDefinitionEvent.kind -> AppDefinitionEvent(id, pubKey, createdAt, tags, content, sig) AppDefinitionEvent.kind -> AppDefinitionEvent(id, pubKey, createdAt, tags, content, sig)
AppRecommendationEvent.kind -> AppRecommendationEvent(id, pubKey, createdAt, tags, content, sig) AppRecommendationEvent.kind -> AppRecommendationEvent(id, pubKey, createdAt, tags, content, sig)
AudioHeaderEvent.kind -> AudioHeaderEvent(id, pubKey, createdAt, tags, content, sig)
AudioTrackEvent.kind -> AudioTrackEvent(id, pubKey, createdAt, tags, content, sig) AudioTrackEvent.kind -> AudioTrackEvent(id, pubKey, createdAt, tags, content, sig)
BadgeAwardEvent.kind -> BadgeAwardEvent(id, pubKey, createdAt, tags, content, sig) BadgeAwardEvent.kind -> BadgeAwardEvent(id, pubKey, createdAt, tags, content, sig)
BadgeDefinitionEvent.kind -> BadgeDefinitionEvent(id, pubKey, createdAt, tags, content, sig) BadgeDefinitionEvent.kind -> BadgeDefinitionEvent(id, pubKey, createdAt, tags, content, sig)