From 4c091a383c695990de42d4c374127e79bdd342d3 Mon Sep 17 00:00:00 2001 From: Foysal Ahamed Date: Wed, 31 Jul 2024 23:01:07 +0200 Subject: [PATCH 1/5] :sparkles: Add post embedded video player --- app/surprise-me/page.tsx | 2 +- components/common/posts/PostsFeed.tsx | 18 ++++++++-- components/common/video/player.tsx | 47 +++++++++++++++++++++++++++ package.json | 1 + yarn.lock | 5 +++ 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 components/common/video/player.tsx diff --git a/app/surprise-me/page.tsx b/app/surprise-me/page.tsx index 11892276..958a040c 100644 --- a/app/surprise-me/page.tsx +++ b/app/surprise-me/page.tsx @@ -1,5 +1,5 @@ 'use client' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { useInterval, useTitle } from 'react-use' import dynamic from 'next/dynamic' diff --git a/components/common/posts/PostsFeed.tsx b/components/common/posts/PostsFeed.tsx index e0c26d74..215278b8 100644 --- a/components/common/posts/PostsFeed.tsx +++ b/components/common/posts/PostsFeed.tsx @@ -1,13 +1,14 @@ 'use client' import { useEffect, useState } from 'react' +import dynamic from 'next/dynamic' import { AppBskyFeedDefs, AppBskyEmbedImages, AppBskyEmbedExternal, AppBskyEmbedRecordWithMedia, + AppBskyEmbedVideo, AppBskyFeedPost, AppBskyEmbedRecord, - AppBskyGraphList, AppBskyGraphDefs, } from '@atproto/api' import Link from 'next/link' @@ -15,7 +16,6 @@ import { DocumentMagnifyingGlassIcon, ExclamationCircleIcon, LanguageIcon, - InformationCircleIcon, FolderMinusIcon, FolderPlusIcon, } from '@heroicons/react/24/outline' @@ -37,6 +37,9 @@ import { useWorkspaceRemoveItemsMutation, } from '@/workspace/hooks' import { ImageList } from './ImageList' +const VideoPlayer = dynamic(() => import('@/common/video/player'), { + ssr: false, +}) export function PostsFeed({ items, @@ -229,6 +232,17 @@ export function PostEmbeds({ item }: { item: AppBskyFeedDefs.FeedViewPost }) { imageRequiresBlur ? 'blur-sm hover:blur-none' : '', ) + if (AppBskyEmbedVideo.isView(embed)) { + return ( +
+ +
+ ) + } + // render image embeds if (AppBskyEmbedImages.isView(embed)) { const embeddedImageClassName = classNames( diff --git a/components/common/video/player.tsx b/components/common/video/player.tsx new file mode 100644 index 00000000..ede61979 --- /dev/null +++ b/components/common/video/player.tsx @@ -0,0 +1,47 @@ +import Hls from 'hls.js/dist/hls.light' // Use light build of hls. +import { useEffect, useRef, useState } from 'react' + +export default function VideoPlayer({ + source, + poster, +}: { + source: string + poster: string +}) { + const [hls] = useState(() => new Hls()) + + const ref = useRef(null) + + useEffect(() => { + if (ref.current && Hls.isSupported()) { + hls.attachMedia(ref.current) + + return () => { + hls.detachMedia() + } + } + }, [hls]) + + useEffect(() => { + if (ref.current) { + if (Hls.isSupported()) { + hls.loadSource(source) + } else { + // TODO: fallback + } + } + }, [source, hls]) + + return ( +