Reviewed-on: #357 Co-authored-by: miteruzo <miteruzo@naver.com> Co-committed-by: miteruzo <miteruzo@naver.com>
このコミットはPull リクエスト #357 でマージされました.
このコミットが含まれているのは:
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import YoutubeEmbed from 'react-youtube'
|
||||
|
||||
import NicoViewer from '@/components/NicoViewer'
|
||||
@@ -8,17 +8,97 @@ import { useDialogue } from '@/components/dialogues/DialogueProvider'
|
||||
import type { FC, RefObject } from 'react'
|
||||
|
||||
import type { NiconicoMetadata, NiconicoVideoInfo, NiconicoViewerHandle, Post } from '@/types'
|
||||
import type { YouTubePlayer } from 'react-youtube'
|
||||
|
||||
type YouTubeEvent<T = unknown> = {
|
||||
data: T
|
||||
target: YouTubePlayer }
|
||||
|
||||
type Props = {
|
||||
ref?: RefObject<NiconicoViewerHandle | null>
|
||||
post: Post
|
||||
onLoadComplete?: (info: NiconicoVideoInfo) => void
|
||||
onMetadataChange?: (meta: NiconicoMetadata) => void }
|
||||
onMetadataChange?: (meta: NiconicoMetadata) => void
|
||||
onVideoReady?: (durationMs: number) => void
|
||||
onPlaybackChange?: (currentTimeMs: number) => number | void
|
||||
onError?: (data: unknown) => void }
|
||||
|
||||
|
||||
const PostEmbed: FC<Props> = ({ ref, post, onLoadComplete, onMetadataChange }) => {
|
||||
const PostEmbed: FC<Props> = ({
|
||||
ref,
|
||||
post,
|
||||
onLoadComplete,
|
||||
onMetadataChange,
|
||||
onVideoReady,
|
||||
onPlaybackChange,
|
||||
onError,
|
||||
}) => {
|
||||
const dialogue = useDialogue ()
|
||||
const [framed, setFramed] = useState (false)
|
||||
const [youtubePlayer, setYoutubePlayer] = useState<YouTubePlayer | null> (null)
|
||||
|
||||
const reportYoutubePlayback = useCallback (async (player: YouTubePlayer) => {
|
||||
const currentTime = await player.getCurrentTime ()
|
||||
const currentTimeMs = currentTime * 1_000
|
||||
const targetTimeMs = onPlaybackChange?.(currentTimeMs)
|
||||
|
||||
if (typeof targetTimeMs !== 'number')
|
||||
return
|
||||
|
||||
if (Math.abs (currentTimeMs - targetTimeMs) > 5_000)
|
||||
await player.seekTo (targetTimeMs / 1_000, true)
|
||||
}, [onPlaybackChange])
|
||||
|
||||
const handleYoutubeReady = async (event: YouTubeEvent) => {
|
||||
setYoutubePlayer (event.target)
|
||||
|
||||
try
|
||||
{
|
||||
await event.target.playVideo ()
|
||||
|
||||
const duration = await event.target.getDuration ()
|
||||
const durationMs = duration * 1_000
|
||||
onVideoReady?.(durationMs)
|
||||
|
||||
if (!(Number.isFinite (durationMs)) || durationMs <= 0)
|
||||
return
|
||||
|
||||
await reportYoutubePlayback (event.target)
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
onError?.({ platform: 'youtube', error })
|
||||
}
|
||||
}
|
||||
|
||||
const handleYoutubeStateChange = (event: YouTubeEvent<number>) => {
|
||||
void reportYoutubePlayback (event.target)
|
||||
}
|
||||
|
||||
const handleYoutubeError = (event: YouTubeEvent<number>) => {
|
||||
onError?.({ platform: 'youtube', code: event.data })
|
||||
}
|
||||
|
||||
const handleNiconicoLoadComplete = (info: NiconicoVideoInfo) => {
|
||||
onVideoReady?.(info.lengthInSeconds * 1_000)
|
||||
onLoadComplete?.(info)
|
||||
}
|
||||
|
||||
const handleNiconicoMetadataChange = (meta: NiconicoMetadata) => {
|
||||
onPlaybackChange?.(meta.currentTime)
|
||||
onMetadataChange?.(meta)
|
||||
}
|
||||
|
||||
useEffect (() => {
|
||||
if (!(youtubePlayer) || !(onPlaybackChange))
|
||||
return
|
||||
|
||||
const timer = setInterval (
|
||||
() => void reportYoutubePlayback (youtubePlayer),
|
||||
1_000)
|
||||
|
||||
return () => clearInterval (timer)
|
||||
}, [onPlaybackChange, reportYoutubePlayback, youtubePlayer])
|
||||
|
||||
const url = new URL (post.url)
|
||||
|
||||
@@ -38,8 +118,9 @@ const PostEmbed: FC<Props> = ({ ref, post, onLoadComplete, onMetadataChange }) =
|
||||
id={videoId}
|
||||
width={640}
|
||||
height={360}
|
||||
onLoadComplete={onLoadComplete}
|
||||
onMetadataChange={onMetadataChange}/>)
|
||||
onLoadComplete={handleNiconicoLoadComplete}
|
||||
onMetadataChange={handleNiconicoMetadataChange}
|
||||
onError={onError}/>)
|
||||
}
|
||||
|
||||
case 'twitter.com':
|
||||
@@ -69,7 +150,10 @@ const PostEmbed: FC<Props> = ({ ref, post, onLoadComplete, onMetadataChange }) =
|
||||
mute: 0,
|
||||
loop: 1,
|
||||
width: '640',
|
||||
height: '360' } }}/>)
|
||||
height: '360' } }}
|
||||
onReady={handleYoutubeReady}
|
||||
onStateChange={handleYoutubeStateChange}
|
||||
onError={handleYoutubeError}/>)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
新しい課題から参照
ユーザをブロックする