e03cc01109
#171 #171 #171 #171 #171 #171 #171 Co-authored-by: miteruzo <miteruzo@naver.com> Reviewed-on: #345
105 lines
2.5 KiB
TypeScript
105 lines
2.5 KiB
TypeScript
import { useState } from 'react'
|
|
import YoutubeEmbed from 'react-youtube'
|
|
|
|
import NicoViewer from '@/components/NicoViewer'
|
|
import TwitterEmbed from '@/components/TwitterEmbed'
|
|
import { useDialogue } from '@/components/dialogues/DialogueProvider'
|
|
|
|
import type { FC, RefObject } from 'react'
|
|
|
|
import type { NiconicoMetadata, NiconicoVideoInfo, NiconicoViewerHandle, Post } from '@/types'
|
|
|
|
type Props = {
|
|
ref?: RefObject<NiconicoViewerHandle | null>
|
|
post: Post
|
|
onLoadComplete?: (info: NiconicoVideoInfo) => void
|
|
onMetadataChange?: (meta: NiconicoMetadata) => void }
|
|
|
|
|
|
export default (({ ref, post, onLoadComplete, onMetadataChange }: Props) => {
|
|
const dialogue = useDialogue ()
|
|
|
|
const url = new URL (post.url)
|
|
|
|
switch (url.hostname.split ('.').slice (-2).join ('.'))
|
|
{
|
|
case 'nicovideo.jp':
|
|
{
|
|
const mVideoId = url.pathname.match (/(?<=\/watch\/)[a-zA-Z0-9]+?(?=\/|$)/)
|
|
if (!(mVideoId))
|
|
break
|
|
|
|
const [videoId] = mVideoId
|
|
|
|
return (
|
|
<NicoViewer
|
|
ref={ref}
|
|
id={videoId}
|
|
width={640}
|
|
height={360}
|
|
onLoadComplete={onLoadComplete}
|
|
onMetadataChange={onMetadataChange}/>)
|
|
}
|
|
|
|
case 'twitter.com':
|
|
case 'x.com':
|
|
{
|
|
const mUserId = url.pathname.match (/(?<=\/)[^\/]+?(?=\/|$|\?)/)
|
|
const mStatusId = url.pathname.match (/(?<=\/status\/)\d+?(?=\/|$|\?)/)
|
|
if (!(mUserId) || !(mStatusId))
|
|
break
|
|
|
|
const [userId] = mUserId
|
|
const [statusId] = mStatusId
|
|
|
|
return <TwitterEmbed userId={userId} statusId={statusId}/>
|
|
}
|
|
|
|
case 'youtube.com':
|
|
{
|
|
const videoId = url.searchParams.get ('v')
|
|
if (!(videoId))
|
|
break
|
|
|
|
return (
|
|
<YoutubeEmbed videoId={videoId} opts={{ playerVars: {
|
|
playsinline: 1,
|
|
autoplay: 1,
|
|
mute: 0,
|
|
loop: 1,
|
|
width: '640',
|
|
height: '360' } }}/>)
|
|
}
|
|
}
|
|
|
|
const [framed, setFramed] = useState (false)
|
|
|
|
return (
|
|
<>
|
|
{framed
|
|
? (
|
|
<iframe
|
|
src={post.url}
|
|
title={post.title || post.url}
|
|
width={640}
|
|
height={360}/>)
|
|
: (
|
|
<div>
|
|
<a href="#" onClick={async e => {
|
|
e.preventDefault ()
|
|
|
|
setFramed (await dialogue.confirm ({
|
|
title: '未確認の外部ページを表示します。',
|
|
description: (
|
|
<div>
|
|
<p>悪意のあるスクリプトが実行される可能性があります。</p>
|
|
<p>表示しますか?</p>
|
|
</div>),
|
|
confirmText: '表示' }))
|
|
}}>
|
|
外部ページを表示
|
|
</a>
|
|
</div>)}
|
|
</>)
|
|
}) satisfies FC<Props>
|