Browse Source

fix minified error

add replaceable media kinds
imwald
Silberengel 23 hours ago
parent
commit
74ab84f0dd
  1. 16
      package-lock.json
  2. 2
      package.json
  3. 4
      src/components/ContentPreview/index.tsx
  4. 4
      src/components/KindFilter/index.tsx
  5. 5
      src/components/LatestFromFollowsSection/index.tsx
  6. 4
      src/components/MediaGridItem/index.tsx
  7. 9
      src/components/NormalFeed/index.tsx
  8. 6
      src/components/Note/Highlight/index.tsx
  9. 4
      src/components/Note/index.tsx
  10. 2
      src/components/NoteList/index.tsx
  11. 17
      src/components/PostEditor/PostContent.tsx
  12. 2
      src/components/WebPreview/index.tsx
  13. 29
      src/constants.ts
  14. 2
      src/lib/draft-event.ts
  15. 4
      src/lib/kind-description.ts
  16. 14
      src/lib/wisp-trending-relay.ts
  17. 13
      src/pages/primary/NoteListPage/RelaysFeed.tsx
  18. 4
      src/pages/secondary/NotePage/index.tsx
  19. 5
      src/providers/FavoriteRelaysActivityProvider.tsx
  20. 7
      src/services/event-archive.service.ts
  21. 16
      src/services/local-storage.service.ts
  22. 7
      src/services/mention-event-search.service.ts
  23. 2
      src/services/nip89.service.ts

16
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "imwald", "name": "imwald",
"version": "23.1.2", "version": "23.3.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "imwald", "name": "imwald",
"version": "23.1.2", "version": "23.3.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@asciidoctor/core": "^3.0.4", "@asciidoctor/core": "^3.0.4",
@ -6679,9 +6679,9 @@
} }
}, },
"node_modules/@xmldom/xmldom": { "node_modules/@xmldom/xmldom": {
"version": "0.8.12", "version": "0.8.13",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.12.tgz", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz",
"integrity": "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==", "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==",
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"engines": { "engines": {
@ -12498,9 +12498,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.5.8", "version": "8.5.13",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.13.tgz",
"integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "integrity": "sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "imwald", "name": "imwald",
"version": "23.2.0", "version": "23.3.0",
"description": "Imwald — a user-friendly Nostr client focused on relay feed browsing, publications, and relay discovery", "description": "Imwald — a user-friendly Nostr client focused on relay feed browsing, publications, and relay discovery",
"private": true, "private": true,
"type": "module", "type": "module",

4
src/components/ContentPreview/index.tsx

@ -1,5 +1,5 @@
import { Skeleton } from '@/components/ui/skeleton' import { Skeleton } from '@/components/ui/skeleton'
import { ExtendedKind } from '@/constants' import { ExtendedKind, isNip71StyleVideoKind } from '@/constants'
import { import {
notificationReactionSummaryKey, notificationReactionSummaryKey,
useNotificationReactionDisplay useNotificationReactionDisplay
@ -184,7 +184,7 @@ export default function ContentPreview({
return withKindRow(<LongFormArticlePreview event={previewEvent} />) return withKindRow(<LongFormArticlePreview event={previewEvent} />)
} }
if (event.kind === ExtendedKind.VIDEO || event.kind === ExtendedKind.SHORT_VIDEO) { if (isNip71StyleVideoKind(event.kind)) {
return withKindRow(<VideoNotePreview event={previewEvent} />) return withKindRow(<VideoNotePreview event={previewEvent} />)
} }

4
src/components/KindFilter/index.tsx

@ -4,7 +4,7 @@ import { Switch } from '@/components/ui/switch'
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer' import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { ExtendedKind, PROFILE_FEED_KINDS } from '@/constants' import { ExtendedKind, NIP71_VIDEO_KINDS, PROFILE_FEED_KINDS } from '@/constants'
import { LIVE_ACTIVITY_KINDS } from '@/lib/live-activities' import { LIVE_ACTIVITY_KINDS } from '@/lib/live-activities'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { useKindFilter } from '@/providers/KindFilterProvider' import { useKindFilter } from '@/providers/KindFilterProvider'
@ -24,7 +24,7 @@ const KIND_FILTER_OPTIONS = [
{ kindGroup: [ExtendedKind.ZAP_POLL], label: 'Zap polls' }, { kindGroup: [ExtendedKind.ZAP_POLL], label: 'Zap polls' },
{ kindGroup: [ExtendedKind.VOICE, ExtendedKind.VOICE_COMMENT], label: 'Voice Posts' }, { kindGroup: [ExtendedKind.VOICE, ExtendedKind.VOICE_COMMENT], label: 'Voice Posts' },
{ kindGroup: [ExtendedKind.PICTURE], label: 'Photo Posts' }, { kindGroup: [ExtendedKind.PICTURE], label: 'Photo Posts' },
{ kindGroup: [ExtendedKind.VIDEO, ExtendedKind.SHORT_VIDEO], label: 'Video Posts' }, { kindGroup: [...NIP71_VIDEO_KINDS], label: 'Video Posts' },
{ kindGroup: [ExtendedKind.DISCUSSION], label: 'Discussions' }, { kindGroup: [ExtendedKind.DISCUSSION], label: 'Discussions' },
{ kindGroup: [ExtendedKind.CALENDAR_EVENT_DATE, ExtendedKind.CALENDAR_EVENT_TIME], label: 'Calendar Events' }, { kindGroup: [ExtendedKind.CALENDAR_EVENT_DATE, ExtendedKind.CALENDAR_EVENT_TIME], label: 'Calendar Events' },
{ kindGroup: [...LIVE_ACTIVITY_KINDS], label: 'Live streams' }, { kindGroup: [...LIVE_ACTIVITY_KINDS], label: 'Live streams' },

5
src/components/LatestFromFollowsSection/index.tsx

@ -1,7 +1,7 @@
import NoteCard from '@/components/NoteCard' import NoteCard from '@/components/NoteCard'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible' import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
import { Skeleton } from '@/components/ui/skeleton' import { Skeleton } from '@/components/ui/skeleton'
import { ExtendedKind } from '@/constants' import { ExtendedKind, NIP71_VIDEO_KINDS } from '@/constants'
import { buildFollowOutboxAggregateReadUrls } from '@/lib/follow-outbox-aggregate-relays' import { buildFollowOutboxAggregateReadUrls } from '@/lib/follow-outbox-aggregate-relays'
import { import {
buildSearchFollowsFeedScopeKey, buildSearchFollowsFeedScopeKey,
@ -52,8 +52,7 @@ const FEED_KINDS = [
kinds.LongFormArticle, kinds.LongFormArticle,
kinds.Highlights, kinds.Highlights,
ExtendedKind.PICTURE, ExtendedKind.PICTURE,
ExtendedKind.VIDEO, ...NIP71_VIDEO_KINDS,
ExtendedKind.SHORT_VIDEO,
ExtendedKind.COMMENT, ExtendedKind.COMMENT,
kinds.Repost, kinds.Repost,
ExtendedKind.GENERIC_REPOST ExtendedKind.GENERIC_REPOST

4
src/components/MediaGridItem/index.tsx

@ -1,3 +1,4 @@
import { isNip71StyleVideoKind } from '@/constants'
import { getCachedThreadContextEvents } from '@/lib/navigation-related-events' import { getCachedThreadContextEvents } from '@/lib/navigation-related-events'
import { toNote } from '@/lib/link' import { toNote } from '@/lib/link'
import client from '@/services/client.service' import client from '@/services/client.service'
@ -13,8 +14,7 @@ export default function MediaGridItem({ event }: { event: Event }) {
const media = useMemo(() => extractAllMediaFromEvent(event), [event]) const media = useMemo(() => extractAllMediaFromEvent(event), [event])
const first = media.all[0] const first = media.all[0]
const isVideo = const isVideo = first?.m?.startsWith('video/') || isNip71StyleVideoKind(event.kind)
first?.m?.startsWith('video/') || event.kind === 21 || event.kind === 22
const isAudio = first?.m?.startsWith('audio/') || event.kind === 1222 const isAudio = first?.m?.startsWith('audio/') || event.kind === 1222
const hasMultiple = media.all.length > 1 const hasMultiple = media.all.length > 1

9
src/components/NormalFeed/index.tsx

@ -4,6 +4,7 @@ import Tabs, { TabDefinition } from '@/components/Tabs'
import { useKindFilter } from '@/providers/KindFilterProvider' import { useKindFilter } from '@/providers/KindFilterProvider'
import { useUserTrust } from '@/contexts/user-trust-context' import { useUserTrust } from '@/contexts/user-trust-context'
import storage from '@/services/local-storage.service' import storage from '@/services/local-storage.service'
import { PROFILE_MEDIA_TAB_KINDS } from '@/constants'
import type { TPrimaryPageName } from '@/PageManager' import type { TPrimaryPageName } from '@/PageManager'
import { TFeedSubRequest, TNoteListMode } from '@/types' import { TFeedSubRequest, TNoteListMode } from '@/types'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
@ -116,10 +117,10 @@ const NormalFeed = forwardRef<TNoteListRef, {
const noteListRef = ref || internalNoteListRef const noteListRef = ref || internalNoteListRef
const [feedFilterTabRowHost, setFeedFilterTabRowHost] = useState<HTMLDivElement | null>(null) const [feedFilterTabRowHost, setFeedFilterTabRowHost] = useState<HTMLDivElement | null>(null)
const onFeedFilterTabRowSlotRef = useCallback((node: HTMLDivElement | null) => { const onFeedFilterTabRowSlotRef = useCallback((node: HTMLDivElement | null) => {
setFeedFilterTabRowHost(node) setFeedFilterTabRowHost((prev) => (Object.is(prev, node) ? prev : node))
}, []) }, [])
const MEDIA_KINDS = useMemo(() => [20, 21, 22, 1222], []) const MEDIA_KINDS = useMemo(() => [...PROFILE_MEDIA_TAB_KINDS], [])
const tabs = useMemo( const tabs = useMemo(
(): TabDefinition[] => { (): TabDefinition[] => {
@ -224,6 +225,9 @@ const NormalFeed = forwardRef<TNoteListRef, {
setSubHeader(tabsElement) setSubHeader(tabsElement)
} }
return () => setSubHeader(null) return () => setSubHeader(null)
// Intentionally omit `tabsElement`: same semantics are covered by listMode + subHeaderFilterDepsKey.
// Listing tabsElement here can retrigger the effect every render if its useMemo input references churn,
// which calls setSubHeader repeatedly → parent state → maximum update depth (#185).
}, [ }, [
isMainFeed, isMainFeed,
setSubHeader, setSubHeader,
@ -232,7 +236,6 @@ const NormalFeed = forwardRef<TNoteListRef, {
onSubHeaderRefresh, onSubHeaderRefresh,
allowKindlessRelayExplore, allowKindlessRelayExplore,
mergeFilterWithTabsRow, mergeFilterWithTabsRow,
tabsElement,
onFeedFilterTabRowSlotRef onFeedFilterTabRowSlotRef
]) ])

6
src/components/Note/Highlight/index.tsx

@ -279,8 +279,10 @@ export default function Highlight({
kinds.LongFormArticle, // 30023 — long-form preview card kinds.LongFormArticle, // 30023 — long-form preview card
ExtendedKind.POLL, // Has PollPreview ExtendedKind.POLL, // Has PollPreview
ExtendedKind.DISCUSSION, // Has DiscussionNote ExtendedKind.DISCUSSION, // Has DiscussionNote
ExtendedKind.VIDEO, // Has VideoNotePreview ExtendedKind.VIDEO,
ExtendedKind.SHORT_VIDEO, // Has VideoNotePreview ExtendedKind.SHORT_VIDEO,
ExtendedKind.VIDEO_ADDRESSABLE,
ExtendedKind.SHORT_VIDEO_ADDRESSABLE, // NIP-71 addressable; same VideoNotePreview path as 21/22
ExtendedKind.PICTURE, // Has PictureNotePreview ExtendedKind.PICTURE, // Has PictureNotePreview
ExtendedKind.PUBLICATION, // Has PublicationCard ExtendedKind.PUBLICATION, // Has PublicationCard
ExtendedKind.WIKI_ARTICLE, // Has special card ExtendedKind.WIKI_ARTICLE, // Has special card

4
src/components/Note/index.tsx

@ -1,5 +1,5 @@
import { useSmartNoteNavigationOptional } from '@/PageManager' import { useSmartNoteNavigationOptional } from '@/PageManager'
import { ExtendedKind, publicAssetUrl } from '@/constants' import { ExtendedKind, isNip71StyleVideoKind, publicAssetUrl } from '@/constants'
import { isRenderableNoteKind } from '@/lib/note-renderable-kinds' import { isRenderableNoteKind } from '@/lib/note-renderable-kinds'
import { import {
getHttpUrlFromITags, getHttpUrlFromITags,
@ -358,7 +358,7 @@ export default function Note({
) )
} else if (event.kind === ExtendedKind.PICTURE) { } else if (event.kind === ExtendedKind.PICTURE) {
content = <PictureNote className="mt-2" event={event} /> content = <PictureNote className="mt-2" event={event} />
} else if (event.kind === ExtendedKind.VIDEO || event.kind === ExtendedKind.SHORT_VIDEO) { } else if (isNip71StyleVideoKind(event.kind)) {
content = <VideoNote className="mt-2" event={event} /> content = <VideoNote className="mt-2" event={event} />
} else if (event.kind === ExtendedKind.RELAY_REVIEW) { } else if (event.kind === ExtendedKind.RELAY_REVIEW) {
content = <RelayReview className="mt-2" event={displayEvent} /> content = <RelayReview className="mt-2" event={displayEvent} />

2
src/components/NoteList/index.tsx

@ -1786,7 +1786,7 @@ const NoteList = forwardRef(
...(rawTotal === 0 ...(rawTotal === 0
? { ? {
emptyHint: emptyHint:
'All sub-batches returned 0 events: relays may not index these kinds for this author, the query may have timed out before slow relays EOSEd, or posts are kind 1 with links (this tab uses kinds 20/21/22/1222 only).' 'All sub-batches returned 0 events: relays may not index these kinds for this author, the query may have timed out before slow relays EOSEd, or posts are kind 1 with links (this tab uses native media kinds only: picture, NIP-71 video regular/addressable, voice).'
} }
: {}) : {})
}) })

17
src/components/PostEditor/PostContent.tsx

@ -37,7 +37,12 @@ import {
collectUploadImetaTagsForContentUrls, collectUploadImetaTagsForContentUrls,
mergeUploadImetaTagsInto mergeUploadImetaTagsInto
} from '@/lib/draft-event' } from '@/lib/draft-event'
import { ExtendedKind, MAX_PUBLISH_RELAYS } from '@/constants' import {
ExtendedKind,
isNip71ShortVideoKind,
isNip71StyleVideoKind,
MAX_PUBLISH_RELAYS
} from '@/constants'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import { useFeed } from '@/providers/FeedProvider' import { useFeed } from '@/providers/FeedProvider'
@ -878,7 +883,7 @@ export default function PostContent({
mediaImetaTags: uploadImetaTagsOpt mediaImetaTags: uploadImetaTagsOpt
} }
) )
} else if (mediaNoteKind === ExtendedKind.VIDEO || mediaNoteKind === ExtendedKind.SHORT_VIDEO) { } else if (isNip71StyleVideoKind(mediaNoteKind)) {
return await createVideoDraftEvent( return await createVideoDraftEvent(
cleanedText, cleanedText,
mediaImetaTags, mediaImetaTags,
@ -1927,7 +1932,7 @@ export default function PostContent({
} else if (/\.mp4$/i.test(fileName)) { } else if (/\.mp4$/i.test(fileName)) {
mimeType = 'audio/mp4' mimeType = 'audio/mp4'
} }
} else if (kindHint === ExtendedKind.VIDEO || kindHint === ExtendedKind.SHORT_VIDEO) { } else if (isNip71StyleVideoKind(kindHint)) {
const fileName = uploadingFile.name.toLowerCase() const fileName = uploadingFile.name.toLowerCase()
if (/\.webm$/i.test(fileName)) { if (/\.webm$/i.test(fileName)) {
mimeType = 'video/webm' mimeType = 'video/webm'
@ -2321,10 +2326,8 @@ export default function PostContent({
return t('Voice Note') return t('Voice Note')
} else if (determinedKind === ExtendedKind.PICTURE) { } else if (determinedKind === ExtendedKind.PICTURE) {
return t('Picture Note') return t('Picture Note')
} else if (determinedKind === ExtendedKind.VIDEO) { } else if (isNip71StyleVideoKind(determinedKind)) {
return t('Video Note') return isNip71ShortVideoKind(determinedKind) ? t('Short Video Note') : t('Video Note')
} else if (determinedKind === ExtendedKind.SHORT_VIDEO) {
return t('Short Video Note')
} else if (determinedKind === ExtendedKind.POLL) { } else if (determinedKind === ExtendedKind.POLL) {
return t('New Poll') return t('New Poll')
} else if (determinedKind === ExtendedKind.PUBLIC_MESSAGE) { } else if (determinedKind === ExtendedKind.PUBLIC_MESSAGE) {

2
src/components/WebPreview/index.tsx

@ -34,8 +34,10 @@ function getEventTypeName(kind: number): string {
case ExtendedKind.PICTURE: case ExtendedKind.PICTURE:
return 'Picture' return 'Picture'
case ExtendedKind.VIDEO: case ExtendedKind.VIDEO:
case ExtendedKind.VIDEO_ADDRESSABLE:
return 'Video' return 'Video'
case ExtendedKind.SHORT_VIDEO: case ExtendedKind.SHORT_VIDEO:
case ExtendedKind.SHORT_VIDEO_ADDRESSABLE:
return 'Short Video' return 'Short Video'
case ExtendedKind.POLL: case ExtendedKind.POLL:
return 'Poll' return 'Poll'

29
src/constants.ts

@ -447,6 +447,10 @@ export const ExtendedKind = {
PICTURE: 20, PICTURE: 20,
VIDEO: 21, VIDEO: 21,
SHORT_VIDEO: 22, SHORT_VIDEO: 22,
/** NIP-71: addressable normal video (same rendering as {@link ExtendedKind.VIDEO}). */
VIDEO_ADDRESSABLE: 34235,
/** NIP-71: addressable short video (same rendering as {@link ExtendedKind.SHORT_VIDEO}). */
SHORT_VIDEO_ADDRESSABLE: 34236,
POLL: 1068, POLL: 1068,
/** NIP-B9 zap poll (paid votes via zaps). */ /** NIP-B9 zap poll (paid votes via zaps). */
ZAP_POLL: 6969, ZAP_POLL: 6969,
@ -538,6 +542,26 @@ export function isUnsignedExperimentalKind(kind: number): boolean {
return kind >= UNSIGNED_EXPERIMENTAL_KIND_MIN && kind <= UNSIGNED_EXPERIMENTAL_KIND_MAX return kind >= UNSIGNED_EXPERIMENTAL_KIND_MIN && kind <= UNSIGNED_EXPERIMENTAL_KIND_MAX
} }
/** NIP-71 regular + addressable video kinds (21, 22, 34235, 34236). */
export const NIP71_VIDEO_KINDS: readonly number[] = [
ExtendedKind.VIDEO,
ExtendedKind.SHORT_VIDEO,
ExtendedKind.VIDEO_ADDRESSABLE,
ExtendedKind.SHORT_VIDEO_ADDRESSABLE
]
const NIP71_VIDEO_KIND_SET = new Set<number>(NIP71_VIDEO_KINDS)
/** True for NIP-71 normal/short video events (regular or addressable). */
export function isNip71StyleVideoKind(kind: number): boolean {
return NIP71_VIDEO_KIND_SET.has(kind)
}
/** Short-form portrait-style bucket (kind 22 or 34236). */
export function isNip71ShortVideoKind(kind: number): boolean {
return kind === ExtendedKind.SHORT_VIDEO || kind === ExtendedKind.SHORT_VIDEO_ADDRESSABLE
}
/** Max kind for signed “custom event” notes in the generic composer (below the unsigned experimental range). */ /** Max kind for signed “custom event” notes in the generic composer (below the unsigned experimental range). */
export const MAX_SIGNED_CUSTOM_EVENT_KIND = 40000 export const MAX_SIGNED_CUSTOM_EVENT_KIND = 40000
@ -695,6 +719,8 @@ export const SUPPORTED_KINDS = [
ExtendedKind.PICTURE, ExtendedKind.PICTURE,
ExtendedKind.VIDEO, ExtendedKind.VIDEO,
ExtendedKind.SHORT_VIDEO, ExtendedKind.SHORT_VIDEO,
ExtendedKind.VIDEO_ADDRESSABLE,
ExtendedKind.SHORT_VIDEO_ADDRESSABLE,
ExtendedKind.POLL, ExtendedKind.POLL,
ExtendedKind.ZAP_POLL, ExtendedKind.ZAP_POLL,
ExtendedKind.COMMENT, ExtendedKind.COMMENT,
@ -748,8 +774,7 @@ const PROFILE_PUBLICATIONS_TAB_KIND_SET = new Set<number>(PROFILE_PUBLICATIONS_T
/** NIP native media kinds for the profile Media tab (and Spells → media faux spell). */ /** NIP native media kinds for the profile Media tab (and Spells → media faux spell). */
export const PROFILE_MEDIA_TAB_KINDS: readonly number[] = [ export const PROFILE_MEDIA_TAB_KINDS: readonly number[] = [
ExtendedKind.PICTURE, ExtendedKind.PICTURE,
ExtendedKind.VIDEO, ...NIP71_VIDEO_KINDS,
ExtendedKind.SHORT_VIDEO,
ExtendedKind.VOICE ExtendedKind.VOICE
] ]

2
src/lib/draft-event.ts

@ -1951,7 +1951,7 @@ export async function createVideoDraftEvent(
content: string, content: string,
imetaTags: string[][], imetaTags: string[][],
mentions: string[], mentions: string[],
videoKind: number, // 21 or 22 videoKind: number, // 21, 22, 34235, or 34236 (NIP-71)
options: { options: {
title?: string title?: string
addClientTag?: boolean addClientTag?: boolean

4
src/lib/kind-description.ts

@ -36,6 +36,10 @@ export function getKindDescription(
return { number: 21, description: 'Video Note' } return { number: 21, description: 'Video Note' }
case ExtendedKind.SHORT_VIDEO: case ExtendedKind.SHORT_VIDEO:
return { number: 22, description: 'Short Video Note' } return { number: 22, description: 'Short Video Note' }
case ExtendedKind.VIDEO_ADDRESSABLE:
return { number: 34235, description: 'Video Note (addressable)' }
case ExtendedKind.SHORT_VIDEO_ADDRESSABLE:
return { number: 34236, description: 'Short Video Note (addressable)' }
case kinds.LongFormArticle: case kinds.LongFormArticle:
return { number: 30023, description: 'Long-form Article' } return { number: 30023, description: 'Long-form Article' }
case ExtendedKind.WIKI_ARTICLE: case ExtendedKind.WIKI_ARTICLE:

14
src/lib/wisp-trending-relay.ts

@ -1,3 +1,4 @@
import { ExtendedKind } from '@/constants'
import { normalizeUrl } from '@/lib/url' import { normalizeUrl } from '@/lib/url'
/** /**
@ -17,7 +18,18 @@ export function buildWispTrendingNotesRelayUrl(
} }
/** Wisp `FeedSubscriptionManager` FEED_KINDS when subscribing to trending notes. */ /** Wisp `FeedSubscriptionManager` FEED_KINDS when subscribing to trending notes. */
export const WISP_TRENDING_FEED_KINDS: readonly number[] = [1, 6, 1068, 6969, 30023, 20, 21, 22] export const WISP_TRENDING_FEED_KINDS: readonly number[] = [
1,
6,
1068,
6969,
30023,
ExtendedKind.PICTURE,
ExtendedKind.VIDEO,
ExtendedKind.SHORT_VIDEO,
ExtendedKind.VIDEO_ADDRESSABLE,
ExtendedKind.SHORT_VIDEO_ADDRESSABLE
]
/** True when `url` is any nostrarchives notes trending WebSocket feed (path `/notes/trending/...`). */ /** True when `url` is any nostrarchives notes trending WebSocket feed (path `/notes/trending/...`). */
export function isWispTrendingNotesRelayUrl(url: string): boolean { export function isWispTrendingNotesRelayUrl(url: string): boolean {

13
src/pages/primary/NoteListPage/RelaysFeed.tsx

@ -73,12 +73,13 @@ const RelaysFeed = forwardRef<
} }
}, [relayUrlsKey, relayUrls.length]) }, [relayUrlsKey, relayUrls.length])
const defaultKinds = /** Stable identity when kind filter is empty so `subRequests` does not invalidate every render. */
kindsOverride && kindsOverride.length > 0 const fallbackNoteKinds = useMemo(() => [kinds.ShortTextNote], [])
? kindsOverride const defaultKinds = useMemo(() => {
: showKinds.length > 0 if (kindsOverride && kindsOverride.length > 0) return kindsOverride
? showKinds if (showKinds.length > 0) return showKinds
: [kinds.ShortTextNote] return fallbackNoteKinds
}, [kindsOverride, showKinds, fallbackNoteKinds])
const canRenderFeed = const canRenderFeed =
(feedInfo.feedType === 'relay' || (feedInfo.feedType === 'relay' ||

4
src/pages/secondary/NotePage/index.tsx

@ -52,8 +52,10 @@ function getEventTypeName(kind: number): string {
case ExtendedKind.PICTURE: case ExtendedKind.PICTURE:
return 'Picture' return 'Picture'
case ExtendedKind.VIDEO: case ExtendedKind.VIDEO:
case ExtendedKind.VIDEO_ADDRESSABLE:
return 'Video' return 'Video'
case ExtendedKind.SHORT_VIDEO: case ExtendedKind.SHORT_VIDEO:
case ExtendedKind.SHORT_VIDEO_ADDRESSABLE:
return 'Short Video' return 'Short Video'
case ExtendedKind.POLL: case ExtendedKind.POLL:
return 'Poll' return 'Poll'
@ -205,8 +207,10 @@ const NotePage = forwardRef(({ id, index, hideTitlebar = false, initialEvent }:
case 20: // ExtendedKind.PICTURE case 20: // ExtendedKind.PICTURE
return 'Note: Picture' return 'Note: Picture'
case 21: // ExtendedKind.VIDEO case 21: // ExtendedKind.VIDEO
case 34235: // ExtendedKind.VIDEO_ADDRESSABLE (NIP-71)
return 'Note: Video' return 'Note: Video'
case 22: // ExtendedKind.SHORT_VIDEO case 22: // ExtendedKind.SHORT_VIDEO
case 34236: // ExtendedKind.SHORT_VIDEO_ADDRESSABLE (NIP-71)
return 'Note: Short Video' return 'Note: Short Video'
case 11: // ExtendedKind.DISCUSSION case 11: // ExtendedKind.DISCUSSION
return 'Discussions' return 'Discussions'

5
src/providers/FavoriteRelaysActivityProvider.tsx

@ -1,5 +1,5 @@
import logger from '@/lib/logger' import logger from '@/lib/logger'
import { ExtendedKind } from '@/constants' import { ExtendedKind, NIP71_VIDEO_KINDS } from '@/constants'
import { getFavoritesFeedRelayUrls } from '@/lib/favorites-feed-relays' import { getFavoritesFeedRelayUrls } from '@/lib/favorites-feed-relays'
import { import {
readRelayPulseActiveNpubsCache, readRelayPulseActiveNpubsCache,
@ -34,8 +34,7 @@ const ACTIVE_PULSE_KINDS = [
kinds.Highlights, kinds.Highlights,
ExtendedKind.DISCUSSION, ExtendedKind.DISCUSSION,
ExtendedKind.PICTURE, ExtendedKind.PICTURE,
ExtendedKind.VIDEO, ...NIP71_VIDEO_KINDS,
ExtendedKind.SHORT_VIDEO,
ExtendedKind.COMMENT, ExtendedKind.COMMENT,
ExtendedKind.GENERIC_REPOST ExtendedKind.GENERIC_REPOST
] as number[] ] as number[]

7
src/services/event-archive.service.ts

@ -1,4 +1,4 @@
import { ExtendedKind } from '@/constants' import { ExtendedKind, NIP71_VIDEO_KINDS } from '@/constants'
import { shouldDropEventOnIngest } from '@/lib/event-ingest-filter' import { shouldDropEventOnIngest } from '@/lib/event-ingest-filter'
import { getEventArchiveConfig } from '@/lib/event-archive-config' import { getEventArchiveConfig } from '@/lib/event-archive-config'
import { isNip18RepostKind, isNip25ReactionKind, isReplaceableEvent } from '@/lib/event' import { isNip18RepostKind, isNip25ReactionKind, isReplaceableEvent } from '@/lib/event'
@ -12,9 +12,8 @@ const CORE_FEED_KINDS = new Set<number>([
kinds.ShortTextNote, kinds.ShortTextNote,
11, 11,
ExtendedKind.COMMENT, ExtendedKind.COMMENT,
20, ExtendedKind.PICTURE,
21, ...NIP71_VIDEO_KINDS,
22,
9802 // highlights 9802 // highlights
]) ])

16
src/services/local-storage.service.ts

@ -325,13 +325,27 @@ class LocalStorageService {
showKinds.push(ExtendedKind.WIKI_ARTICLE_MARKDOWN) showKinds.push(ExtendedKind.WIKI_ARTICLE_MARKDOWN)
} }
} }
if (showKindsVersion < 13) {
// NIP-71 addressable video (34235 / 34236): add when user already had regular video kinds enabled.
if (
showKinds.includes(ExtendedKind.VIDEO) ||
showKinds.includes(ExtendedKind.SHORT_VIDEO)
) {
if (!showKinds.includes(ExtendedKind.VIDEO_ADDRESSABLE)) {
showKinds.push(ExtendedKind.VIDEO_ADDRESSABLE)
}
if (!showKinds.includes(ExtendedKind.SHORT_VIDEO_ADDRESSABLE)) {
showKinds.push(ExtendedKind.SHORT_VIDEO_ADDRESSABLE)
}
}
}
// v9: boosts are optional in the same filter list as other kinds; do not auto-enable (leave absent). // v9: boosts are optional in the same filter list as other kinds; do not auto-enable (leave absent).
this.showKinds = showKinds this.showKinds = showKinds
// Only persist when we read from localStorage. If SHOW_KINDS is missing here (migrated to IDB and // Only persist when we read from localStorage. If SHOW_KINDS is missing here (migrated to IDB and
// keys cleared), persisting would write DEFAULT_FEED_SHOW_KINDS to IndexedDB and wipe the user's // keys cleared), persisting would write DEFAULT_FEED_SHOW_KINDS to IndexedDB and wipe the user's
// saved filter before initAsync/applySettings runs. // saved filter before initAsync/applySettings runs.
this.persistSetting(StorageKey.SHOW_KINDS, JSON.stringify(this.showKinds)) this.persistSetting(StorageKey.SHOW_KINDS, JSON.stringify(this.showKinds))
this.persistSetting(StorageKey.SHOW_KINDS_VERSION, '12') this.persistSetting(StorageKey.SHOW_KINDS_VERSION, '13')
} }
// Feed filter: kind 1 OPs, kind 1 replies, kind 1111 (migrate from legacy showRepliesAndComments if set) // Feed filter: kind 1 OPs, kind 1 replies, kind 1111 (migrate from legacy showRepliesAndComments if set)

7
src/services/mention-event-search.service.ts

@ -8,7 +8,7 @@ import {
citationPickerMatchesQuery, citationPickerMatchesQuery,
tryParseCitationEventIdFromQuery tryParseCitationEventIdFromQuery
} from '@/lib/citation-picker-search' } from '@/lib/citation-picker-search'
import { ExtendedKind, SEARCHABLE_RELAY_URLS } from '@/constants' import { ExtendedKind, NIP71_VIDEO_KINDS, SEARCHABLE_RELAY_URLS } from '@/constants'
import { kinds, type Event as NEvent } from 'nostr-tools' import { kinds, type Event as NEvent } from 'nostr-tools'
import client, { eventService, queryService } from './client.service' import client, { eventService, queryService } from './client.service'
import indexedDb from './indexed-db.service' import indexedDb from './indexed-db.service'
@ -22,8 +22,7 @@ export const MENTION_NPUB_DROPDOWN_LIMIT = 50
export const NEVENT_KINDS = [ export const NEVENT_KINDS = [
kinds.ShortTextNote, kinds.ShortTextNote,
ExtendedKind.PICTURE, ExtendedKind.PICTURE,
ExtendedKind.VIDEO, ...NIP71_VIDEO_KINDS,
ExtendedKind.SHORT_VIDEO,
ExtendedKind.POLL, ExtendedKind.POLL,
ExtendedKind.ZAP_POLL, ExtendedKind.ZAP_POLL,
ExtendedKind.COMMENT, ExtendedKind.COMMENT,
@ -139,7 +138,7 @@ async function searchCitationEventsForPickerInternal(
/** /**
* Search for events: session cache IndexedDB relays. Merges and dedupes by event id, up to limit. * Search for events: session cache IndexedDB relays. Merges and dedupes by event id, up to limit.
* @param mode - 'nevent' uses NEVENT_KINDS (1,11,20,21,22,9802), 'naddr' uses NADDR_KINDS (30023,30817,30818,30040). * @param mode - 'nevent' uses NEVENT_KINDS (incl. NIP-71 video 21/22/34235/34236), 'naddr' uses NADDR_KINDS (30023,30817,30818,30040).
* @param kindFilter - When set, only these kinds are searched (overrides `mode` for the kinds list). * @param kindFilter - When set, only these kinds are searched (overrides `mode` for the kinds list).
*/ */
export async function searchEventsForPicker( export async function searchEventsForPicker(

2
src/services/nip89.service.ts

@ -219,6 +219,8 @@ class Nip89Service {
ExtendedKind.PICTURE, ExtendedKind.PICTURE,
ExtendedKind.VIDEO, ExtendedKind.VIDEO,
ExtendedKind.SHORT_VIDEO, ExtendedKind.SHORT_VIDEO,
ExtendedKind.VIDEO_ADDRESSABLE,
ExtendedKind.SHORT_VIDEO_ADDRESSABLE,
ExtendedKind.POLL, ExtendedKind.POLL,
ExtendedKind.COMMENT, ExtendedKind.COMMENT,
ExtendedKind.VOICE, ExtendedKind.VOICE,

Loading…
Cancel
Save