mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
feat(home): request pictures and every NIP-71 video kind on all home legs
The "All Follows" home feed fans out to four REQ builders — authors, hashtags, geohashes and communities. Only the authors leg asked for pictures (kind 20) and the NIP-71 videos (21, 22, 34235, 34236); the other three stopped at text notes, articles, classifieds, highlights, wiki and friends. HomeNewThreadFeedFilter already accepts all of those kinds, and AllFollowsTopNavFilter.match() already matches an event by a followed hashtag, geohash or community, so the events would have rendered fine — they were simply never requested. A kind-22 short tagged #bitcoin never reached Home while a kind-1 with the same tag did. Adds the five media kinds to HomePostsBuHashtagsKinds, HomePostsByGeohashKinds and HomePostsFromCommunityKinds, and derives HomePostsFromCommunityKindsStr (the `k` tag values on a NIP-72 post approval) from the kind list instead of repeating it by hand, so the two cannot drift apart again. Kinds 34235/34236 are current NIP-71 kinds, not deprecated ones — drops the "legacy" framing from the comments that described them that way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019V3yENZpF2eTDSzjnj1ZCi
This commit is contained in:
+3
-3
@@ -186,7 +186,7 @@ class NostrSignerPermissionLedger(
|
|||||||
* delete afterwards, in the same risk class as the original kind 1/6/7 set (notes, reposts,
|
* delete afterwards, in the same risk class as the original kind 1/6/7 set (notes, reposts,
|
||||||
* reactions, pictures, videos, voice, public/live/relay chat, threads, polls, comments,
|
* reactions, pictures, videos, voice, public/live/relay chat, threads, polls, comments,
|
||||||
* highlights, code snippets, file metadata, reports, torrents, long-form articles, wiki, status).
|
* highlights, code snippets, file metadata, reports, torrents, long-form articles, wiki, status).
|
||||||
* Some are *addressable* (long-form 30023, wiki 30818, legacy video 34235/34236): re-signing
|
* Some are *addressable* (long-form 30023, wiki 30818, video 34235/34236): re-signing
|
||||||
* with the same `d` tag replaces the app's own prior version at that address — an accepted
|
* with the same `d` tag replaces the app's own prior version at that address — an accepted
|
||||||
* trade-off, since an app that can already post arbitrary notes could do equal reputational harm.
|
* trade-off, since an app that can already post arbitrary notes could do equal reputational harm.
|
||||||
* The set also includes two harmless non-content signatures:
|
* The set also includes two harmless non-content signatures:
|
||||||
@@ -247,8 +247,8 @@ class NostrSignerPermissionLedger(
|
|||||||
LongTextNoteEvent.KIND, // 30023 — NIP-23 long-form articles (addressable content)
|
LongTextNoteEvent.KIND, // 30023 — NIP-23 long-form articles (addressable content)
|
||||||
StatusEvent.KIND, // 30315 — ephemeral user status / presence
|
StatusEvent.KIND, // 30315 — ephemeral user status / presence
|
||||||
WikiNoteEvent.KIND, // 30818 — NIP-54 wiki articles (addressable content)
|
WikiNoteEvent.KIND, // 30818 — NIP-54 wiki articles (addressable content)
|
||||||
VideoHorizontalEvent.KIND, // 34235 — legacy addressable horizontal video (NIP-71)
|
VideoHorizontalEvent.KIND, // 34235 — addressable horizontal video (NIP-71)
|
||||||
VideoVerticalEvent.KIND, // 34236 — legacy addressable vertical video (NIP-71)
|
VideoVerticalEvent.KIND, // 34236 — addressable vertical video (NIP-71)
|
||||||
PublicationIndexEvent.KIND, // 30040 — NKBIP-01 publication index (addressable content)
|
PublicationIndexEvent.KIND, // 30040 — NKBIP-01 publication index (addressable content)
|
||||||
LearningResourceEvent.KIND, // 30142 — learning resources (addressable content)
|
LearningResourceEvent.KIND, // 30142 — learning resources (addressable content)
|
||||||
BlossomPieceIndexEvent.KIND, // 32176 — Blossom piece indexes (addressable content)
|
BlossomPieceIndexEvent.KIND, // 32176 — Blossom piece indexes (addressable content)
|
||||||
|
|||||||
+10
@@ -35,6 +35,11 @@ import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
|
|||||||
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
||||||
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
||||||
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
||||||
|
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.nip84Highlights.HighlightEvent
|
import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent
|
||||||
import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent
|
import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent
|
||||||
import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent
|
import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent
|
||||||
@@ -52,6 +57,11 @@ val HomePostsByGeohashKinds =
|
|||||||
VoiceEvent.KIND,
|
VoiceEvent.KIND,
|
||||||
AttestationEvent.KIND,
|
AttestationEvent.KIND,
|
||||||
InteractiveStoryPrologueEvent.KIND,
|
InteractiveStoryPrologueEvent.KIND,
|
||||||
|
PictureEvent.KIND,
|
||||||
|
VideoNormalEvent.KIND,
|
||||||
|
VideoShortEvent.KIND,
|
||||||
|
VideoHorizontalEvent.KIND,
|
||||||
|
VideoVerticalEvent.KIND,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun filterHomePostsByGeohashes(
|
fun filterHomePostsByGeohashes(
|
||||||
|
|||||||
+10
@@ -38,6 +38,11 @@ import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
|
|||||||
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
||||||
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
||||||
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
||||||
|
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.nip84Highlights.HighlightEvent
|
import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent
|
||||||
import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent
|
import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent
|
||||||
import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent
|
import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent
|
||||||
@@ -57,6 +62,11 @@ val HomePostsBuHashtagsKinds =
|
|||||||
VoiceEvent.KIND,
|
VoiceEvent.KIND,
|
||||||
AttestationEvent.KIND,
|
AttestationEvent.KIND,
|
||||||
InteractiveStoryPrologueEvent.KIND,
|
InteractiveStoryPrologueEvent.KIND,
|
||||||
|
PictureEvent.KIND,
|
||||||
|
VideoNormalEvent.KIND,
|
||||||
|
VideoShortEvent.KIND,
|
||||||
|
VideoHorizontalEvent.KIND,
|
||||||
|
VideoVerticalEvent.KIND,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun filterHomePostsByHashtags(
|
fun filterHomePostsByHashtags(
|
||||||
|
|||||||
+12
-13
@@ -32,6 +32,11 @@ import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
|||||||
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
import com.vitorpamplona.quartz.nip22Comments.CommentEvent
|
||||||
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
||||||
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
import com.vitorpamplona.quartz.nip54Wiki.WikiNoteEvent
|
||||||
|
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.approval.CommunityPostApprovalEvent
|
||||||
import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent
|
import com.vitorpamplona.quartz.nip84Highlights.HighlightEvent
|
||||||
import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
|
import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
|
||||||
@@ -49,21 +54,15 @@ val HomePostsFromCommunityKinds =
|
|||||||
CommunityPostApprovalEvent.KIND,
|
CommunityPostApprovalEvent.KIND,
|
||||||
CommentEvent.KIND,
|
CommentEvent.KIND,
|
||||||
InteractiveStoryPrologueEvent.KIND,
|
InteractiveStoryPrologueEvent.KIND,
|
||||||
|
PictureEvent.KIND,
|
||||||
|
VideoNormalEvent.KIND,
|
||||||
|
VideoShortEvent.KIND,
|
||||||
|
VideoHorizontalEvent.KIND,
|
||||||
|
VideoVerticalEvent.KIND,
|
||||||
)
|
)
|
||||||
|
|
||||||
val HomePostsFromCommunityKindsStr =
|
/** The same set, as the `k` tag values a NIP-72 post approval carries. */
|
||||||
listOf(
|
val HomePostsFromCommunityKindsStr = HomePostsFromCommunityKinds.map { it.toString() }
|
||||||
TextNoteEvent.KIND.toString(),
|
|
||||||
LongTextNoteEvent.KIND.toString(),
|
|
||||||
ClassifiedsEvent.KIND.toString(),
|
|
||||||
HighlightEvent.KIND.toString(),
|
|
||||||
PollEvent.KIND.toString(),
|
|
||||||
WikiNoteEvent.KIND.toString(),
|
|
||||||
NipTextEvent.KIND.toString(),
|
|
||||||
CommunityPostApprovalEvent.KIND.toString(),
|
|
||||||
CommentEvent.KIND.toString(),
|
|
||||||
InteractiveStoryPrologueEvent.KIND.toString(),
|
|
||||||
)
|
|
||||||
|
|
||||||
fun filterHomePostsFromCommunity(
|
fun filterHomePostsFromCommunity(
|
||||||
relay: NormalizedRelayUrl,
|
relay: NormalizedRelayUrl,
|
||||||
|
|||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.amethyst.commons.relayClient.home
|
||||||
|
|
||||||
|
import com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core.HomePostsBuHashtagsKinds
|
||||||
|
import com.vitorpamplona.amethyst.commons.relayClient.home.nip01Core.HomePostsByGeohashKinds
|
||||||
|
import com.vitorpamplona.amethyst.commons.relayClient.home.nip65Follows.HomePostsNewThreadKinds1
|
||||||
|
import com.vitorpamplona.amethyst.commons.relayClient.home.nip72Communities.HomePostsFromCommunityKinds
|
||||||
|
import com.vitorpamplona.amethyst.commons.relayClient.home.nip72Communities.HomePostsFromCommunityKindsStr
|
||||||
|
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 kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "All Follows" home feed fans out to four REQ builders: authors, hashtags, geohashes and
|
||||||
|
* communities. The home DAL renders pictures and every NIP-71 video kind from any of those legs,
|
||||||
|
* so a leg that omits a media kind silently hides content the feed would happily show — a
|
||||||
|
* kind-22 short tagged `#bitcoin` never arriving while a kind-1 with the same tag does.
|
||||||
|
*/
|
||||||
|
class HomeMediaKindCoverageTest {
|
||||||
|
private val mediaKinds =
|
||||||
|
listOf(
|
||||||
|
PictureEvent.KIND,
|
||||||
|
VideoNormalEvent.KIND,
|
||||||
|
VideoShortEvent.KIND,
|
||||||
|
VideoHorizontalEvent.KIND,
|
||||||
|
VideoVerticalEvent.KIND,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun assertCarriesMedia(
|
||||||
|
legName: String,
|
||||||
|
kinds: List<Int>,
|
||||||
|
) = mediaKinds.forEach {
|
||||||
|
assertTrue(it in kinds, "$legName must request kind $it")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun everyHomeLegRequestsPicturesAndAllVideoKinds() {
|
||||||
|
assertCarriesMedia("authors", HomePostsNewThreadKinds1)
|
||||||
|
assertCarriesMedia("hashtags", HomePostsBuHashtagsKinds)
|
||||||
|
assertCarriesMedia("geohashes", HomePostsByGeohashKinds)
|
||||||
|
assertCarriesMedia("communities", HomePostsFromCommunityKinds)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun communityApprovalKTagsMirrorTheCommunityKinds() {
|
||||||
|
assertEquals(HomePostsFromCommunityKinds.map { it.toString() }, HomePostsFromCommunityKindsStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -25,7 +25,7 @@ import kotlin.test.Test
|
|||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kinds 34235/34236 (legacy NIP-71 videos) are parameterized replaceable
|
* Kinds 34235/34236 (the addressable NIP-71 videos) are parameterized replaceable
|
||||||
* events: their address MUST include the `d` tag. A wrong (empty-dTag)
|
* events: their address MUST include the `d` tag. A wrong (empty-dTag)
|
||||||
* address makes LocalCache consume the event into a different
|
* address makes LocalCache consume the event into a different
|
||||||
* AddressableNote than the one `a` tags point to, so quotes/reposts of
|
* AddressableNote than the one `a` tags point to, so quotes/reposts of
|
||||||
|
|||||||
Reference in New Issue
Block a user