Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add youtube thumbnail fallbacks #173

Merged
merged 3 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/components/posts/editor/HtmlEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface HTMLEditorProps {
saveBodyDraft?: (body: string) => void
className?: string
showToolbar?: boolean
autoFocus?: boolean
}

export default function HtmlEditor({
Expand All @@ -16,13 +17,14 @@ export default function HtmlEditor({
saveBodyDraft,
className,
showToolbar,
autoFocus,
}: HTMLEditorProps) {
const editor = useCreateEditor(onChange, value, saveBodyDraft)

return (
<>
{showToolbar && <ToolBar editor={editor} />}
<EditorContent tabIndex={0} className={className} editor={editor} />
<EditorContent autoFocus tabIndex={0} className={className} editor={editor} />
</>
)
}
6 changes: 5 additions & 1 deletion src/components/posts/editor/ModalEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ export const PostEditorModalBody = ({
<SpaceSelector />
<Form.Item name={fieldName('body')} className='my-3'>
{/* value and onChange are provided by Form.Item */}
<HtmlEditor saveBodyDraft={saveDraft} className={clsx(styles.FastEditor, 'ant-input')} />
<HtmlEditor
autoFocus
saveBodyDraft={saveDraft}
className={clsx(styles.FastEditor, 'ant-input')}
/>
</Form.Item>
{imgUrl && (
<PreviewUploadedImage
Expand Down
83 changes: 67 additions & 16 deletions src/components/posts/embed/Embed.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import clsx from 'clsx'
import { useMemo } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import LiteYouTubeEmbed from 'react-lite-youtube-embed'
import styles from './Embed.module.sass'

Expand Down Expand Up @@ -78,27 +78,78 @@ const Embed = ({ link, className }: EmbedProps) => {
)
}

const thumbnail = ['maxresdefault', 'mqdefault', 'sddefault', 'hqdefault', 'default'] as const
export type ThumbnailRes = (typeof thumbnail)[number]

export function YoutubeThumbnailChecker({
setThumbnailRes,
src,
}: {
src: string
setThumbnailRes: (res: ThumbnailRes) => void
}) {
const currentRetries = useRef(0)
const imgRef = useRef<HTMLImageElement | null>(null)
const youtubeId = useMemo(() => getYoutubeVideoId(src), [src])
const [res, setRes] = useState(0)
useEffect(() => {
setThumbnailRes(thumbnail[res])
}, [res])

useEffect(() => {
function checkImage() {
if (imgRef.current?.complete) {
if (imgRef.current.naturalWidth === 120 && imgRef.current.naturalHeight === 90) {
if (res < thumbnail.length - 1) {
setRes(res + 1)
}
}
} else {
currentRetries.current++
if (currentRetries.current <= 5)
setTimeout(() => {
checkImage()
}, 200)
}
}
checkImage()
}, [res])

return (
<img
ref={imgRef}
style={{ display: 'none' }}
src={`https://i3.ytimg.com/vi/${youtubeId}/${thumbnail[res]}.jpg`}
/>
)
}

function YoutubeEmbed({ src }: { src: string }) {
const youtubeId = useMemo(() => getYoutubeVideoId(src), [src])
const [thumbnailRes, setThumbnailRes] = useState<ThumbnailRes>('maxresdefault')
console.log(thumbnailRes)

if (!youtubeId) return null

return (
<LiteYouTubeEmbed
id={youtubeId}
adNetwork={true}
params=''
playlist={false}
poster='maxresdefault'
title='YouTube Embed'
noCookie={true}
wrapperClass={clsx(styles.YoutubeEmbedWrapper)}
activatedClass='youtube-activated'
playerClass={clsx(styles.YoutubeEmbedPlayer)}
iframeClass={styles.YoutubeEmbedIframe}
aspectHeight={9}
aspectWidth={16}
/>
<>
<YoutubeThumbnailChecker src={src} setThumbnailRes={setThumbnailRes} />
<LiteYouTubeEmbed
id={youtubeId}
adNetwork={true}
params=''
playlist={false}
poster={thumbnailRes}
title='YouTube Embed'
noCookie={true}
wrapperClass={clsx(styles.YoutubeEmbedWrapper)}
activatedClass='youtube-activated'
playerClass={clsx(styles.YoutubeEmbedPlayer)}
iframeClass={styles.YoutubeEmbedIframe}
aspectHeight={9}
aspectWidth={16}
/>
</>
)
}

Expand Down
14 changes: 2 additions & 12 deletions src/components/posts/view-post/PostPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getPostIdFromSlug } from '@subsocial/utils/slugify'
import clsx from 'clsx'
import { NextPage } from 'next'
import router from 'next/router'
import { FC, useEffect } from 'react'
import { FC } from 'react'
import { CommentSection } from 'src/components/comments/CommentsSection'
import MobileStakerRewardDashboard from 'src/components/creators/MobileStakerRewardDashboard'
import { PageContent } from 'src/components/main/PageWrapper'
Expand All @@ -17,7 +17,7 @@ import { return404 } from 'src/components/utils/next'
import config from 'src/config'
import { resolveIpfsUrl } from 'src/ipfs'
import { getInitialPropsWithRedux, NextContextWithRedux } from 'src/rtk/app'
import { useSelectProfile, useSetChatEntityConfig } from 'src/rtk/app/hooks'
import { useSelectProfile } from 'src/rtk/app/hooks'
import { useAppSelector } from 'src/rtk/app/store'
import { fetchPost, fetchPosts, selectPost } from 'src/rtk/features/posts/postsSlice'
import { useFetchMyReactionsByPostId } from 'src/rtk/features/reactions/myPostReactionsHooks'
Expand Down Expand Up @@ -59,16 +59,6 @@ const InnerPostPage: NextPage<PostDetailsProps> = props => {
const { post, space } = postData
const { struct, content } = post

const setChatConfig = useSetChatEntityConfig()
useEffect(() => {
if (!post) return
setChatConfig({ entity: { data: post, type: 'post' }, withFloatingButton: true })

return () => {
setChatConfig(null)
}
}, [])

const goToCommentsId = 'comments'

const profile = useSelectProfile(postData.post.struct.ownerId)
Expand Down
Loading