import { Card , CircularProgress , Typography } from '@material-ui/core' ; import React , { useCallback , useRef } from 'react' ; import ReactPlayer , { Config as ReactPlayerConfig } from 'react-player/lazy' ; import { useRouteMatch } from 'react-router-dom' ; import { StationPlayerQuery , useOnStationPlayerChangedSubscription , useStationPlayerQuery } from 'operations' ; import { usePreviousNonNullableValue } from 'hooks/use-previous-non-nullable-value' ; import { useStationContextState } from '../context' ; import { useStyles } from './styles' ; interface RouteParams { slug : string ; } export const Player = ( ) => { const classes = useStyles ( ) ; const match = useRouteMatch < RouteParams > ( ) ; if ( ! match ) { throw new Error ( `Match not found. The "$stationSlug" is not existed in query param.` ) ; } const { player : { muted } , } = useStationContextState ( ) ; const { loading , data , refetch } = useStationPlayerQuery ( { variables : { stationSlug : match . params . slug } , fetchPolicy : 'network-only' , } ) ; useOnStationPlayerChangedSubscription ( { variables : { stationSlug : match . params . slug } , onSubscriptionData : ( { subscriptionData : { data } } ) => { if ( ! data ) return ; const { onPlayingSongChanged } = data ; if ( ! onPlayingSongChanged ) return ; refetch ( ) ; } , } ) ; const playingSong = React . useMemo < StationPlayerQuery [ 'playingSongs' ] [ 0 ] | undefined > ( ( ) => { if ( data ?. playingSongs [ 0 ] ) return data . playingSongs [ 0 ] ; return undefined ; } , [ data ] ) ; const playerRef = useRef < ReactPlayer > ( null ) ; const syncPlayer = useCallback ( ( ) => { if ( playerRef . current && playingSong ) { const currentTime = new Date ( ) . getTime ( ) ; const startPlayerTime = new Date ( playingSong . startedAt ) . getTime ( ) ; const seekTime = currentTime - startPlayerTime ; const seekToSeconds = seekTime / 1000 ; if ( Math . abs ( playerRef . current . getCurrentTime ( ) - seekToSeconds ) > 5 ) { playerRef . current . seekTo ( seekToSeconds ) ; } } } , [ playingSong , playerRef ] ) ; const [ url ] = usePreviousNonNullableValue ( playingSong ?. url ) ; const [ id ] = usePreviousNonNullableValue ( playingSong ?. id ) ; const playerConfig = React . useMemo < ReactPlayerConfig > ( ( ) => ( { } ) , [ ] ) ; let content ; if ( url ) { content = ( < ReactPlayer url = { `${ url }&re-radio-song-id=${ id }` } onPlay = { syncPlayer } ref = { playerRef } className = { classes . wrapper } config = { playerConfig } width = "100%" height = "100%" muted = { muted } playing controls = { false } / > ) ; } else if ( loading ) { content = < CircularProgress />; } else if ( ! playingSong ) { content = null ; } else { content = ( < Typography variant = "subtitle1" color = "error" > something bad happen : ( < /Typography>); } return ( < Card id = "station-player" className = { classes . container } elevation = { 0 } square > { content } < /Card>); } ;