ファイル
btrc-hub/frontend/src/components/PostEmbed.tsx
T
みてるぞ 6cf42e38c6 feat: 対応外の投稿を iframe で埋込む(#157) (#199)
#157

#157 対応外の投稿を iframe で埋込む

Co-authored-by: miteruzo <miteruzo@naver.com>
Reviewed-on: #199
2026-01-01 21:19:10 +09:00

68 行
1.7 KiB
TypeScript

import { useState } from 'react'
import YoutubeEmbed from 'react-youtube'
import NicoViewer from '@/components/NicoViewer'
import TwitterEmbed from '@/components/TwitterEmbed'
import type { FC } from 'react'
import type { Post } from '@/types'
type Props = { post: Post }
export default (({ post }: Props) => {
const url = new URL (post.url)
switch (url.hostname.split ('.').slice (-2).join ('.'))
{
case 'nicovideo.jp':
{
const [videoId] = url.pathname.match (/(?<=\/watch\/)[a-zA-Z0-9]+?(?=\/|$)/)!
return <NicoViewer id={videoId} width={640} height={360}/>
}
case 'twitter.com':
case 'x.com':
const [userId] = url.pathname.match (/(?<=\/)[^\/]+?(?=\/|$|\?)/)!
const [statusId] = url.pathname.match (/(?<=\/status\/)\d+?(?=\/|$|\?)/)!
return <TwitterEmbed userId={userId} statusId={statusId}/>
case 'youtube.com':
{
const videoId = url.searchParams.get ('v')!
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={e => {
e.preventDefault ()
setFramed (confirm ('未確認の外部ページを表示します。\n'
+ '悪意のあるスクリプトが実行される可能性があります。\n'
+ '表示しますか?'))
return
}}>
</a>
</div>)}
</>)
}) satisfies FC<Props>