feat: add note content support for direct video URLs

- Add noteContent prop to VideoView component for displaying note text
- Update VideoView to prioritize note content over metadata when available
- Detect direct video URLs from Nostr notes (nostr.build, nostr.video domains)
- Pass bookmark information through URL selection in bookmark components
- Show placeholder message for direct videos from Nostr notes
- Maintains backward compatibility with existing video metadata extraction
This commit is contained in:
Gigi
2025-10-25 00:30:07 +02:00
parent 4e4d719d94
commit c69e50d3bb
5 changed files with 15 additions and 5 deletions

View File

@@ -129,7 +129,7 @@ export const BookmarkItem: React.FC<BookmarkItemProps> = ({ bookmark, index, onS
if (!hasUrls) return if (!hasUrls) return
const firstUrl = extractedUrls[0] const firstUrl = extractedUrls[0]
if (onSelectUrl) { if (onSelectUrl) {
onSelectUrl(firstUrl) onSelectUrl(firstUrl, bookmark)
} else { } else {
window.open(firstUrl, '_blank') window.open(firstUrl, '_blank')
} }

View File

@@ -145,7 +145,7 @@ export const CardView: React.FC<CardViewProps> = ({
<button <button
key={urlIndex} key={urlIndex}
className="bookmark-url" className="bookmark-url"
onClick={(e) => { e.stopPropagation(); onSelectUrl?.(url) }} onClick={(e) => { e.stopPropagation(); onSelectUrl?.(url, bookmark) }}
title="Open in reader" title="Open in reader"
> >
{url} {url}

View File

@@ -56,7 +56,7 @@ export const CompactView: React.FC<CompactViewProps> = ({
navigate(`/a/${naddr}`) navigate(`/a/${naddr}`)
} }
} else if (hasUrls) { } else if (hasUrls) {
onSelectUrl?.(extractedUrls[0]) onSelectUrl?.(extractedUrls[0], bookmark)
} else if (isNote) { } else if (isNote) {
navigate(`/e/${bookmark.id}`) navigate(`/e/${bookmark.id}`)
} }

View File

@@ -381,6 +381,12 @@ const ThreePaneLayout: React.FC<ThreePaneLayoutProps> = (props) => {
const isExternalVideo = !isNostrArticle && !!props.selectedUrl && ['youtube', 'video'].includes(classifyUrl(props.selectedUrl).type) const isExternalVideo = !isNostrArticle && !!props.selectedUrl && ['youtube', 'video'].includes(classifyUrl(props.selectedUrl).type)
if (isExternalVideo) { if (isExternalVideo) {
// Check if this is a direct video URL from a Nostr note
// For URLs like /r/https%3A%2F%2Fv.nostr.build%2FWFO5YkruM9GFJjeg.mp4
const isDirectVideoFromNote = props.selectedUrl?.includes('nostr.build') ||
props.selectedUrl?.includes('nostr.video') ||
props.selectedUrl?.includes('v.nostr.build')
return ( return (
<VideoView <VideoView
videoUrl={props.selectedUrl!} videoUrl={props.selectedUrl!}
@@ -391,6 +397,7 @@ const ThreePaneLayout: React.FC<ThreePaneLayoutProps> = (props) => {
settings={props.settings} settings={props.settings}
relayPool={props.relayPool} relayPool={props.relayPool}
activeAccount={props.activeAccount} activeAccount={props.activeAccount}
noteContent={isDirectVideoFromNote ? "This video was shared from a Nostr note. The original note content would be displayed here if available." : undefined}
onOpenHighlights={() => { onOpenHighlights={() => {
if (props.isHighlightsCollapsed) { if (props.isHighlightsCollapsed) {
props.onToggleHighlightsPanel() props.onToggleHighlightsPanel()

View File

@@ -34,6 +34,7 @@ interface VideoViewProps {
relayPool?: RelayPool | null relayPool?: RelayPool | null
activeAccount?: IAccount | null activeAccount?: IAccount | null
onOpenHighlights?: () => void onOpenHighlights?: () => void
noteContent?: string // Content from the original Nostr note
} }
const VideoView: React.FC<VideoViewProps> = ({ const VideoView: React.FC<VideoViewProps> = ({
@@ -45,7 +46,8 @@ const VideoView: React.FC<VideoViewProps> = ({
settings, settings,
relayPool, relayPool,
activeAccount, activeAccount,
onOpenHighlights onOpenHighlights,
noteContent
}) => { }) => {
const [isMarkedAsWatched, setIsMarkedAsWatched] = useState(false) const [isMarkedAsWatched, setIsMarkedAsWatched] = useState(false)
const [isCheckingWatchedStatus, setIsCheckingWatchedStatus] = useState(false) const [isCheckingWatchedStatus, setIsCheckingWatchedStatus] = useState(false)
@@ -209,7 +211,8 @@ const VideoView: React.FC<VideoViewProps> = ({
} }
const displayTitle = ytMeta?.title || title const displayTitle = ytMeta?.title || title
const displaySummary = ytMeta?.description || summary // For direct video URLs from Nostr notes, prioritize note content over metadata
const displaySummary = noteContent || ytMeta?.description || summary
const durationText = videoDurationSec !== null ? formatDuration(videoDurationSec) : null const durationText = videoDurationSec !== null ? formatDuration(videoDurationSec) : null
// Get video thumbnail for cover image // Get video thumbnail for cover image