import { useEffect, useRef, useState } from 'react' import { Helmet } from 'react-helmet-async' import { useParams } from 'react-router-dom' import PostEmbed from '@/components/PostEmbed' import MainArea from '@/components/layout/MainArea' import { SITE_TITLE } from '@/config' import { apiGet, apiPatch, apiPut } from '@/lib/api' import { fetchPost } from '@/lib/posts' import type { FC } from 'react' import type { NiconicoMetadata, NiconicoViewerHandle, Post, Theatre } from '@/types' type TheatreInfo = { hostFlg: boolean postId: number | null postStartedAt: string | null } export default (() => { const { id } = useParams () const embedRef = useRef (null) const [loading, setLoading] = useState (false) const [theatre, setTheatre] = useState (null) const [theatreInfo, setTheatreInfo] = useState ({ hostFlg: false, postId: null, postStartedAt: null }) const [post, setPost] = useState (null) const [videoLength, setVideoLength] = useState (9_999_999_999) useEffect (() => { if (!(id)) return void (async () => { setTheatre (await apiGet (`/theatres/${ id }`)) }) () const interval = setInterval (async () => { if (theatreInfo.hostFlg && theatreInfo.postStartedAt && ((new Date).getTime () - (new Date (theatreInfo.postStartedAt)).getTime () > videoLength)) setTheatreInfo ({ hostFlg: true, postId: null, postStartedAt: null }) else setTheatreInfo (await apiPut (`/theatres/${ id }/watching`)) }, 1_000) return () => clearInterval (interval) }, [id, theatreInfo.hostFlg, theatreInfo.postStartedAt, videoLength]) useEffect (() => { if (!(theatreInfo.hostFlg) || loading) return if (theatreInfo.postId == null) { void (async () => { setLoading (true) await apiPatch (`/theatres/${ id }/next_post`) setLoading (false) }) () return } }, [id, loading, theatreInfo.hostFlg, theatreInfo.postId]) useEffect (() => { if (theatreInfo.postId == null) return void (async () => { setPost (await fetchPost (String (theatreInfo.postId))) }) () }, [theatreInfo.postId, theatreInfo.postStartedAt]) const syncPlayback = (meta: NiconicoMetadata) => { if (!(theatreInfo.postStartedAt)) return const targetTime = ((new Date).getTime () - (new Date (theatreInfo.postStartedAt)).getTime ()) const drift = Math.abs (meta.currentTime - targetTime) if (drift > 5_000) embedRef.current?.seek (targetTime) } return ( {theatre && ( {'上映会場' + (theatre.name ? `『${ theatre.name }』` : ` #${ theatre.id }`) + ` | ${ SITE_TITLE }`} )} {post && ( { embedRef.current?.play () setVideoLength (info.lengthInSeconds * 1_000) }} onMetadataChange={meta => { syncPlayback (meta) }}/>)} ) }) satisfies FC