Videos and audio don't play

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;
using UnityEngine.EventSystems;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using FMODUnity;
using FMOD.Studio;

public class DisneyPlusPlayer : MonoBehaviour
{
[Header(“Video Components”)]
public VideoPlayer videoPlayer;
public RenderTexture renderTexture;
public RawImage videoDisplay;

[Header("FMOD Audio")]
public EventReference videoAudioEvent; // FMOD event for video audio
private EventInstance videoAudioInstance;

[Header("UI Components")]
public Text titleText;
public Button nextEpisodeButton;
public Button skipIntroButton;
public Slider episodeProgressBar;
public Text subtitleText;

[Header("UI Containers (for overlay)")]
public CanvasGroup uiOverlayGroup; // Container for all overlay UI elements
public Canvas mainCanvas; // Main canvas for UI

[Header("Content")]
public VideoClip disneyIntro;
public VideoClip[] episodes;
public EventReference[] episodeFMODEvents; // FMOD events for each episode
public string[] episodeTitles;

[Header("Subtitles")]
public bool subtitlesEnabled = false;
public TextAsset[] subtitleFiles;

[Header("Display Settings")]
public bool maintainAspectRatio = true;
public bool fullScreenVideo = true;
public float uiHideDelay = 3f; // Time before UI hides after no mouse movement

[Header("Playback Controls")]
public KeyCode playPauseKey = KeyCode.Space;
public string playPauseButtonPS5 = "X"; // PS5 X button
public string playPauseButtonXbox = "A"; // Xbox A button
public float controllerSeekSpeed = 0.5f; // Speed for controller seeking

[Header("FMOD Parameters")]
public string volumeParameter = "Volume";
public float defaultVolume = 1f;

private int currentEpisode = 0;
private bool introSkipped = false;
private bool isNextEpisodeAutoPlay = false;
private bool isPlayingIntro = false;
private bool isSeeking = false;
private bool isFMODPlaying = false;

private Dictionary<double, string> subtitles;
private Vector3 lastMousePosition;
private float timeSinceLastMouseMove;
private bool isUIVisible = true;
private Coroutine hideUICoroutine;
private Coroutine nextEpisodeCoroutine;
private Coroutine syncCoroutine;

void Start()
{
    SetupVideoPlayer();
    SetupUI();
    SetupFullScreenVideo();
    lastMousePosition = Input.mousePosition;

    // Wait a frame before playing to ensure everything is set up
    StartCoroutine(DelayedStart());
}

IEnumerator DelayedStart()
{
    yield return new WaitForEndOfFrame();
    PlayIntro();
}

void SetupVideoPlayer()
{
    if (videoPlayer == null)
    {
        videoPlayer = GetComponent<VideoPlayer>();
    }

    // Create full-screen render texture
    CreateFullScreenRenderTexture();

    videoPlayer.renderMode = VideoRenderMode.RenderTexture;
    videoPlayer.targetTexture = renderTexture;
    videoPlayer.waitForFirstFrame = true;
    videoPlayer.prepareCompleted += OnVideoPrepared;
    videoPlayer.audioOutputMode = VideoAudioOutputMode.None; // Disable Unity audio output

    if (videoDisplay != null)
    {
        videoDisplay.texture = renderTexture;
    }
    else
    {
        Debug.LogError("VideoDisplay RawImage is not assigned!");
    }
}

void OnVideoPrepared(VideoPlayer vp)
{
    Debug.Log("Video prepared and ready to play");
}

void CreateFullScreenRenderTexture()
{
    // Get screen dimensions
    int screenWidth = Screen.width;
    int screenHeight = Screen.height;

    // Ensure minimum size
    if (screenWidth < 1920) screenWidth = 1920;
    if (screenHeight < 1080) screenHeight = 1080;

    if (renderTexture != null)
    {
        renderTexture.Release();
    }

    renderTexture = new RenderTexture(screenWidth, screenHeight, 24);
    renderTexture.antiAliasing = 1;
    renderTexture.Create();

    Debug.Log($"Created RenderTexture: {screenWidth}x{screenHeight}");
}

void SetupFullScreenVideo()
{
    if (videoDisplay != null && fullScreenVideo)
    {
        // Remove any aspect ratio fitter that might constrain the video
        AspectRatioFitter arf = videoDisplay.GetComponent<AspectRatioFitter>();
        if (arf != null)
        {
            DestroyImmediate(arf);
        }

        // Make video fill entire screen
        RectTransform videoRect = videoDisplay.GetComponent<RectTransform>();
        if (videoRect != null)
        {
            videoRect.anchorMin = Vector2.zero;
            videoRect.anchorMax = Vector2.one;
            videoRect.offsetMin = Vector2.zero;
            videoRect.offsetMax = Vector2.zero;
            videoRect.anchoredPosition = Vector2.zero;

            // Ensure it's behind UI
            videoDisplay.transform.SetAsFirstSibling();
        }

        // Set UV coordinates to fill and crop appropriately
        videoDisplay.uvRect = new Rect(0, 0, 1, 1);
    }

    // Setup canvas for UI overlay
    if (mainCanvas == null)
    {
        mainCanvas = FindFirstObjectByType<Canvas>();
    }

    if (mainCanvas != null)
    {
        mainCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
        mainCanvas.sortingOrder = 10; // Ensure UI is on top
    }
}

void SetupUI()
{
    // Create or find UI overlay group
    if (uiOverlayGroup == null)
    {
        // Try to find existing overlay group first
        uiOverlayGroup = FindFirstObjectByType<CanvasGroup>();

        if (uiOverlayGroup == null)
        {
            GameObject overlayObj = new GameObject("UI Overlay");
            overlayObj.transform.SetParent(mainCanvas.transform, false);
            uiOverlayGroup = overlayObj.AddComponent<CanvasGroup>();

            RectTransform overlayRect = overlayObj.GetComponent<RectTransform>();
            overlayRect.anchorMin = Vector2.zero;
            overlayRect.anchorMax = Vector2.one;
            overlayRect.offsetMin = Vector2.zero;
            overlayRect.offsetMax = Vector2.zero;
        }
    }

    // Position UI elements like Disney+
    PositionUIElements();

    // Initial UI state - hide everything initially
    if (nextEpisodeButton != null) nextEpisodeButton.gameObject.SetActive(false);
    if (skipIntroButton != null) skipIntroButton.gameObject.SetActive(false);
    if (episodeProgressBar != null) episodeProgressBar.gameObject.SetActive(false);
    if (subtitleText != null) subtitleText.gameObject.SetActive(subtitlesEnabled);
    if (titleText != null) titleText.gameObject.SetActive(false);

    // Setup button listeners
    if (skipIntroButton != null) skipIntroButton.onClick.AddListener(SkipIntro);
    if (nextEpisodeButton != null) nextEpisodeButton.onClick.AddListener(OnNextEpisodeButtonClicked);

    // Setup slider events
    SetupSliderEvents();

    // Start with UI hidden
    if (uiOverlayGroup != null)
    {
        uiOverlayGroup.alpha = 0f;
        isUIVisible = false;
    }
}

void SetupSliderEvents()
{
    if (episodeProgressBar != null)
    {
        // Add event triggers for slider
        EventTrigger trigger = episodeProgressBar.gameObject.AddComponent<EventTrigger>();

        // Pointer down event
        var pointerDown = new EventTrigger.Entry();
        pointerDown.eventID = EventTriggerType.PointerDown;
        pointerDown.callback.AddListener((data) => { OnSliderPointerDown(); });
        trigger.triggers.Add(pointerDown);

        // Pointer up event
        var pointerUp = new EventTrigger.Entry();
        pointerUp.eventID = EventTriggerType.PointerUp;
        pointerUp.callback.AddListener((data) => { OnSliderPointerUp(); });
        trigger.triggers.Add(pointerUp);
    }
}

void OnSliderPointerDown()
{
    isSeeking = true;
    videoPlayer.Pause();
    if (isFMODPlaying && videoAudioInstance.isValid())
    {
        videoAudioInstance.setPaused(true);
    }
}

void OnSliderPointerUp()
{
    if (isSeeking)
    {
        isSeeking = false;
        SeekToTime(episodeProgressBar.value * videoPlayer.clip.length);
    }
}

void SeekToTime(double time)
{
    if (videoPlayer.clip == null) return;

    time = Mathf.Clamp((float)time, 0, (float)videoPlayer.clip.length);
    videoPlayer.time = time;

    if (videoAudioInstance.isValid())
    {
        // Convert seconds to milliseconds for FMOD
        int msPosition = (int)(time * 1000);
        videoAudioInstance.setTimelinePosition(msPosition);
    }

    videoPlayer.Play();
    if (videoAudioInstance.isValid())
    {
        videoAudioInstance.setPaused(false);
        isFMODPlaying = true;
    }

    // Update subtitles immediately after seeking
    if (subtitlesEnabled)
    {
        DisplaySubtitle();
    }

    // Restart sync coroutine
    if (syncCoroutine != null)
    {
        StopCoroutine(syncCoroutine);
    }
    syncCoroutine = StartCoroutine(SyncFMODWithVideo());
}

void PositionUIElements()
{
    // Position title at top-left
    if (titleText != null)
    {
        RectTransform titleRect = titleText.GetComponent<RectTransform>();
        titleRect.anchorMin = new Vector2(0, 1);
        titleRect.anchorMax = new Vector2(0, 1);
        titleRect.anchoredPosition = new Vector2(50, -50);
        titleRect.sizeDelta = new Vector2(400, 50);
    }

    // Position progress bar at bottom
    if (episodeProgressBar != null)
    {
        RectTransform progressRect = episodeProgressBar.GetComponent<RectTransform>();
        progressRect.anchorMin = new Vector2(0, 0);
        progressRect.anchorMax = new Vector2(1, 0);
        progressRect.anchoredPosition = new Vector2(0, 40);
        progressRect.sizeDelta = new Vector2(-100, 20);
    }

    // Position next episode button at bottom-right
    if (nextEpisodeButton != null)
    {
        RectTransform buttonRect = nextEpisodeButton.GetComponent<RectTransform>();
        buttonRect.anchorMin = new Vector2(1, 0);
        buttonRect.anchorMax = new Vector2(1, 0);
        buttonRect.anchoredPosition = new Vector2(-150, 100);
        buttonRect.sizeDelta = new Vector2(200, 50);
    }

    // Position skip intro button at bottom-right
    if (skipIntroButton != null)
    {
        RectTransform skipRect = skipIntroButton.GetComponent<RectTransform>();
        skipRect.anchorMin = new Vector2(1, 0);
        skipRect.anchorMax = new Vector2(1, 0);
        skipRect.anchoredPosition = new Vector2(-100, 100);
        skipRect.sizeDelta = new Vector2(150, 40);
    }

    // Position subtitles at bottom-center
    if (subtitleText != null)
    {
        RectTransform subtitleRect = subtitleText.GetComponent<RectTransform>();
        subtitleRect.anchorMin = new Vector2(0.5f, 0);
        subtitleRect.anchorMax = new Vector2(0.5f, 0);
        subtitleRect.anchoredPosition = new Vector2(0, 80);
        subtitleRect.sizeDelta = new Vector2(800, 60);
    }
}

void Update()
{
    HandleMouseMovement();
    HandleKeyboardAndControllerInput();
    HandlePlayPauseInput();
    HandleControllerSeeking();

    if (videoPlayer.isPlaying && !isSeeking)
    {
        UpdateProgressBar();

        if (subtitlesEnabled && subtitles != null && subtitles.Count > 0)
        {
            DisplaySubtitle();
        }
    }
}

void HandlePlayPauseInput()
{
    bool playPausePressed = false;

    // Check keyboard
    if (Input.GetKeyDown(playPauseKey))
    {
        playPausePressed = true;
    }

    // Check PS5 controller
    if (Input.GetButtonDown(playPauseButtonPS5))
    {
        playPausePressed = true;
    }

    // Check Xbox controller
    if (Input.GetButtonDown(playPauseButtonXbox))
    {
        playPausePressed = true;
    }

    if (playPausePressed)
    {
        TogglePlayPause();
    }
}

void TogglePlayPause()
{
    if (videoPlayer.isPlaying)
    {
        videoPlayer.Pause();
        if (videoAudioInstance.isValid())
        {
            videoAudioInstance.setPaused(true);
            isFMODPlaying = false;
        }
    }
    else
    {
        videoPlayer.Play();
        if (videoAudioInstance.isValid())
        {
            videoAudioInstance.setPaused(false);
            isFMODPlaying = true;
            StartCoroutine(SyncFMODWithVideo());
        }
    }

    // Show UI when pausing/playing
    ShowUI();
    if (hideUICoroutine != null)
    {
        StopCoroutine(hideUICoroutine);
    }
    hideUICoroutine = StartCoroutine(HideUIAfterDelay());
}

void HandleControllerSeeking()
{
    if (isSeeking) return; // Don't allow controller seeking while dragging slider

    float horizontalInput = Input.GetAxis("Horizontal");
    if (Mathf.Abs(horizontalInput) > 0.2f)
    {
        if (videoPlayer.isPlaying)
        {
            double seekAmount = horizontalInput * controllerSeekSpeed * Time.deltaTime;
            double newTime = videoPlayer.time + seekAmount;
            SeekToTime(newTime);

            // Update progress bar immediately
            if (episodeProgressBar != null && videoPlayer.clip != null)
            {
                episodeProgressBar.value = (float)(newTime / videoPlayer.clip.length);
            }

            // Show UI when seeking
            ShowUI();
            if (hideUICoroutine != null)
            {
                StopCoroutine(hideUICoroutine);
            }
            hideUICoroutine = StartCoroutine(HideUIAfterDelay());
        }
    }
}

void HandleKeyboardAndControllerInput()
{
    // Check for any keyboard input
    if (Input.anyKeyDown)
    {
        if (!isUIVisible)
        {
            ShowUI();
        }

        if (hideUICoroutine != null)
        {
            StopCoroutine(hideUICoroutine);
        }
        hideUICoroutine = StartCoroutine(HideUIAfterDelay());
    }

    // Check for controller input
    if (Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0 ||
        Input.GetButtonDown("Submit") || Input.GetButtonDown("Cancel") ||
        Input.GetButtonDown("Jump") || Input.GetButtonDown("Fire1"))
    {
        if (!isUIVisible)
        {
            ShowUI();
        }

        if (hideUICoroutine != null)
        {
            StopCoroutine(hideUICoroutine);
        }
        hideUICoroutine = StartCoroutine(HideUIAfterDelay());
    }
}

void HandleMouseMovement()
{
    Vector3 currentMousePos = Input.mousePosition;

    // Check if mouse moved significantly
    if (Vector3.Distance(currentMousePos, lastMousePosition) > 1f)
    {
        lastMousePosition = currentMousePos;
        timeSinceLastMouseMove = 0f;

        // Show UI if it's hidden
        if (!isUIVisible)
        {
            ShowUI();
        }

        // Reset hide timer
        if (hideUICoroutine != null)
        {
            StopCoroutine(hideUICoroutine);
        }
        hideUICoroutine = StartCoroutine(HideUIAfterDelay());
    }
    else
    {
        timeSinceLastMouseMove += Time.deltaTime;
    }

    // Also check for any mouse clicks
    if (Input.GetMouseButtonDown(0))
    {
        if (!isUIVisible)
        {
            ShowUI();
        }

        if (hideUICoroutine != null)
        {
            StopCoroutine(hideUICoroutine);
        }
        hideUICoroutine = StartCoroutine(HideUIAfterDelay());
    }
}

IEnumerator HideUIAfterDelay()
{
    yield return new WaitForSeconds(uiHideDelay);

    // Don't hide UI during intro or when next episode button is active
    if (!isPlayingIntro && (nextEpisodeButton == null || !nextEpisodeButton.gameObject.activeInHierarchy))
    {
        HideUI();
    }
}

void ShowUI()
{
    if (uiOverlayGroup != null)
    {
        isUIVisible = true;
        StopAllCoroutines();
        StartCoroutine(FadeUI(uiOverlayGroup.alpha, 1f, 0.3f));

        // Show appropriate UI elements
        if (titleText != null && !string.IsNullOrEmpty(titleText.text))
        {
            titleText.gameObject.SetActive(true);
        }

        // Only show progress bar and buttons when UI is visible due to interaction
        if (episodeProgressBar != null && videoPlayer.isPlaying && !isPlayingIntro)
        {
            episodeProgressBar.gameObject.SetActive(true);
        }

        if (skipIntroButton != null && isPlayingIntro)
        {
            skipIntroButton.gameObject.SetActive(true);
        }

        // Always show next episode button if it's active (regardless of why UI is showing)
        if (nextEpisodeButton != null && nextEpisodeButton.gameObject.activeSelf)
        {
            nextEpisodeButton.gameObject.SetActive(true);
        }
    }
}

void HideUI()
{
    if (uiOverlayGroup != null && !isPlayingIntro)
    {
        isUIVisible = false;
        StartCoroutine(FadeUI(uiOverlayGroup.alpha, 0f, 0.5f));

        // Hide interactive elements when UI fades out
        if (episodeProgressBar != null)
        {
            episodeProgressBar.gameObject.SetActive(false);
        }

        if (skipIntroButton != null)
        {
            skipIntroButton.gameObject.SetActive(false);
        }

        // Only hide next episode button if it's not in the "filling" state
        if (nextEpisodeButton != null && nextEpisodeCoroutine == null)
        {
            nextEpisodeButton.gameObject.SetActive(false);
        }
    }
}

IEnumerator FadeUI(float fromAlpha, float toAlpha, float duration)
{
    float elapsed = 0f;
    while (elapsed < duration)
    {
        elapsed += Time.deltaTime;
        if (uiOverlayGroup != null)
        {
            uiOverlayGroup.alpha = Mathf.Lerp(fromAlpha, toAlpha, elapsed / duration);
        }
        yield return null;
    }
    if (uiOverlayGroup != null)
    {
        uiOverlayGroup.alpha = toAlpha;
    }
}

void PlayIntro()
{
    if (disneyIntro == null)
    {
        Debug.LogWarning("No intro video assigned, skipping to episode");
        PlayEpisode(currentEpisode);
        return;
    }

    isPlayingIntro = true;
    ShowUI(); // Always show UI during intro

    if (skipIntroButton != null)
    {
        skipIntroButton.gameObject.SetActive(true);
    }

    if (titleText != null)
    {
        titleText.text = "Disney+";
        titleText.gameObject.SetActive(true);
    }

    videoPlayer.clip = disneyIntro;
    videoPlayer.audioOutputMode = VideoAudioOutputMode.None;

    // Play FMOD audio for intro if assigned
    if (!videoAudioEvent.IsNull)
    {
        StopFMODAudio();
        videoAudioInstance = RuntimeManager.CreateInstance(videoAudioEvent);
        if (videoAudioInstance.isValid())
        {
            videoAudioInstance.setVolume(defaultVolume);
            videoAudioInstance.start();
            isFMODPlaying = true;
        }
    }

    videoPlayer.Prepare();
    videoPlayer.prepareCompleted += OnIntroPrepared;
}

void OnIntroPrepared(VideoPlayer vp)
{
    videoPlayer.prepareCompleted -= OnIntroPrepared;
    videoPlayer.Play();
    videoPlayer.loopPointReached += OnIntroFinished;
    Debug.Log("Playing intro video");
}

void OnIntroFinished(VideoPlayer vp)
{
    videoPlayer.loopPointReached -= OnIntroFinished;
    isPlayingIntro = false;

    if (skipIntroButton != null)
    {
        skipIntroButton.gameObject.SetActive(false);
    }

    StopFMODAudio();
    PlayEpisode(currentEpisode);
}

void SkipIntro()
{
    if (isPlayingIntro)
    {
        introSkipped = true;
        isPlayingIntro = false;

        if (skipIntroButton != null)
        {
            skipIntroButton.gameObject.SetActive(false);
        }

        videoPlayer.Stop();
        StopFMODAudio();

        // Remove the intro finished listener to prevent it from firing
        videoPlayer.loopPointReached -= OnIntroFinished;

        PlayEpisode(currentEpisode);
    }
}

void PlayEpisode(int episodeIndex)
{
    if (episodes == null || episodeIndex >= episodes.Length)
    {
        Debug.LogError("Episode index out of range or no episodes assigned!");
        return;
    }

    if (episodes[episodeIndex] == null)
    {
        Debug.LogError($"Episode {episodeIndex} is null!");
        return;
    }

    if (titleText != null && episodeTitles != null && episodeIndex < episodeTitles.Length)
    {
        titleText.text = episodeTitles[episodeIndex];
        titleText.gameObject.SetActive(true);
    }

    if (episodeProgressBar != null)
    {
        episodeProgressBar.gameObject.SetActive(true);
        episodeProgressBar.value = 0f;
    }

    videoPlayer.clip = episodes[episodeIndex];
    videoPlayer.audioOutputMode = VideoAudioOutputMode.None;

    // Set up FMOD audio for episode
    if (episodeFMODEvents != null && episodeIndex < episodeFMODEvents.Length)
    {
        StopFMODAudio();
        videoAudioInstance = RuntimeManager.CreateInstance(episodeFMODEvents[episodeIndex]);
        if (videoAudioInstance.isValid())
        {
            videoAudioInstance.setVolume(defaultVolume);
        }
    }

    videoPlayer.Prepare();
    videoPlayer.prepareCompleted += OnEpisodePrepared;

    if (subtitlesEnabled && subtitleFiles != null && subtitleFiles.Length > episodeIndex)
    {
        subtitles = ParseSubtitles(subtitleFiles[episodeIndex]);
    }
}

void OnEpisodePrepared(VideoPlayer vp)
{
    videoPlayer.prepareCompleted -= OnEpisodePrepared;
    videoPlayer.Play();

    if (videoAudioInstance.isValid())
    {
        videoAudioInstance.start();
        isFMODPlaying = true;
        syncCoroutine = StartCoroutine(SyncFMODWithVideo());
    }

    videoPlayer.loopPointReached += OnEpisodeFinished;
    Debug.Log($"Playing episode {currentEpisode}");

    // Start the UI hide timer
    if (hideUICoroutine != null)
    {
        StopCoroutine(hideUICoroutine);
    }
    hideUICoroutine = StartCoroutine(HideUIAfterDelay());
}

IEnumerator SyncFMODWithVideo()
{
    while (videoPlayer.isPlaying && videoAudioInstance.isValid())
    {
        videoAudioInstance.getPlaybackState(out PLAYBACK_STATE state);
        
        // Convert video time to milliseconds for FMOD
        int targetPosition = (int)(videoPlayer.time * 1000);
        videoAudioInstance.setTimelinePosition(targetPosition);
        
        yield return new WaitForSeconds(0.1f);
    }
}

void OnEpisodeFinished(VideoPlayer vp)
{
    Debug.Log("Episode finished playing");
    videoPlayer.loopPointReached -= OnEpisodeFinished;

    if (episodeProgressBar != null)
    {
        episodeProgressBar.value = 1f;
    }

    StopFMODAudio();

    ShowNextEpisodeButton();
}

void UpdateProgressBar()
{
    if (videoPlayer.clip != null && episodeProgressBar != null && !isPlayingIntro && !isSeeking)
    {
        double progress = videoPlayer.time / videoPlayer.clip.length;
        episodeProgressBar.value = (float)progress;
    }
}

void ShowNextEpisodeButton()
{
    Debug.Log($"ShowNextEpisodeButton called. Current episode: {currentEpisode}, Total episodes: {episodes?.Length}");

    if (nextEpisodeButton != null)
    {
        Debug.Log("Next episode button reference exists");
    }
    else
    {
        Debug.LogError("Next episode button is null!");
        return;
    }

    if (currentEpisode + 1 < episodes.Length)
    {
        Debug.Log("There is a next episode available");
        nextEpisodeButton.gameObject.SetActive(true);
        ShowUI();
        // Reset the button fill state
        Image buttonImage = nextEpisodeButton.GetComponent<Image>();
        if (buttonImage != null)
        {
            buttonImage.type = Image.Type.Simple;
            buttonImage.fillAmount = 1;
        }

        if (nextEpisodeCoroutine != null)
        {
            StopCoroutine(nextEpisodeCoroutine);
        }
        nextEpisodeCoroutine = StartCoroutine(FillNextEpisodeButton());
    }
    else
    {
        Debug.Log("No more episodes available");
    }
}

IEnumerator FillNextEpisodeButton()
{
    Image buttonImage = nextEpisodeButton.GetComponent<Image>();
    if (buttonImage != null)
    {
        buttonImage.type = Image.Type.Filled;
        buttonImage.fillMethod = Image.FillMethod.Horizontal;
        buttonImage.fillAmount = 0;

        float duration = 5f;
        float elapsed = 0f;

        while (elapsed < duration && nextEpisodeButton.gameObject.activeInHierarchy)
        {
            elapsed += Time.deltaTime;
            buttonImage.fillAmount = Mathf.Clamp01(elapsed / duration);
            yield return null;
        }

        if (nextEpisodeButton.gameObject.activeInHierarchy && !isNextEpisodeAutoPlay)
        {
            OnNextEpisodeButtonClicked();
        }
    }
}

void OnNextEpisodeButtonClicked()
{
    if (nextEpisodeCoroutine != null)
    {
        StopCoroutine(nextEpisodeCoroutine);
    }

    if (nextEpisodeButton != null)
    {
        nextEpisodeButton.gameObject.SetActive(false);
    }

    isNextEpisodeAutoPlay = false;
    currentEpisode++;

    if (currentEpisode < episodes.Length)
    {
        introSkipped = false;
        PlayIntro();
    }
    else
    {
        Debug.Log("All episodes finished!");
        if (titleText != null)
        {
            titleText.text = "Series Complete!";
            titleText.gameObject.SetActive(true);
        }
    }
}

void StopFMODAudio()
{
    if (videoAudioInstance.isValid())
    {
        videoAudioInstance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
        videoAudioInstance.release();
        isFMODPlaying = false;
    }
    
    if (syncCoroutine != null)
    {
        StopCoroutine(syncCoroutine);
    }
}

// Optional: Method to control FMOD volume
public void SetFMODVolume(float volume)
{
    if (videoAudioInstance.isValid())
    {
        videoAudioInstance.setVolume(Mathf.Clamp01(volume));
    }
}

// Optional: Method to set FMOD parameter
public void SetFMODParameter(string parameterName, float value)
{
    if (videoAudioInstance.isValid())
    {
        videoAudioInstance.setParameterByName(parameterName, value);
    }
}

Dictionary<double, string> ParseSubtitles(TextAsset subtitleFile)
{
    if (subtitleFile == null)
    {
        return new Dictionary<double, string>();
    }

    string extension = Path.GetExtension(subtitleFile.name).ToLower();
    switch (extension)
    {
        case ".srt":
            return ParseSRT(subtitleFile.text);
        case ".vtt":
            return ParseVTT(subtitleFile.text);
        case ".ass":
            return ParseASS(subtitleFile.text);
        default:
            Debug.LogError("Unsupported subtitle format: " + extension);
            return new Dictionary<double, string>();
    }
}

Dictionary<double, string> ParseSRT(string subtitleText)
{
    var subtitleDict = new Dictionary<double, string>();
    string[] blocks = Regex.Split(subtitleText, @"\r?\n\r?\n");

    foreach (string block in blocks)
    {
        if (string.IsNullOrWhiteSpace(block)) continue;

        string[] lines = Regex.Split(block.Trim(), @"\r?\n");
        if (lines.Length < 3) continue;

        string timeLine = lines[1];
        if (timeLine.Contains("-->"))
        {
            string[] timeParts = timeLine.Split(new string[] { "-->" }, System.StringSplitOptions.None);
            if (timeParts.Length == 2)
            {
                double startTime = ParseTimestampSRT(timeParts[0].Trim());
                string subtitleLine = "";
                for (int i = 2; i < lines.Length; i++)
                {
                    if (i > 2) subtitleLine += " ";
                    subtitleLine += lines[i];
                }

                if (!string.IsNullOrEmpty(subtitleLine))
                {
                    subtitleDict[startTime] = subtitleLine;
                }
            }
        }
    }

    return subtitleDict;
}

Dictionary<double, string> ParseVTT(string subtitleText)
{
    var subtitleDict = new Dictionary<double, string>();
    string[] lines = Regex.Split(subtitleText, @"\r?\n");

    for (int i = 0; i < lines.Length; i++)
    {
        string line = lines[i].Trim();

        if (line.Contains("-->"))
        {
            string[] timeParts = line.Split(new string[] { "-->" }, System.StringSplitOptions.None);
            if (timeParts.Length == 2)
            {
                double startTime = ParseTimestampVTT(timeParts[0].Trim());
                string subtitleLine = "";
                for (int j = i + 1; j < lines.Length && !string.IsNullOrWhiteSpace(lines[j]); j++)
                {
                    if (!string.IsNullOrEmpty(subtitleLine)) subtitleLine += " ";
                    subtitleLine += lines[j].Trim();
                }

                if (!string.IsNullOrEmpty(subtitleLine))
                {
                    subtitleDict[startTime] = subtitleLine;
                }
            }
        }
    }

    return subtitleDict;
}

Dictionary<double, string> ParseASS(string subtitleText)
{
    var subtitleDict = new Dictionary<double, string>();
    string[] lines = Regex.Split(subtitleText, @"\r?\n");

    foreach (string line in lines)
    {
        if (line.StartsWith("Dialogue:"))
        {
            string[] parts = line.Split(',');
            if (parts.Length > 9)
            {
                double timestamp = ParseTimestampASS(parts[1].Trim());
                string subtitleLine = parts[9];
                for (int i = 10; i < parts.Length; i++)
                {
                    subtitleLine += "," + parts[i];
                }

                if (!string.IsNullOrEmpty(subtitleLine))
                {
                    subtitleDict[timestamp] = subtitleLine;
                }
            }
        }
    }

    return subtitleDict;
}

double ParseTimestampSRT(string timestamp)
{
    try
    {
        string[] timeParts = timestamp.Split(':');
        string[] secondsParts = timeParts[2].Split(',');

        int hours = int.Parse(timeParts[0]);
        int minutes = int.Parse(timeParts[1]);
        int seconds = int.Parse(secondsParts[0]);
        int milliseconds = int.Parse(secondsParts[1]);

        return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000.0;
    }
    catch
    {
        return 0;
    }
}

double ParseTimestampVTT(string timestamp)
{
    try
    {
        string[] timeParts = timestamp.Split(':');
        string[] secondsParts = timeParts[2].Split('.');

        int hours = int.Parse(timeParts[0]);
        int minutes = int.Parse(timeParts[1]);
        int seconds = int.Parse(secondsParts[0]);
        int milliseconds = int.Parse(secondsParts[1]);

        return hours * 3600 + minutes * 60 + seconds + milliseconds / 1000.0;
    }
    catch
    {
        return 0;
    }
}

double ParseTimestampASS(string timestamp)
{
    try
    {
        string[] timeParts = timestamp.Split(':');
        string[] secondsParts = timeParts[2].Split('.');

        int hours = int.Parse(timeParts[0]);
        int minutes = int.Parse(timeParts[1]);
        int seconds = int.Parse(secondsParts[0]);
        int centiseconds = int.Parse(secondsParts[1]);

        return hours * 3600 + minutes * 60 + seconds + centiseconds / 100.0;
    }
    catch
    {
        return 0;
    }
}

void DisplaySubtitle()
{
    if (subtitleText == null) return;

    double currentTime = videoPlayer.time;
    string currentSubtitle = "";

    foreach (var kvp in subtitles)
    {
        if (currentTime >= kvp.Key && currentTime <= kvp.Key + 3)
        {
            currentSubtitle = kvp.Value;
            break;
        }
    }

    if (subtitleText.text != currentSubtitle)
    {
        subtitleText.text = currentSubtitle;
    }
}

void OnDestroy()
{
    if (renderTexture != null)
    {
        renderTexture.Release();
    }

    if (hideUICoroutine != null)
    {
        StopCoroutine(hideUICoroutine);
    }

    if (nextEpisodeCoroutine != null)
    {
        StopCoroutine(nextEpisodeCoroutine);
    }

    if (syncCoroutine != null)
    {
        StopCoroutine(syncCoroutine);
    }

    StopFMODAudio();
}

void OnValidate()
{
    if (videoPlayer == null)
    {
        videoPlayer = GetComponent<VideoPlayer>();
    }
}

}

Videos and audio don’t play - when I use the slicer to move the video the audio glitches by playing the same audio frame on repeat and the video frame is stucked… I have been trying to fix it a long time and still don’t know the reason of this issue… could you please try this script in Unity and fix it for me?

DisneyPlusPlayer.txt (34.7 KB)