сделай синхронизацию видео еще точнее до пары мс import React, { useEffect, useRef, useState } from 'react';
import '@vidstack/react/player/styles/default/theme.css';
import '@vidstack/react/player/styles/default/layouts/audio.css';
import '@vidstack/react/player/styles/default/layouts/video.css';

import { MediaPlayer, MediaProvider } from '@vidstack/react';
import {
    DefaultVideoLayout,
    defaultLayoutIcons,
    DefaultAudioLayout,
} from '@vidstack/react/player/layouts/default';

import { IconButton } from '@mui/material';
import ChatIcon from '@mui/icons-material/Chat';
import CloseIcon from '@mui/icons-material/Close';

import { socket } from '../api';
import Chat from './Chat';
import { useTimesync } from './timesyncHelper';
const Player = ({ roomId, nickname, VideoUrl, setVideoUrl }) => {
    const [showChat, setShowChat] = useState(false);
    const playerRef = useRef(null);
    const lockSeekRef = useRef(false);
    const RUSSIA = {
        'Caption Styles': 'Стили субтитров',
        'Captions look like this': 'Субтитры выглядят так',
        'Closed-Captions Off': 'Субтитры отключены',
        'Closed-Captions On': 'Субтитры включены',
        'Display Background': 'Фон отображения',
        'Enter Fullscreen': 'Вход в полноэкранный режим',
        'Enter PiP': 'Войти в режим "картинка в картинке"',
        'Exit Fullscreen': 'Выйти из полноэкранного режима',
        'Exit PiP': 'Выйти из режима "картинка в картинке"',
        'Google Cast': 'Google Cast',
        'Keyboard Animations': 'Анимации клавиатуры',
        'Seek Backward': 'Перемотать назад',
        'Seek Forward': 'Перемотать вперед',
        'Skip To Live': 'Перейти к живому эфиру',
        'Text Background': 'Фон текста',
        Accessibility: 'Доступность',
        AirPlay: 'AirPlay',
        Announcements: 'Объявления',
        Audio: 'Аудио',
        Auto: 'Авто',
        Boost: 'Усиление звука',
        Captions: 'Субтитры',
        Chapters: 'Главы',
        Color: 'Цвет',
        Connected: 'Подключено',
        Connecting: 'Подключение',
        Continue: 'Продолжить',
        Default: 'По умолчанию',
        Disabled: 'Отключено',
        Disconnected: 'Отключено',
        Download: 'Скачать',
        Family: 'Семейный',
        Font: 'Шрифт',
        Fullscreen: 'Полноэкранный режим',
        LIVE: 'В эфире',
        Loop: 'Повтор',
        Mute: 'Выключить звук',
        Normal: 'Норма',
        Off: 'Выключено',
        Opacity: 'Прозрачность',
        Pause: 'Пауза',
        PiP: 'Картинка в картинке',
        Play: 'Воспроизвести',
        Playback: 'Воспроизведение',
        Quality: 'Качество',
        Replay: 'Повторить',
        Reset: 'Сбросить',
        Seek: 'Перемотка',
        Settings: 'Настройки',
        Shadow: 'Тень',
        Size: 'Размер',
        Speed: 'Скорость',
        Text: 'Текст',
        Track: 'Дорожка',
        Unmute: 'Включить звук',
        Volume: 'Громкость',
    };
    const { ts, currentTime, loading } = useTimesync('http://127.0.0.1:3001/timesync'); // Замените на ваш URL сервера timesync

    const toggleChat = () => {
        setShowChat((prevShowChat) => !prevShowChat);
    };

    const remoteControl = useRef({
        play: false,
        pause: false,
        seek: false,
        // Добавьте другие флаги при необходимости
    });

    useEffect(() => {
        if (loading || !ts) return;

        const player = playerRef.current;

        const sendCurrentTime = () => {
            const currentTime = player.currentTime;
            if (0 !== currentTime) {
                const currentTimestamp = ts.now() / 1000;
                socket.emit('videoControl', {
                    roomId,
                    action: 'sync',
                    data: currentTime,
                    timestamp: currentTimestamp,
                });
            }
        };

        const intervalId = setInterval(sendCurrentTime, 5000);

        const handlePlay = () => {
            if (remoteControl.current.play) {
                remoteControl.current.play = false;
                return;
            }
            const currentTimestamp = ts.now() / 1000;
            socket.emit('videoControl', {
                roomId,
                action: 'play',
                data: player.currentTime,
                timestamp: currentTimestamp,
            });
        };

        const handlePause = () => {
            if (remoteControl.current.pause) {
                remoteControl.current.pause = false;
                return;
            }
            const currentTimestamp = ts.now() / 1000;
            socket.emit('videoControl', {
                roomId,
                action: 'pause',
                data: player.currentTime,
                timestamp: currentTimestamp,
            });
        };

        const handleSeeked = () => {
            if (lockSeekRef.current) {
                lockSeekRef.current = false;
                return;
            }
            const currentTimestamp = ts.now() / 1000;
            socket.emit('videoControl', {
                roomId,
                action: 'seek',
                data: player.currentTime,
                timestamp: currentTimestamp,
            });
        };

        player.addEventListener('play', handlePlay);
        player.addEventListener('pause', handlePause);
        player.addEventListener('seeked', handleSeeked);

        const handleVideoControl = (data) => {
            if (data && ts) {
                const currentTimestamp = ts.now() / 1000;
                const adjustedTime = data.data + (currentTimestamp - data.timestamp);

                switch (data.action) {
                    case 'setUrl':
                        setVideoUrl(data.data);
                        break;
                    case 'play':
                        remoteControl.current.play = true;

                            lockSeekRef.current = true;
                            player.currentTime = adjustedTime ;

                        player.play();
                        break;
                    case 'pause':
                        remoteControl.current.pause = true;

                            lockSeekRef.current = true;
                            player.currentTime = data.data;

                        player.pause();
                        break;
                    case 'seek':
                    case 'sync':
                        if (Math.abs(player.currentTime - adjustedTime) > 0.05) {
                            lockSeekRef.current = true;
                            player.currentTime = adjustedTime;
                        }
                        break;
                    default:
                        break;
                }
            }
        };

        socket.on('videoControl', handleVideoControl);

        return () => {
            clearInterval(intervalId);
            socket.off('videoControl', handleVideoControl);
            player.removeEventListener('play', handlePlay);
            player.removeEventListener('pause', handlePause);
            player.removeEventListener('seeked', handleSeeked);
        };
    }, [roomId, setVideoUrl, ts, loading]);

    // Стили контейнера плеера
    const playerContainerStyle = {
        width: '100%',
        height: '100%',
        overflow: 'hidden',
        display: 'flex',
        flexDirection: 'column',
        position: 'relative',
    };

    // Стили для MediaPlayer
    const mediaPlayerStyle = {
        width: '100%',
        height: '100%',
        flex: '1',
        position: 'relative',
    };

    // Стили для видео
    const videoStyle = {
        width: '100%',
        height: '100%',
        objectFit: 'contain',
    };

    // Стили для кнопки чата
    const chatToggleButtonStyle = {
        position: 'absolute',
        top: '50%',
        transform: 'translateY(-50%)',
        right: showChat ? 'calc(30% + 20px)' : '20px',
        zIndex: 15,
        color: 'white',
    };

    // Стили для контейнера чата
    const chatContainerStyle = {
        position: 'absolute',
        top: '0',
        right: '0',
        width: '30%',
        height: '100%',
        backgroundColor: 'rgba(0, 0, 0, 0.8)',
        zIndex: 10,
        overflowY: 'auto',
        display: 'flex',
        flexDirection: 'column',
    };

    return (
        <div style={playerContainerStyle}>
            <MediaPlayer
                ref={playerRef}
                src={VideoUrl || 'https://files.vidstack.io/sprite-fight/720p.mp4'}
                viewType='video'
                streamType='on-demand'
                logLevel='warn'
                crossOrigin
                playsInline
                title='Sprite Fight'
                poster='https://files.vidstack.io/sprite-fight/poster.webp'
                aspectRatio='none'
                style={mediaPlayerStyle}
                controls={showChat} // Скрываем панель управления при открытии чата
            >
                <MediaProvider>
                    {(props) => (
                        <video {...props} style={videoStyle}>
                            {props.children}
                        </video>
                    )}
                </MediaProvider>
                <DefaultAudioLayout icons={defaultLayoutIcons} />
                <DefaultVideoLayout icons={defaultLayoutIcons} translations={RUSSIA} title={'Матрица'} />

                {/* Кнопка переключения чата */}
                <IconButton onClick={toggleChat} style={chatToggleButtonStyle}>
                    <ChatIcon />
                </IconButton>

                {/* Отображение чата поверх плеера */}
                {showChat && (
                    <div style={chatContainerStyle}>
                        {/* Кнопка закрытия внутри чата */}

                        {/* Сам чат */}
                        <Chat roomId={roomId} nickname={nickname} />
                    </div>
                )}
            </MediaPlayer>
        </div>
    );
};

export default Player;     socket.on('videoControl', async ({ roomId, action, data, timestamp }) => {


      let room = await Room.findOne({
        where: { roomId: roomId },
        include: ['members']
      });

      // Проверяем, может ли текущий пользователь управлять комнатой
     // if (!room.allowOthersControl && room.ownerId !== user.id) {
      //  socket.emit('errorMessage', { text: 'Только владелец может управлять комнатой' });
       // return;
      //}
      switch (action) {
        case "setUrl":

          a=await Room.update({ videoUrl: data }, { where: { roomId: roomId } });

          break;
        case "pause":

          await Room.update({ isPause: true }, { where: { roomId: roomId } });
          break;
        case "play":

          await Room.update({ isPause: false }, { where: { roomId: roomId } });

          break;
        case "seek":

          break;
        case "sync":
          return
          if (Math.abs(room.time - data) < 4) {
            await Room.update({time: Number(data)}, {where: {roomId: roomId}});
          }
            break;
        case "changeEpisode":
          console.log("asd");

      }

      await room.save();

      socket.to(room.id).emit('videoControl', { action: action, data: data, timestamp: timestamp });
    });
  });