add html5 video to element

with support to callbacks on full cached

by Maksim Kachurin

HTML

Функция добавляет html5 видео внутрь элемента.
А еще она кэширует видео, перед воспроизведением и вызывает коллбэк после того как закэширует.

Зачем нужно?
Был проект, лендинг, в котором видео использовалось в 5 местах, в 3х вариациях:
1. Полноэкранное видео без звука в виде бэкграунда, дающее потрясающий внешний вид страницы.
2. То же самое видео, но открывающееся со звуком на весь экран (в фэнсибоксе)
3. Еще 4 видео, открывающееся в фэнсибоксе, но не на весь экран.

И проблемы, соответственно:
1. Видео сильно тормозило сайт, т.к вместе с загрузкой цсс, картинок и прочей разметки, браузер вытягивал видео размером в 13 мегабайт
2. Видео нельзя было подгружать в фэнсибокс ифреймом, потому что невозможно заставить содержимое внутри фрейма растянуться на 100% ширины и высоты, и видео показывалось в оригинальном разрешении , т.е маленьким квадратиком по центру, фэнсибокс с этим справиться никак не мог. Поэтому видео вынеслось в отдельный скрытый элемент, откуда его фэнси и показывал. Проблема - видео кэшировалось и замедляло сайт. Что легко обходилось запретом на прелоад и отключеным автоплей, но в итоге пришлось писать кучу скриптов в коллбеки фэнси, что бы видео воспроизводилось по открытию фэнси, останавливалось (и переставало кэшироваться, что стандартными методами не возможно) по закрытию и т.д
3. Нет проблем, видео просто открывалось в фрейме.

Было решено:
1. Написать некий код, который бы запускался только после полной загрузки сайта и запускал видео. По возможности немного закэшировать видео перед показом, что бы на медленных соединениях оно не дергалось  каждые 2 секунды буферизуясь.
2. Применить код из п.1, но повесить на коллбэк фенси перед открытием.

Так родилось это.
принимает аргументы:
1. Элемент внутрь которого вставлять видео. Может быть строкой или обьектом жквери
2. Обьект с аттрибутами тега video. Сюда пишем всякие автоплеи, классы, айди и все что вздумается, любые атрибуты.
3. Источник файла (пока только один, возможно когда нибудь сделаю что б...

JavaScript

// add html5 video to element
    function addHtml5Video(element, attr, src, type, percent_preload, callback) {
      var video = document.createElement('video'),
        source = document.createElement('source');

      source.src = src;
      source.type = type;
      video.appendChild(source);
      $(video).attr(attr).appendTo(element);

      window.video = video;

      if (attr.muted) {
        video.volume = 0; // fix mute in firefox
      }

      video.addEventListener("canplay", function() {
        this.removeEventListener("canplay", arguments.callee, false);

        // если не указано сколько подгружать перед показом - принимаем за 0
        if (!percent_preload) percent_preload = 0;
        // видео без длинны явно браковано
        if (!video.duration) return null;

        var temp = setInterval(function(){
          // весь смысл этой темы с интервалами в том, что файрфокс не очень то торопится загружать видео, и один раз из десяти роняет скрипт, т.к обращение к video.buffered.end(0) вызывает исключение
          if (!video.buffered.length) return;

          clearInterval(temp);
          if (Math.round((video.buffered.end(0) / video.duration) * 100) >= percent_preload) {
            // Видео уже загружено (из кэша, либо его не требуется предподгружать)
            // выполняем коллбэк
            if (typeof callback == 'function') {
              callback();
            }
            this.play();
            console.log('video loaded: already');
          }
          else {
            //  Отслеживаем изменение прогресса загрузки
            video.addEventListener("progress", function() {

              var percent = (video.buffered.end(0) / video.duration) * 100;
              console.log('video loaded: ' + percent + '%');

              if (percent >= percent_preload) {
                console.log('video loaded: success');
                // выполняем коллбэк
                if (typeof callback == 'function') {
                  callback();
...