Код магнитолы

JS и не только

Java - это...интересно

Hello, Android!

Assembler...м-м-э

Создаём сайт

Любимые сериалы

Гостевая

Что по чём?

Astrometa:TVR-player

Счётчик для сайта


Если интересуешся программированием, то пройти, мимо JavaScript & Ko, довольно трудно. Тем более, что много функций JS встроено, например, в OS Windows. Грех этим не попользоваться. Например - при создании медиа-проигрывателя.

Все script-ы, в гости, к нам

Это - плеер, для сайта, с позволения технологии HTML5. Есть поддержка - есть плеер. Помимо этого, в работе над плеером, учавствовали - JavaScript, CSS3 и SVG. Плеер создан под Chrome, в плане стиля.
Начнём, пожалуй - с HTML:
.....
<div id="media" class="flex media"> 
    <div id="cont" class="flex cont" title="размер экрана">RS</div> 
    <video>
        <source src="disk:/path/to/file.mp4" type="video/mp4" /> 
        <font color="red"><video>, тут, не пляшет</font>
    </video>
    <div id="video-control" class="flex video-control">
        <div id="bar" class="flex bar">
            <input type="range" id="progres" class="progres" value="0" min="0" max="1" step="0.01" title="прогресс" />
            <span id="progres-tip" class="progres-tip">00:00:00</span>
        </div>
        <span id="play" class="play" title="пуск"><svg><path d="M11,9 L22,15 11,21 Z"></path></svg></span>
        <span id="pause" class="pause" title="пауза">
            <svg><path d="M10,10 L14,10 14,20 10,20 M16,10 L20,10 20,20 16,20 Z"></path></svg>
        </span>
        <span id="stop" class="stop" title="возврат к началу">
            <svg><path d="M10,10 L20,10 20,20 10,20 Z"></path></svg>
        </span>  
        <input type="range" id="saund" class="saund" value="0" min="0" max="1" step="0.01" title="громкость" />
        <span id="saund-tip" class="saund-tip"></span>
        <span id="play-time" class="play-time" title="текущее время">00:00:00</span>
        <span class="slash"> / </span>
        <span id="full-time" class="full-time" title="общее время">00:00:00</span>
        <span id="pip" class="pip" title="картинка-в-картинке">
            <svg><path d="M7.5,7.5 L22.5,7.5 22.5,17.5 7.5,17.5 M17.5,20 L22.5,20 22.5,22.5 17.5,22.5 Z"></path></svg>
        </span>
        <span id="full" class="full" title="полный экран">
            <svg><path d="M7.5,10 L7.5,22.5 20,22.5 M10,7.5 L22.5,7.5 22.5,20 Z"></path></svg>
        </span>
    </div>
</div>
.....

Как видно из приведённого кода - в плеере задействованы кнопки, созданные на базе SVG-технологии. Всего, этих кнопок - пять. Отсутствует кнопка локального выбора файла. О ней - ниже. Кроме этого - присутствуют - шкала прогресса, шкала контроля уровня звука, таймеры полного времени и времени воспроизведения, индикаторы выбора эпизода и уровня громкости.
Особого внимания заслуживает контейнер cont. За этот контейнер, мышкой, можно менять размеры "экрана" плеера, сохраняя соотношение сторон.

Всё будет стильно?

Сначала - общие контуры и симпатичный, вспомогатльный класс:
@charset "UTF-8";
body {
  background: #ccc; 
  color: #000; 
}
.flex { 
    display: flex;
    align-items: center;
} 

Общий контейнер с видео (экраном)...во весь контейнер:
.media { 
    position: relative;  
    width: 480px; 
    height: 270px; 
}
video { 
    width: 100%; 
    height: 100%;
}

Вспомогательный контейнер (заведующий параметрами изображения) и панель управления плеером:
.cont {
    position: absolute;
    top: 0;
    right: 0; 
    bottom: 0;
    width: 5px; 	
    z-index: 100;	
}
.cont:active, cont:hover {
    cursor: se-resize; 
} 
.video-control {                     
    position: absolute;
    right: 0;
    left: 0;
    bottom: 0; 
    height: 30px;            
    transition: all 2s ease;
    background: rgba(0, 0, 0, 0.5); 
}

Бар, под прогресс, который - отдельно, над панелью управления:
  
.bar { 
    position: absolute;                           
    width: 100%;
    height: 15px;
    bottom: 100%;
    background: rgba(0, 0, 0, 0.5); 
}

Шкала прогресса и окошко контроля, за выбором эпизода:
.progres { 
    width: 97%; 
    margin: 0 0 0 1.5%; 
    cursor: pointer;
} 
.progres:hover + .progres-tip {
    opacity: 1;
}
.progres-tip {  
    position: absolute;
    bottom: 100%; 
    content: "";      
    opacity: 0;  
    font: bold 10px verdana;  
    color: #000;
    background: #ccc; 
}

Шкала громкости и окошко контроля, за уровнем:
.saund {  
    width: 15%;
    margin: 0 0 0 10px; 
    cursor: pointer; 
}
.saund:hover + .saund-tip {
    opacity: 1;
}
.saund-tip {  
    position: absolute;
    bottom: 70%; 
    content: "";      
    opacity: 0;  
    font: bold 10px verdana;  
    color: #000;
    background: #ccc; 
}

Интерфейс прогресса и громкости (они - через input):
 
input[type=range]{
    -webkit-appearance: none;    
    height: 3px; 
    background: #363636;         
    cursor: pointer;   
} 
input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
    height: 9px;
    width: 9px;
    border-radius: 100%;
    background: #ff0000;   
}
input{    
  border: none; 
  outline: none;
  padding: none; 
}
Вариант, к слову сказать - не самый удачный.
Кнопочки и таймеры:
.play {
    margin-left: 2%;
} 
.play-time, .full-time, .slash {
    color: #ccc;
    font: normal 12px Verdana; 
}
.play-time {
    margin: 0 0 0 20px;
}

.pip {
    position: absolute;	
	right: 40px;
}
.full {
    position: absolute;	
	right: 5px;
} 

Интерфейс кнопочек и класс...на всякий случай:
  
svg {
    width: 30px;
    height: 30px;
    fill: #fff;
    opacity: 0.5;
    margin: 2px 0 0 0;
    cursor: pointer; 
}
svg:hover {
    opacity: 1;
}
svg:active {
    background: #ee7249; 
    border-radius: 100%; 
    fill: #000;  
}
.hidden {display: none;}
Кнопочки, у нас - без "подложки", что-бы не усложнять. Высота кнопок - даёт минимальную высоту панели управления.

Оживляем плеер

Резервируем память, под компоненты:
var vc = document.querySelector('.media'),
    video = document.querySelector('.media video'),
    cont = document.getElementById('cont'),	
    control = document.getElementById('video-control'),
    choise = document.getElementById('progres'), 
    ptt = document.getElementById('progres-tip'),
    play = document.getElementById('play'),
    pause = document.getElementById('pause'),
    stop = document.getElementById('stop'),
    elapsed = document.getElementById('play-time'),
    volumeEl = document.getElementById('saund'),
    stt = document.getElementById('saund-tip'),	
    duration = document.getElementById('full-time'),
    pip = document.getElementById('pip'),
    full = document.getElementById('full');

Предварительные требования и расчёт времени (в формате 00:00:00):
document.addEventListener('DOMContentLoaded', () => { 
    video.volume = 0.05; 
    video.autoplay = false;
    video.loop = false;
    if (!('pictureInPictureEnabled' in document)) {
        pip.classList.add('hidden');                  // .hidden {display: none;}
    }	
});	
 
function setTime(time){
    var h = parseInt(time / 3600), m = parseInt((time % 3600) / 60), s = parseInt((time % 3600) % 60);
    if (h < 10) {h = '0' + h} if (m < 10) {m = '0' + m} if (s < 10) {s = '0' + s}
    return h + ':' + m + ':' + s;
}

Управление воспроизведением:
play.addEventListener('click', function () {
      if (video.paused || video.ended) {video.play();}  
}, false);
 
stop.addEventListener('click', function () {
    video.pause();
    video.currentTime = 0;
    video.choise = 0; 
    video.volume = 0.05; 
}, false);
 
video.addEventListener('ended', function () {
    video.currentTime = 0;
    video.choise = 0;
    video.volume = 0.05;
}, false);
 
pause.addEventListener('click', function () {
    video.pause();
}, false);

Иницииуем звук и получаем информацию об уровне громкости:
volumeEl.addEventListener('input', function () {
    inPercent = (volumeEl.value * 100) / volumeEl.max;
    volumeEl.style.background = `linear-gradient(to right, #ccc ${inPercent}%, #363636 ${inPercent}%)`;
    video.volume = volumeEl.value;
}, false);
 
volumeEl.addEventListener('mousemove', function (e) {
	var perc = e.offsetX * 100 / volumeEl.offsetWidth; 
    stt.innerHTML = Math.round(perc);
    var rect = video.getBoundingClientRect();
    stt.style.left = `${e.pageX - rect.left}px`;	
}, false);

Инициируем плеер и обновляем прогресс, привязывая, его, ко времени:
video.addEventListener('loadedmetadata', function () {
    var init = Math.round(video.duration);
    choise.setAttribute('max', init);
    duration.innerHTML = setTime(video.duration);
}, false);
 
video.addEventListener('timeupdate', function () { 
    inPersent = (video.currentTime * 100) / video.duration;
    choise.style.background = `linear-gradient(to right, #ccc ${inPersent}%, #363636 ${inPersent}%)`;
    choise.value = Math.floor(video.currentTime); 
    elapsed.innerHTML = setTime(video.currentTime);
}, false);

Выбираем эпизод и получаем информацию о выборе:
choise.addEventListener('input', function (e) {
    var progres = e.target.dataset.seek ? e.target.dataset.seek : e.target.value;
    video.currentTime = progres; 
    choise.value = progres;
}, false);
 
choise.addEventListener('mousemove', function (e) {
    var skipTo = Math.round((e.offsetX / e.target.clientWidth) * parseInt(e.target.getAttribute('max'), 10));
    choise.setAttribute('data-seek', skipTo); 
    ptt.innerHTML = setTime(skipTo);
    var rect = video.getBoundingClientRect();
    ptt.style.left = `${e.pageX - rect.left}px`; 
}, false);
Информация, пока - только в формате времени. Отлов кадра, при выборе, JS не обеспечивает. У Flash, с этим - проблем нет. Ждёмс-с.
Режим "картинка-в-картинке" и "полный экран":
pip.addEventListener('click', function () {   
    if (document.pictureInPictureElement) {
        document.exitPictureInPicture(); 
    } 
    else if (document.pictureInPictureEnabled) {
        video.requestPictureInPicture(); 
    }     
});

full.addEventListener('click', function () {   
    if (document.webkitFullscreenElement) {
        document.webkitExitFullscreen();                      
        full.innerHTML = '<svg><path d="M7.5,10 L7.5,22.5 L20,22.5 M10,7.5 L22.5,7.5 L22.5,20 Z"></path></svg>';   
    }
    else {
        vc.webkitRequestFullscreen();
        full.innerHTML = '<svg><path d="M15,15 L15,5 L25,15 M15,15 L15,25 L5,15 Z"></path></svg>';  
    }     
});

Изменяем размеры экрана, мышкой, с сохранением пропорций:
var cont = document.querySelector('.cont'),   
    isResizing = false,  
    startWidth = vc.offsetWidth, 
    startHeight = vc.offsetHeight;
cont.addEventListener('mousedown', (e) => {
    e.preventDefault(); 
    isResizing = true;
    var startX = e.clientX, 
        startY = e.clientY;	
    document.addEventListener('mousemove', (e) => {
        if (!isResizing) {return;}
        var width = startWidth + (e.clientX - startX),
            height = startHeight + (e.clientY - startY);		
	    // cохраняем пропорции:
        var ratio = startWidth / startHeight;	
		if (width / height > ratio) {
            vc.style.width = `${height * ratio}px`;
            vc.style.height = `${height}px`;
        } 
	    else {
            vc.style.width = `${width}px`;
            vc.style.height = `${width / ratio}px`;
        }  
    });
    document.addEventListener('mouseup', () => {
        isResizing = false; 
    });

Организуем "исчезновение" ненужных компонентов:
vc.addEventListener('mouseenter', function () {
    control.style.opacity = 1; 
    cont.style.opacity = 1;	
}); 

vc.addEventListener('mouseleave', function () {   
    control.style.opacity = 0; 
    cont.style.opacity = 0;	
});

Несколько слов о выборе локального файла. Опция, это, свежая - не все бро её понимают:
buton.addEventListener('click', async () => { 
    if (window.isSecureContext){
        try {
            var [handle] = await window.showOpenFilePicker(),
                file = await handle.getFile(),
                fileURL = URL.createObjectURL(file),
                video = document.getElementById('player');  // или document.querySelector('.video-cont video');
            video.src = fileURL;
        }
        catch {
            alert('Опция showOpenFilePicker - не поддерживается');
        }
    } 
});

Результат


00:00:00
00:00:00  /  00:00:00

Если верить стилям, "растягивать" экран необходимо за правый край. Будет подсветка, ага.

Как пройти в библиотеку?

Можно создавать плееры при помощи специальных библиотек. Интересно? Тогда - сюда.