Плавная смена видео через атрибут src js

Подскажите пожалуйста, как можно сделать плавную смену видео через JS. Есть массив с ссылками на видео, и я каждые 15 минут меняю атрибут src на рандомный из массива. Видео меняется очень резко, как сделать что бы оно менялась с плавной анимацией?

<!-- HTML -->
<video autoplay muted id="video">
</video>
// JavaScript
function viewRandomVideo() {
  var vids = ["video1.mp4",
            "video2.mp4",
            "video3.mp4"
            ];
  var randomVideo = vids[Math.floor(Math.random()*vids.length)];
  var videoElement = document.getElementById("video");
  videoElement.src = randomVideo;
};
setInterval(viewRandomVideo, 900000); // = 15 минут

Видео довольно большие, больше 15 минут, поэтому загружать их все сразу и поочередно менять opacity нельзя.


Ответы (1 шт):

Автор решения: De.Minov

Подробные комментария к работе скрипта внутри.

let videoURL = [ // Список ссылок на видео
  'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4',
  'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
  'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4'
],
  videoEL = document.querySelector('.random-video'), // Блок обёртка всех видео
  oldVideo = Math.floor(Math.random() * videoURL.length), // Рандомно выберем старовое видео (можно прописать индекс любого видео из списка)
  videos, // Тут будем хранить список всех видео
  timerTime = 1000*10, // Кол-во мс, через сколько будет смена видео
  opacityTime = 1000; // Кол-во мс, за сколько сменится видео ("плавность" перехода)

// Стартуем(©)
for(let url of videoURL) { // Проходим циклом по списку видео
  videoEL.insertAdjacentHTML('beforeend', `<video src="${url}" muted></video>`); // И создаём видео внутри блока для видео
}
videos = videoEL.querySelectorAll('video'); // Далее записываем все видео из блока в переменную
videos[oldVideo].play(); // Запускаем "стартовое" видео
videos[oldVideo].style.opacity = 1; // Выставляем ему "видемость"
videoEL.style.setProperty('--opacity-time', opacityTime); // Указываем время плавности перехода для всех видео ("переход делаем через CSS)
let timer = setTimeout(function RandomVideo() { // Запускаем функцию смены видео в рекурсивном таймере
  let newVideo = function NewVideo() {
    let rand = Math.floor(Math.random() * videoURL.length);
    if(oldVideo === rand) return NewVideo(); else return rand;
  }(); // Рандомно берём видео из списка
  
  let oldVideoEL = videos[oldVideo]; // Берём "старое" видео (точнее текущее, которое воспроизводится сейчас)
  oldVideoEL.style.opacity = 0; // плавно "спрячем"
  setTimeout(function() { // После того как закончится плавный проход прозрачности, выполним это:
    oldVideoEL.pause(); // Остановим "старое" видео
    oldVideoEL.currentTime = 0; // Поставим время на 0, чтобы потом он начался сначала
  }, opacityTime);

  let newVideoEL = videos[newVideo]; // "Новое" видео (или следующее рандомное)
  newVideoEL.play(); // Запустим "новое" видео
  newVideoEL.style.opacity = 1; // плавно "покажем" его
  
  oldVideo = newVideo; // Теперь "новое" видео будет "старым" (текущим)
  timer = setTimeout(RandomVideo, timerTime); // Запустим цикл заного
}, timerTime);
.random-video {
  display: block;
  background: red;
  width: 300px;
  height: 180px;
  position: relative;
  --opacity-time: 1;
}

.random-video > video {
  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0; top: 0; right: 0; bottom: 0;
  margin: 0;
  border: 0;
  opacity: 0;
  transition: all calc(var(--opacity-time) * 1ms) linear;
}
<div class="random-video"></div>

→ Ссылка