From 4fb40e81b355e3854001ddd890d21b271f322803 Mon Sep 17 00:00:00 2001 From: codytseng Date: Sat, 4 Apr 2026 16:30:48 +0800 Subject: [PATCH] feat: improve addressable video (kind 34235/34236) display with title and hashtags Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ContentPreview/VideoNotePreview.tsx | 13 ++++++++++++- src/components/ContentPreview/index.tsx | 7 ++++++- src/components/Note/VideoNote.tsx | 18 ++++++++++++++++++ src/lib/event-metadata.ts | 19 +++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/components/ContentPreview/VideoNotePreview.tsx b/src/components/ContentPreview/VideoNotePreview.tsx index d189b72..950e90f 100644 --- a/src/components/ContentPreview/VideoNotePreview.tsx +++ b/src/components/ContentPreview/VideoNotePreview.tsx @@ -1,5 +1,8 @@ +import { ExtendedKind } from '@/constants' +import { getVideoMetadataFromEvent } from '@/lib/event-metadata' import { cn } from '@/lib/utils' import { Event } from 'nostr-tools' +import { useMemo } from 'react' import { useTranslation } from 'react-i18next' export default function VideoNotePreview({ @@ -10,10 +13,18 @@ export default function VideoNotePreview({ className?: string }) { const { t } = useTranslation() + const isAddressable = + event.kind === ExtendedKind.ADDRESSABLE_NORMAL_VIDEO || + event.kind === ExtendedKind.ADDRESSABLE_SHORT_VIDEO + const metadata = useMemo( + () => (isAddressable ? getVideoMetadataFromEvent(event) : null), + [event, isAddressable] + ) return (
- [{t('Media')}] {event.content} + [{t('Media')}]{' '} + {metadata?.title || event.content}
) } diff --git a/src/components/ContentPreview/index.tsx b/src/components/ContentPreview/index.tsx index 576bdca..bc0f402 100644 --- a/src/components/ContentPreview/index.tsx +++ b/src/components/ContentPreview/index.tsx @@ -83,7 +83,12 @@ export default function ContentPreview({ return } - if (event.kind === ExtendedKind.VIDEO || event.kind === ExtendedKind.SHORT_VIDEO) { + if ( + event.kind === ExtendedKind.VIDEO || + event.kind === ExtendedKind.SHORT_VIDEO || + event.kind === ExtendedKind.ADDRESSABLE_NORMAL_VIDEO || + event.kind === ExtendedKind.ADDRESSABLE_SHORT_VIDEO + ) { return } diff --git a/src/components/Note/VideoNote.tsx b/src/components/Note/VideoNote.tsx index a5debe0..512d9ff 100644 --- a/src/components/Note/VideoNote.tsx +++ b/src/components/Note/VideoNote.tsx @@ -1,15 +1,33 @@ +import { ExtendedKind } from '@/constants' import { getImetaInfosFromEvent } from '@/lib/event' +import { getVideoMetadataFromEvent } from '@/lib/event-metadata' import { Event } from 'nostr-tools' import { useMemo } from 'react' import Content from '../Content' +import { EmbeddedHashtag } from '../Embedded' import MediaPlayer from '../MediaPlayer' export default function VideoNote({ event, className }: { event: Event; className?: string }) { const videoInfos = useMemo(() => getImetaInfosFromEvent(event), [event]) + const isAddressable = + event.kind === ExtendedKind.ADDRESSABLE_NORMAL_VIDEO || + event.kind === ExtendedKind.ADDRESSABLE_SHORT_VIDEO + const metadata = useMemo( + () => (isAddressable ? getVideoMetadataFromEvent(event) : null), + [event, isAddressable] + ) return (
+ {metadata?.title &&
{metadata.title}
} + {metadata && metadata.tags.length > 0 && ( +
+ {metadata.tags.map((tag) => ( + + ))} +
+ )} {videoInfos.map((video) => ( ))} diff --git a/src/lib/event-metadata.ts b/src/lib/event-metadata.ts index e85839b..433eea7 100644 --- a/src/lib/event-metadata.ts +++ b/src/lib/event-metadata.ts @@ -387,6 +387,25 @@ export function getEmojisFromEvent(event: Event): TEmoji[] { return info.emojis } +export function getVideoMetadataFromEvent(event: Event) { + let title: string | undefined + const tags = new Set() + + event.tags.forEach(([tagName, tagValue]) => { + if (tagName === 'title') { + title = tagValue + } else if (tagName === 't' && tagValue && tags.size < 6) { + tags.add(tagValue.toLocaleLowerCase()) + } + }) + + if (!title) { + title = event.tags.find(tagNameEquals('d'))?.[1] + } + + return { title, tags: Array.from(tags) } +} + export function getStarsFromRelayReviewEvent(event: Event): number { const ratingTag = event.tags.find((t) => t[0] === 'rating') if (ratingTag) {