mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-27 18:36:37 +02:00
Adds support for NIP-53 Meeting room to quartz
This commit is contained in:
@@ -93,6 +93,9 @@ import com.vitorpamplona.quartz.nip52Calendar.CalendarEvent
|
|||||||
import com.vitorpamplona.quartz.nip52Calendar.CalendarRSVPEvent
|
import com.vitorpamplona.quartz.nip52Calendar.CalendarRSVPEvent
|
||||||
import com.vitorpamplona.quartz.nip52Calendar.CalendarTimeSlotEvent
|
import com.vitorpamplona.quartz.nip52Calendar.CalendarTimeSlotEvent
|
||||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.presence.MeetingRoomPresenceEvent
|
||||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
|
||||||
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
||||||
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
import com.vitorpamplona.quartz.nip56Reports.ReportEvent
|
||||||
@@ -253,6 +256,9 @@ class EventFactory {
|
|||||||
LnZapPrivateEvent.KIND -> LnZapPrivateEvent(id, pubKey, createdAt, tags, content, sig)
|
LnZapPrivateEvent.KIND -> LnZapPrivateEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
LnZapRequestEvent.KIND -> LnZapRequestEvent(id, pubKey, createdAt, tags, content, sig)
|
LnZapRequestEvent.KIND -> LnZapRequestEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
LongTextNoteEvent.KIND -> LongTextNoteEvent(id, pubKey, createdAt, tags, content, sig)
|
LongTextNoteEvent.KIND -> LongTextNoteEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
MeetingRoomEvent.KIND -> MeetingRoomEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
MeetingRoomPresenceEvent.KIND -> MeetingRoomPresenceEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
MeetingSpaceEvent.KIND -> MeetingSpaceEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
MetadataEvent.KIND -> MetadataEvent(id, pubKey, createdAt, tags, content, sig)
|
MetadataEvent.KIND -> MetadataEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
MuteListEvent.KIND -> MuteListEvent(id, pubKey, createdAt, tags, content, sig)
|
MuteListEvent.KIND -> MuteListEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
NNSEvent.KIND -> NNSEvent(id, pubKey, createdAt, tags, content, sig)
|
NNSEvent.KIND -> NNSEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
@@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.meetingSpaces
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.any
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||||
|
import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag
|
||||||
|
import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag
|
||||||
|
import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag
|
||||||
|
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.MeetingSpaceTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.CurrentParticipantsTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.EndsTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.PinnedEventTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.RecordingTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.RelayListTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StartsTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StatusTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StreamingTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.TotalParticipantsTag
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
class MeetingRoomEvent(
|
||||||
|
id: HexKey,
|
||||||
|
pubKey: HexKey,
|
||||||
|
createdAt: Long,
|
||||||
|
tags: Array<Array<String>>,
|
||||||
|
content: String,
|
||||||
|
sig: HexKey,
|
||||||
|
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||||
|
EventHintProvider,
|
||||||
|
AddressHintProvider,
|
||||||
|
PubKeyHintProvider {
|
||||||
|
override fun eventHints(): List<EventIdHint> {
|
||||||
|
val pinnedEvents = pinned()
|
||||||
|
if (pinnedEvents.isEmpty()) return emptyList()
|
||||||
|
|
||||||
|
val relays = allRelayUrls()
|
||||||
|
|
||||||
|
return if (relays.isNotEmpty()) {
|
||||||
|
pinnedEvents
|
||||||
|
.map { eventId ->
|
||||||
|
relays.map { relay ->
|
||||||
|
EventIdHint(eventId, relay)
|
||||||
|
}
|
||||||
|
}.flatten()
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun linkedEventIds() = tags.mapNotNull(PinnedEventTag::parse)
|
||||||
|
|
||||||
|
override fun addressHints(): List<AddressHint> = tags.mapNotNull(MeetingSpaceTag::parseAsHint)
|
||||||
|
|
||||||
|
override fun linkedAddressIds(): List<String> = tags.mapNotNull(MeetingSpaceTag::parseAddressId)
|
||||||
|
|
||||||
|
override fun pubKeyHints() = tags.mapNotNull(ParticipantTag::parseAsHint)
|
||||||
|
|
||||||
|
override fun linkedPubKeys() = tags.mapNotNull(ParticipantTag::parseKey)
|
||||||
|
|
||||||
|
fun interactiveRoom() = tags.firstNotNullOfOrNull(MeetingSpaceTag::parse)
|
||||||
|
|
||||||
|
fun title() = tags.firstNotNullOfOrNull(TitleTag::parse)
|
||||||
|
|
||||||
|
fun summary() = tags.firstNotNullOfOrNull(SummaryTag::parse)
|
||||||
|
|
||||||
|
fun image() = tags.firstNotNullOfOrNull(ImageTag::parse)
|
||||||
|
|
||||||
|
fun streaming() = tags.firstNotNullOfOrNull(StreamingTag::parse)
|
||||||
|
|
||||||
|
fun recording() = tags.firstNotNullOfOrNull(RecordingTag::parse)
|
||||||
|
|
||||||
|
fun starts() = tags.firstNotNullOfOrNull(StartsTag::parse)
|
||||||
|
|
||||||
|
fun ends() = tags.firstNotNullOfOrNull(EndsTag::parse)
|
||||||
|
|
||||||
|
fun status() = checkStatus(tags.firstNotNullOfOrNull(StatusTag::parseEnum))
|
||||||
|
|
||||||
|
fun isLive() = status() == StatusTag.STATUS.LIVE
|
||||||
|
|
||||||
|
fun currentParticipants() = tags.firstNotNullOfOrNull(CurrentParticipantsTag::parse)
|
||||||
|
|
||||||
|
fun totalParticipants() = tags.firstNotNullOfOrNull(TotalParticipantsTag::parse)
|
||||||
|
|
||||||
|
fun participantKeys(): List<HexKey> = tags.mapNotNull(ParticipantTag::parseKey)
|
||||||
|
|
||||||
|
fun participants() = tags.mapNotNull(ParticipantTag::parse)
|
||||||
|
|
||||||
|
fun relays() = tags.mapNotNull(RelayListTag::parse).flatten()
|
||||||
|
|
||||||
|
fun allRelayUrls() = tags.mapNotNull(RelayListTag::parse).flatten()
|
||||||
|
|
||||||
|
fun hasHost() = tags.any(ParticipantTag::isHost)
|
||||||
|
|
||||||
|
fun host() = tags.firstNotNullOfOrNull(ParticipantTag::parseHost)
|
||||||
|
|
||||||
|
fun hosts() = tags.mapNotNull(ParticipantTag::parseHost)
|
||||||
|
|
||||||
|
fun pinned() = tags.mapNotNull(PinnedEventTag::parse)
|
||||||
|
|
||||||
|
fun checkStatus(eventStatus: StatusTag.STATUS?): StatusTag.STATUS? =
|
||||||
|
if (eventStatus == StatusTag.STATUS.LIVE && createdAt < TimeUtils.eightHoursAgo()) {
|
||||||
|
StatusTag.STATUS.ENDED
|
||||||
|
} else if (eventStatus == StatusTag.STATUS.PLANNED) {
|
||||||
|
val starts = starts()
|
||||||
|
val ends = ends()
|
||||||
|
if (starts != null && starts < TimeUtils.oneHourAgo()) {
|
||||||
|
StatusTag.STATUS.ENDED
|
||||||
|
} else if (ends != null && ends < TimeUtils.oneHourAgo()) {
|
||||||
|
StatusTag.STATUS.ENDED
|
||||||
|
} else {
|
||||||
|
eventStatus
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eventStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun participantsIntersect(keySet: Set<String>): Boolean = keySet.contains(pubKey) || tags.any(ParticipantTag::isIn, keySet)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val KIND = 30313
|
||||||
|
const val ALT = "Meeting room event"
|
||||||
|
|
||||||
|
suspend fun create(
|
||||||
|
signer: NostrSigner,
|
||||||
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
): MeetingRoomEvent {
|
||||||
|
val tags = arrayOf(AltTag.assemble(ALT))
|
||||||
|
return signer.sign(createdAt, KIND, tags, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.meetingSpaces
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.any
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||||
|
import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag
|
||||||
|
import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag
|
||||||
|
import com.vitorpamplona.quartz.nip31Alts.AltTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.EndpointUrlTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.RelayListTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.RoomNameTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.ServiceUrlTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.StatusTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
class MeetingSpaceEvent(
|
||||||
|
id: HexKey,
|
||||||
|
pubKey: HexKey,
|
||||||
|
createdAt: Long,
|
||||||
|
tags: Array<Array<String>>,
|
||||||
|
content: String,
|
||||||
|
sig: HexKey,
|
||||||
|
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||||
|
PubKeyHintProvider {
|
||||||
|
override fun pubKeyHints() = tags.mapNotNull(ParticipantTag::parseAsHint)
|
||||||
|
|
||||||
|
override fun linkedPubKeys() = tags.mapNotNull(ParticipantTag::parseKey)
|
||||||
|
|
||||||
|
fun room() = tags.firstNotNullOfOrNull(RoomNameTag::parse)
|
||||||
|
|
||||||
|
fun summary() = tags.firstNotNullOfOrNull(SummaryTag::parse)
|
||||||
|
|
||||||
|
fun image() = tags.firstNotNullOfOrNull(ImageTag::parse)
|
||||||
|
|
||||||
|
fun status() = checkStatus(tags.firstNotNullOfOrNull(StatusTag::parseEnum))
|
||||||
|
|
||||||
|
fun isLive() = status() != StatusTag.STATUS.CLOSED
|
||||||
|
|
||||||
|
fun service() = tags.firstNotNullOfOrNull(ServiceUrlTag::parse)
|
||||||
|
|
||||||
|
fun endpoint() = tags.firstNotNullOfOrNull(EndpointUrlTag::parse)
|
||||||
|
|
||||||
|
fun relays() = tags.mapNotNull(RelayListTag::parse).flatten()
|
||||||
|
|
||||||
|
fun allRelayUrls() = tags.mapNotNull(RelayListTag::parse).flatten()
|
||||||
|
|
||||||
|
fun participantKeys(): List<HexKey> = tags.mapNotNull(ParticipantTag::parseKey)
|
||||||
|
|
||||||
|
fun participants() = tags.mapNotNull(ParticipantTag::parse)
|
||||||
|
|
||||||
|
fun checkStatus(eventStatus: StatusTag.STATUS?): StatusTag.STATUS? =
|
||||||
|
if (eventStatus != StatusTag.STATUS.CLOSED && createdAt < TimeUtils.eightHoursAgo()) {
|
||||||
|
StatusTag.STATUS.CLOSED
|
||||||
|
} else {
|
||||||
|
eventStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun participantsIntersect(keySet: Set<String>): Boolean = keySet.contains(pubKey) || tags.any(ParticipantTag::isIn, keySet)
|
||||||
|
|
||||||
|
companion object Companion {
|
||||||
|
const val KIND = 30312
|
||||||
|
const val ALT = "Interactive room event"
|
||||||
|
|
||||||
|
suspend fun create(
|
||||||
|
signer: NostrSigner,
|
||||||
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
): MeetingSpaceEvent {
|
||||||
|
val tags = arrayOf(AltTag.assemble(ALT))
|
||||||
|
return signer.sign(createdAt, KIND, tags, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.meetingSpaces.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
class EndpointUrlTag {
|
||||||
|
companion object Companion {
|
||||||
|
const val TAG_NAME = "endpoint"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(url: String) = arrayOf(TAG_NAME, url)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,150 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.meetingSpaces.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address
|
||||||
|
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||||
|
import com.vitorpamplona.quartz.utils.bytesUsedInMemory
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
import com.vitorpamplona.quartz.utils.pointerSizeInBytes
|
||||||
|
|
||||||
|
class MeetingSpaceTag(
|
||||||
|
val address: Address,
|
||||||
|
val relayHint: NormalizedRelayUrl? = null,
|
||||||
|
) {
|
||||||
|
fun countMemory(): Long = 2 * pointerSizeInBytes + address.countMemory() + (relayHint?.url?.bytesUsedInMemory() ?: 0)
|
||||||
|
|
||||||
|
fun toTag() = Address.assemble(address.kind, address.pubKeyHex, address.dTag)
|
||||||
|
|
||||||
|
fun toTagArray() = assemble(address, relayHint)
|
||||||
|
|
||||||
|
fun toTagIdOnly() = assemble(address, null)
|
||||||
|
|
||||||
|
companion object Companion {
|
||||||
|
const val TAG_NAME = "a"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isTagged(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isTagged(
|
||||||
|
tag: Array<String>,
|
||||||
|
addressId: String,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isTagged(
|
||||||
|
tag: Array<String>,
|
||||||
|
address: MeetingSpaceTag,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isIn(
|
||||||
|
tag: Array<String>,
|
||||||
|
addressIds: Set<String>,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isTaggedWithKind(
|
||||||
|
tag: Array<String>,
|
||||||
|
kind: String,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && Address.isOfKind(tag[1], kind)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(
|
||||||
|
aTagId: String,
|
||||||
|
relay: String?,
|
||||||
|
) = Address.parse(aTagId)?.let {
|
||||||
|
MeetingSpaceTag(it, relay?.let { RelayUrlNormalizer.normalizeOrNull(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): MeetingSpaceTag? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return parse(tag[1], tag.getOrNull(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parseValidAddress(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return Address.parse(tag[1])?.toValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parseAddress(tag: Array<String>): Address? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return Address.parse(tag[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parseAddressId(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parseAsHint(tag: Array<String>): AddressHint? {
|
||||||
|
ensure(tag.has(2)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
ensure(tag[1].contains(':')) { return null }
|
||||||
|
ensure(tag[2].isNotEmpty()) { return null }
|
||||||
|
|
||||||
|
val relayHint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||||
|
ensure(relayHint != null) { return null }
|
||||||
|
|
||||||
|
return AddressHint(tag[1], relayHint)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(
|
||||||
|
aTagId: HexKey,
|
||||||
|
relay: NormalizedRelayUrl?,
|
||||||
|
) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(
|
||||||
|
address: Address,
|
||||||
|
relay: NormalizedRelayUrl?,
|
||||||
|
) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(
|
||||||
|
kind: Int,
|
||||||
|
pubKey: String,
|
||||||
|
dTag: String,
|
||||||
|
relay: NormalizedRelayUrl?,
|
||||||
|
) = assemble(Address.assemble(kind, pubKey, dTag), relay)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.meetingSpaces.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
class RecordingTag {
|
||||||
|
companion object {
|
||||||
|
const val TAG_NAME = "recording"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(url: String) = arrayOf(TAG_NAME, url)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.meetingSpaces.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
class RelayListTag {
|
||||||
|
companion object {
|
||||||
|
const val TAG_NAME = "relays"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): List<NormalizedRelayUrl>? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
val relays =
|
||||||
|
tag.mapIndexedNotNull { index, s ->
|
||||||
|
if (index == 0) null else RelayUrlNormalizer.normalizeOrNull(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relays.isEmpty()) return null
|
||||||
|
|
||||||
|
return relays
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(urls: List<NormalizedRelayUrl>) = arrayOf(TAG_NAME) + urls.map { it.url }.toTypedArray()
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.meetingSpaces.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
class RoomNameTag {
|
||||||
|
companion object Companion {
|
||||||
|
const val TAG_NAME = "room"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(title: String) = arrayOf(TAG_NAME, title)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.meetingSpaces.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
class ServiceUrlTag {
|
||||||
|
companion object Companion {
|
||||||
|
const val TAG_NAME = "service"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(url: String) = arrayOf(TAG_NAME, url)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.meetingSpaces.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
class StatusTag {
|
||||||
|
enum class STATUS(
|
||||||
|
val code: String,
|
||||||
|
) {
|
||||||
|
OPEN("open"),
|
||||||
|
PRIVATE("private"),
|
||||||
|
CLOSED("closed"),
|
||||||
|
;
|
||||||
|
|
||||||
|
fun toTagArray() = assemble(this)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun parse(code: String): STATUS? =
|
||||||
|
when (code) {
|
||||||
|
STATUS.OPEN.code -> STATUS.OPEN
|
||||||
|
STATUS.PRIVATE.code -> STATUS.PRIVATE
|
||||||
|
STATUS.CLOSED.code -> STATUS.CLOSED
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG_NAME = "status"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parseEnum(tag: Array<String>): STATUS? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return STATUS.parse(tag[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(status: STATUS) = arrayOf(TAG_NAME, status.code)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.presence
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address
|
||||||
|
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.MeetingSpaceTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.presence.tags.HandRaisedTag
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
class MeetingRoomPresenceEvent(
|
||||||
|
id: HexKey,
|
||||||
|
pubKey: HexKey,
|
||||||
|
createdAt: Long,
|
||||||
|
tags: Array<Array<String>>,
|
||||||
|
content: String,
|
||||||
|
sig: HexKey,
|
||||||
|
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||||
|
AddressHintProvider {
|
||||||
|
override fun addressHints(): List<AddressHint> = tags.mapNotNull(MeetingSpaceTag::parseAsHint)
|
||||||
|
|
||||||
|
override fun linkedAddressIds(): List<String> = tags.mapNotNull(MeetingSpaceTag::parseAddressId)
|
||||||
|
|
||||||
|
fun interactiveRoom() = tags.firstNotNullOfOrNull(MeetingSpaceTag::parse)
|
||||||
|
|
||||||
|
fun handRaised() = tags.firstNotNullOfOrNull(HandRaisedTag::parse)
|
||||||
|
|
||||||
|
companion object Companion {
|
||||||
|
const val KIND = 10312
|
||||||
|
const val ALT = "Room Presence tag"
|
||||||
|
|
||||||
|
fun createAddress(
|
||||||
|
pubKey: HexKey,
|
||||||
|
dtag: String,
|
||||||
|
): Address = Address(KIND, pubKey, dtag)
|
||||||
|
|
||||||
|
fun createAddressATag(
|
||||||
|
pubKey: HexKey,
|
||||||
|
dtag: String,
|
||||||
|
): ATag = ATag(KIND, pubKey, dtag, null)
|
||||||
|
|
||||||
|
fun createAddressTag(
|
||||||
|
pubKey: HexKey,
|
||||||
|
dtag: String,
|
||||||
|
): String = Address.assemble(KIND, pubKey, dtag)
|
||||||
|
|
||||||
|
fun build(
|
||||||
|
root: MeetingRoomEvent,
|
||||||
|
handRaised: Boolean?,
|
||||||
|
createdAt: Long = TimeUtils.now(),
|
||||||
|
initializer: TagArrayBuilder<MeetingRoomPresenceEvent>.() -> Unit = {},
|
||||||
|
) = eventTemplate(KIND, "", createdAt) {
|
||||||
|
alt(root.title() ?: ALT)
|
||||||
|
|
||||||
|
roomMeeting(MeetingSpaceTag(root.address(), root.relays().firstOrNull()))
|
||||||
|
|
||||||
|
handRaised?.let {
|
||||||
|
handRaised(it)
|
||||||
|
}
|
||||||
|
initializer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.presence
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingRoomEvent
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.tags.MeetingSpaceTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.presence.tags.HandRaisedTag
|
||||||
|
|
||||||
|
fun TagArrayBuilder<MeetingRoomPresenceEvent>.roomMeeting(rep: MeetingSpaceTag) = addUnique(rep.toTagArray())
|
||||||
|
|
||||||
|
fun TagArrayBuilder<MeetingRoomPresenceEvent>.roomMeeting(rep: EventHintBundle<MeetingRoomEvent>) = addUnique(rep.toATag().toATagArray())
|
||||||
|
|
||||||
|
fun TagArrayBuilder<MeetingRoomPresenceEvent>.handRaised(raised: Boolean) = addUnique(HandRaisedTag.assemble(raised))
|
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.presence.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
class HandRaisedTag {
|
||||||
|
companion object Companion {
|
||||||
|
const val TAG_NAME = "hand"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): Boolean? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1] == "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(handRaised: Boolean) = arrayOf(TAG_NAME, if (handRaised) "1" else "0")
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,150 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.presence.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.AddressHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address
|
||||||
|
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||||
|
import com.vitorpamplona.quartz.utils.bytesUsedInMemory
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
import com.vitorpamplona.quartz.utils.pointerSizeInBytes
|
||||||
|
|
||||||
|
class MeetingRoomTag(
|
||||||
|
val address: Address,
|
||||||
|
val relayHint: NormalizedRelayUrl? = null,
|
||||||
|
) {
|
||||||
|
fun countMemory(): Long = 2 * pointerSizeInBytes + address.countMemory() + (relayHint?.url?.bytesUsedInMemory() ?: 0)
|
||||||
|
|
||||||
|
fun toTag() = Address.assemble(address.kind, address.pubKeyHex, address.dTag)
|
||||||
|
|
||||||
|
fun toTagArray() = assemble(address, relayHint)
|
||||||
|
|
||||||
|
fun toTagIdOnly() = assemble(address, null)
|
||||||
|
|
||||||
|
companion object Companion {
|
||||||
|
const val TAG_NAME = "a"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isTagged(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isTagged(
|
||||||
|
tag: Array<String>,
|
||||||
|
addressId: String,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == addressId
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isTagged(
|
||||||
|
tag: Array<String>,
|
||||||
|
address: MeetingRoomTag,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == address.toTag()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isIn(
|
||||||
|
tag: Array<String>,
|
||||||
|
addressIds: Set<String>,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in addressIds
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isTaggedWithKind(
|
||||||
|
tag: Array<String>,
|
||||||
|
kind: String,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && Address.isOfKind(tag[1], kind)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(
|
||||||
|
aTagId: String,
|
||||||
|
relay: String?,
|
||||||
|
) = Address.parse(aTagId)?.let {
|
||||||
|
MeetingRoomTag(it, relay?.let { RelayUrlNormalizer.normalizeOrNull(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): MeetingRoomTag? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return parse(tag[1], tag.getOrNull(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parseValidAddress(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return Address.parse(tag[1])?.toValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parseAddress(tag: Array<String>): Address? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return Address.parse(tag[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parseAddressId(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parseAsHint(tag: Array<String>): AddressHint? {
|
||||||
|
ensure(tag.has(2)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
ensure(tag[1].contains(':')) { return null }
|
||||||
|
ensure(tag[2].isNotEmpty()) { return null }
|
||||||
|
|
||||||
|
val relayHint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||||
|
ensure(relayHint != null) { return null }
|
||||||
|
|
||||||
|
return AddressHint(tag[1], relayHint)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(
|
||||||
|
aTagId: HexKey,
|
||||||
|
relay: NormalizedRelayUrl?,
|
||||||
|
) = arrayOfNotNull(TAG_NAME, aTagId, relay?.url)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(
|
||||||
|
address: Address,
|
||||||
|
relay: NormalizedRelayUrl?,
|
||||||
|
) = arrayOfNotNull(TAG_NAME, address.toValue(), relay?.url)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(
|
||||||
|
kind: Int,
|
||||||
|
pubKey: String,
|
||||||
|
dTag: String,
|
||||||
|
relay: NormalizedRelayUrl?,
|
||||||
|
) = assemble(Address.assemble(kind, pubKey, dTag), relay)
|
||||||
|
}
|
||||||
|
}
|
@@ -24,13 +24,10 @@ import androidx.compose.runtime.Immutable
|
|||||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.any
|
import com.vitorpamplona.quartz.nip01Core.core.any
|
||||||
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
import com.vitorpamplona.quartz.nip01Core.hints.EventHintProvider
|
||||||
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.tags.events.ETag
|
|
||||||
import com.vitorpamplona.quartz.nip18Reposts.quotes.QTag
|
|
||||||
import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag
|
import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag
|
||||||
import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag
|
import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag
|
||||||
import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag
|
import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag
|
||||||
@@ -38,6 +35,8 @@ import com.vitorpamplona.quartz.nip31Alts.AltTag
|
|||||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.CurrentParticipantsTag
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.CurrentParticipantsTag
|
||||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.EndsTag
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.EndsTag
|
||||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.ParticipantTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.PinnedEventTag
|
||||||
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.RecordingTag
|
||||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.RelayListTag
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.RelayListTag
|
||||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StartsTag
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StartsTag
|
||||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StatusTag
|
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.tags.StatusTag
|
||||||
@@ -55,15 +54,26 @@ class LiveActivitiesEvent(
|
|||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig),
|
||||||
EventHintProvider,
|
EventHintProvider,
|
||||||
AddressHintProvider,
|
|
||||||
PubKeyHintProvider {
|
PubKeyHintProvider {
|
||||||
override fun eventHints() = tags.mapNotNull(ETag::parseAsHint) + tags.mapNotNull(QTag::parseEventAsHint)
|
override fun eventHints(): List<EventIdHint> {
|
||||||
|
val pinnedEvents = pinned()
|
||||||
|
if (pinnedEvents.isEmpty()) return emptyList()
|
||||||
|
|
||||||
override fun linkedEventIds() = tags.mapNotNull(ETag::parseId) + tags.mapNotNull(QTag::parseEventId)
|
val relays = allRelayUrls()
|
||||||
|
|
||||||
override fun addressHints() = tags.mapNotNull(ATag::parseAsHint) + tags.mapNotNull(QTag::parseAddressAsHint)
|
return if (relays.isNotEmpty()) {
|
||||||
|
pinnedEvents
|
||||||
|
.map { eventId ->
|
||||||
|
relays.map { relay ->
|
||||||
|
EventIdHint(eventId, relay)
|
||||||
|
}
|
||||||
|
}.flatten()
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun linkedAddressIds() = tags.mapNotNull(ATag::parseAddressId) + tags.mapNotNull(QTag::parseAddressId)
|
override fun linkedEventIds() = tags.mapNotNull(PinnedEventTag::parse)
|
||||||
|
|
||||||
override fun pubKeyHints() = tags.mapNotNull(ParticipantTag::parseAsHint)
|
override fun pubKeyHints() = tags.mapNotNull(ParticipantTag::parseAsHint)
|
||||||
|
|
||||||
@@ -77,6 +87,8 @@ class LiveActivitiesEvent(
|
|||||||
|
|
||||||
fun streaming() = tags.firstNotNullOfOrNull(StreamingTag::parse)
|
fun streaming() = tags.firstNotNullOfOrNull(StreamingTag::parse)
|
||||||
|
|
||||||
|
fun recording() = tags.firstNotNullOfOrNull(RecordingTag::parse)
|
||||||
|
|
||||||
fun starts() = tags.firstNotNullOfOrNull(StartsTag::parse)
|
fun starts() = tags.firstNotNullOfOrNull(StartsTag::parse)
|
||||||
|
|
||||||
fun ends() = tags.firstNotNullOfOrNull(EndsTag::parse)
|
fun ends() = tags.firstNotNullOfOrNull(EndsTag::parse)
|
||||||
@@ -93,7 +105,7 @@ class LiveActivitiesEvent(
|
|||||||
|
|
||||||
fun participants() = tags.mapNotNull(ParticipantTag::parse)
|
fun participants() = tags.mapNotNull(ParticipantTag::parse)
|
||||||
|
|
||||||
fun relays() = tags.mapNotNull(RelayListTag::parse)
|
fun relays() = tags.mapNotNull(RelayListTag::parse).flatten()
|
||||||
|
|
||||||
fun allRelayUrls() = tags.mapNotNull(RelayListTag::parse).flatten()
|
fun allRelayUrls() = tags.mapNotNull(RelayListTag::parse).flatten()
|
||||||
|
|
||||||
@@ -103,6 +115,8 @@ class LiveActivitiesEvent(
|
|||||||
|
|
||||||
fun hosts() = tags.mapNotNull(ParticipantTag::parseHost)
|
fun hosts() = tags.mapNotNull(ParticipantTag::parseHost)
|
||||||
|
|
||||||
|
fun pinned() = tags.mapNotNull(PinnedEventTag::parse)
|
||||||
|
|
||||||
fun checkStatus(eventStatus: StatusTag.STATUS?): StatusTag.STATUS? =
|
fun checkStatus(eventStatus: StatusTag.STATUS?): StatusTag.STATUS? =
|
||||||
if (eventStatus == StatusTag.STATUS.LIVE && createdAt < TimeUtils.eightHoursAgo()) {
|
if (eventStatus == StatusTag.STATUS.LIVE && createdAt < TimeUtils.eightHoursAgo()) {
|
||||||
StatusTag.STATUS.ENDED
|
StatusTag.STATUS.ENDED
|
||||||
|
@@ -35,6 +35,7 @@ enum class ROLE(
|
|||||||
val code: String,
|
val code: String,
|
||||||
) {
|
) {
|
||||||
HOST("host"),
|
HOST("host"),
|
||||||
|
MODERATOR("moderator"),
|
||||||
SPEAKER("speaker"),
|
SPEAKER("speaker"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.streaming.tags
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Tag
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
class PinnedEventTag {
|
||||||
|
companion object {
|
||||||
|
const val TAG_NAME = "pinned"
|
||||||
|
|
||||||
|
fun isIn(
|
||||||
|
tag: Array<String>,
|
||||||
|
eventIds: Set<HexKey>,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in eventIds
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Tag): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].length == 64) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(eventId: HexKey) = arrayOfNotNull(TAG_NAME, eventId)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* 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.nip53LiveActivities.streaming.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
class RecordingTag {
|
||||||
|
companion object {
|
||||||
|
const val TAG_NAME = "recording"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parse(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].isNotEmpty()) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun assemble(url: String) = arrayOf(TAG_NAME, url)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user