Skip to content

Add diVine video feed#682

Open
marykatefain wants to merge 22 commits intoCodyTseng:masterfrom
marykatefain:divine-feed
Open

Add diVine video feed#682
marykatefain wants to merge 22 commits intoCodyTseng:masterfrom
marykatefain:divine-feed

Conversation

@marykatefain
Copy link
Copy Markdown

  1. Adds a "Divine" feed on the main sidebar which displays divine videos
  2. Adds a "video" tab to your home feed

Try it here: https://jumble-divine.shakespeare.wtf/

divine-in-jumble.mp4

- Created DivinePage as a new primary page for browsing Divine video content
- Added DivineVideoList component for infinite scrolling video feed
- Added DivineVideoCard component for displaying individual video cards
- Created divine-video.ts library for parsing kind 34236 video events
- Added Divine navigation buttons to sidebar and bottom navigation bar
- Registered divine page in primary routes
- Added translations for Divine-related strings

The Divine feed connects to wss://relay.divine.video to fetch kind 34236 
video events. Clicking on a video navigates to the note page where users 
can view the full video and all comments/interactions.
- Added `loop` prop to VideoPlayer and MediaPlayer components
- VideoNote now automatically loops for short-form video kinds:
  - Kind 22 (SHORT_VIDEO)
  - Kind 34236 (ADDRESSABLE_SHORT_VIDEO / Divine videos)
- DivineVideoCard uses looping for inline video playback

This provides the expected Vine/TikTok-style looping experience for 
short-form video content.
- Added "Videos" tab to NormalFeed component (Notes | Replies | Videos | 24h Pulse)
- Videos tab filters to show only video content kinds:
  - Kind 21 (VIDEO)
  - Kind 22 (SHORT_VIDEO)  
  - Kind 34235 (ADDRESSABLE_NORMAL_VIDEO)
  - Kind 34236 (ADDRESSABLE_SHORT_VIDEO / Divine videos)
- Hide kind filter dropdown when Videos tab is active (redundant)
- Added 'videos' to TNoteListMode type
- Added translation for "Videos"
- Created VideoFeed component with source selection:
  - "Following" - shows videos from people you follow (uses existing relay subscriptions)
  - "Global" - shows videos from Divine relay (wss://relay.divine.video)
- Added sort options for Global view: Recent and Trending
- Automatically switches to Global if user is not logged in
- Updated NormalFeed to use VideoFeed component for videos tab
- Added translations for Global and Recent
- Removed broken VideoFeed component with redundant Following/Global toggle
- Added 'divine' as a proper TFeedType alongside 'following', 'relay', 'relays'
- Updated FeedProvider to handle 'divine' feed type (uses wss://relay.divine.video)
- Added "Divine Videos" option in FeedSwitcher dropdown with clapperboard icon
- Created DivineFeed component for rendering Divine video content
- Updated FeedButton to show proper icon and title for Divine feed
- NormalFeed Videos tab now filters by video kinds from current feed source

Users can now select "Divine Videos" from the feed dropdown (same place as
"Following" and relay options) to browse global Divine video content.
This reverts the codebase back to the state at commit 2ffbd3f.

Reverted 2 commit(s):
- a3a8ed6: Fix: Add Divine Videos as a proper feed option in feed switcher
- 48b6eac: Add Following/Global toggle to Videos tab with source options
- Add defaultMuted prop to VideoPlayer component to override global mute setting
- Pass defaultMuted prop through MediaPlayer component
- Set defaultMuted={false} in DivineVideoCard so videos play with sound

Videos on the Divine feed will now start unmuted, while videos elsewhere
still respect the global mute preference.
- Update volumechange handler to only sync to global state when defaultMuted is not set
- Explicitly set video.muted based on defaultMuted when it's provided
- Add proper dependencies to useEffect hooks
- Create VideoFeedProvider context to track when viewing video feed
- Wrap NoteList with VideoFeedProvider in NormalFeed when on Videos tab
- Update VideoNote to use context and set defaultMuted={false} for video feed
- Videos on the Videos tab will now play with sound by default
- Fix DivineButton to use correct SidebarItem props (title, children)
- Fix UserAvatar size prop from "default" to "normal"
- Remove thumbnail/play button - videos now autoplay directly
- Change aspect ratio from square to video (16:9)
- Add date-fns dependency for time formatting
- Clean up unused imports
Videos were not loading because mustLoad was accidentally removed.
This prop forces the MediaPlayer to load videos immediately.
- Add try-catch around URL parsing in MediaPlayer
- Replace plain URL link with nicer fallback UI when video fails to load
- Fallback shows play button and "Open video externally" option
- Helps handle HLS streams and CORS-blocked videos gracefully
Divine videos are just Nostr events - use the same NoteCard component
that works for the Videos tab. Wrap with VideoFeedProvider so videos
play unmuted by default.
- Update DivinePage to use NIP-50 sort modes (hot, top, rising) instead of
  non-functional Discovery/Trending tabs
- Add sortMode prop to DivineVideoList component with NIP-50 search filter
- Create DivineSortMode type and createSortSearch helper in divine-video.ts
- Fix VideoNote component to properly parse Divine video URLs using
  parseVideoEvents fallback for kind 34236 events
- Add translations for new tab labels (Hot, Classic, Rising, New) in all
  supported languages

The tabs now use NIP-50 search extensions similar to divine-web-44:
- Hot: Recent videos with high engagement (sort:hot)
- Classic: Popular archived Vines (sort:top with #platform filter)
- Rising: Videos gaining traction (sort:rising)
- New: Chronological order (no sort mode)
Added stream.divine.video to the list of known video streaming domains
in the isMedia function, so URLs from that domain are properly
recognized as media and rendered with the MediaPlayer component.
- Added .m3u8 to media extensions in isMedia() function
- Added hls.js library for HLS stream playback
- Updated VideoPlayer component to detect and handle HLS streams
- Also added broader divine.video domain matching for future compatibility

Divine videos use HLS streams (playlist.m3u8) which require special
handling since native HTML5 video doesn't support HLS in most browsers.
Videos that only have .m3u8 HLS streams aren't well supported in
browsers without additional complexity. Filter these out of the
Divine feed to only show videos with directly playable URLs (.mp4, etc).
Added hasPlayableVideo check to NoteList's shouldHideEvent callback,
which filters out HLS-only videos from all feeds that use NoteList
including the Following feed, Profile feed, and Videos tab.
The VideoPlayer component already had hls.js support for playing HLS
streams, but the hasPlayableVideo() function was filtering them out.

Changes:
- Updated hasPlayableVideo() in divine-video.ts to consider HLS streams
  as playable when the browser supports them (via native HLS in Safari
  or MediaSource Extensions for hls.js)
- Updated comments in NoteList and DivineVideoList to reflect the new
  behavior

This allows .m3u8 video streams to display in feeds on browsers that
support HLS playback.
The issue was multi-layered:
1. MediaPlayer wasn't recognizing Divine video URLs as video content
2. VideoPlayer only checked for .m3u8 extension, missing Divine URLs
3. Divine video URLs (stream.divine.video) don't always have .m3u8 extension

Changes:
- Added isDivineVideoUrl() helper in url.ts to centralize Divine domain detection
- Updated MediaPlayer to recognize Divine video URLs as video content
- Updated VideoPlayer to:
  - Detect Divine video URLs as requiring HLS playback
  - Append /index.m3u8 to Divine base URLs to get HLS manifest
  - Use hls.js for playback in non-Safari browsers

Now Divine video feeds should properly display video players instead of
plain URLs.
The previous commit was too aggressive in treating all Divine video URLs
as HLS streams. This broke playback of MP4 files from Divine.

Changes:
- Reverted VideoPlayer to only use HLS for explicit .m3u8 URLs
- Reverted MediaPlayer to only detect .m3u8 as requiring special handling
- Keep isMedia() support for Divine domains so URLs are still recognized
  as media and sent to MediaPlayer (which can detect MP4s via metadata)

Now both MP4 and HLS (.m3u8) videos should work:
- MP4 files: Played directly by the browser
- HLS files: Played via hls.js (or native in Safari)
Updated all user-facing text from "Divine" to "diVine":
- Sidebar button title
- Page header title
- All translation files (17 languages)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant