@teyuto/videojs-vtt-thumbnails
Version:
VTT Thumbnails Plugin for Video.js
138 lines (111 loc) • 5.18 kB
JavaScript
(function (videojs) {
var registerPlugin = videojs.registerPlugin || videojs.plugin;
function vttThumbnails(options) {
var player = this;
if (videojs.browser.IS_IOS || videojs.browser.IS_ANDROID) {
return;
}
var thumbnailContainer = document.createElement('div');
thumbnailContainer.className = 'thumbnail-preview';
player.el().appendChild(thumbnailContainer);
function createThumbnails(spriteUrl, vttData) {
if (vttData === undefined) {
console.error('vttData is undefined');
return;
}
if (typeof vttData === 'string') {
processVttData(spriteUrl, vttData);
} else if (typeof vttData === 'object' && vttData.url) {
fetch(vttData.url)
.then(response => response.text())
.then(data => processVttData(spriteUrl, data))
.catch(error => console.error('Error fetching VTT data:', error));
} else {
console.error('Invalid vttData format');
}
}
function processVttData(spriteUrl, vttData) {
console.log(vttData);
const lines = vttData.split('\n');
let index = 0;
while (index < lines.length) {
const line = lines[index].trim();
if (line !== '') {
const matchTime = line.match(/(\d+:\d+:\d+[\.,]\d+) --> (\d+:\d+:\d+[\.,]\d+)/);
if (matchTime) {
const [, startTime, endTime] = matchTime;
const xywhLine = lines[index + 1];
const matchXYWH = xywhLine.match(/#xywh=(\d+),(\d+),(\d+),(\d+)/);
if (matchXYWH) {
const [, x, y, width, height] = matchXYWH;
createThumbnail(spriteUrl, parseVttTime(startTime), x, y, width, height);
}
}
}
index += 1;
}
}
function createThumbnail(spriteUrl, startTime, x, y, width, height) {
const thumbnail = document.createElement('div');
thumbnail.className = 'thumbnail';
thumbnail.dataset.startTime = startTime;
thumbnail.style.backgroundImage = `url(${spriteUrl})`;
thumbnail.style.backgroundPosition = `-${x}px -${y}px`;
thumbnail.style.width = `${width}px`;
thumbnail.style.height = `${height}px`;
thumbnailContainer.appendChild(thumbnail);
}
function parseVttTime(timeString) {
const match = timeString.match(/(\d+:\d+:\d+[\.,]\d+)/);
if (match) {
const [fullMatch] = match;
const timeArray = fullMatch.split(':').map(parseFloat);
if (Array.isArray(timeArray) && timeArray.length === 3) {
const [hours, minutes, seconds] = timeArray;
return hours * 3600 + minutes * 60 + seconds;
} else {
console.error('Error format VTT:', timeString);
return 0;
}
} else {
console.error('Error format VTT:', timeString);
return 0;
}
}
createThumbnails(options.spriteUrl, options.vttData);
player.controlBar.progressControl.on('mousemove', function (e) {
const progressBar = player.controlBar.progressControl.el();
const barRect = progressBar.getBoundingClientRect();
const percentage = (e.clientX - barRect.left) / barRect.width;
const time = percentage * player.duration();
document.querySelectorAll('.thumbnail').forEach(thumbnail => {
thumbnail.style.display = 'none';
});
const closestThumbnail = findClosestThumbnail(time);
if (closestThumbnail) {
closestThumbnail.style.display = 'block';
}
const playerRect = player.el().getBoundingClientRect();
thumbnailContainer.style.left = (e.pageX - playerRect.left) + 'px';
thumbnailContainer.style.display = 'block';
});
player.controlBar.progressControl.on('mouseleave', function () {
thumbnailContainer.style.display = 'none';
});
function findClosestThumbnail(time) {
const thumbnails = document.querySelectorAll('.thumbnail');
let closestThumbnail = null;
let minDifference = Infinity;
thumbnails.forEach(thumbnail => {
const thumbnailTime = parseFloat(thumbnail.dataset.startTime);
const difference = Math.abs(thumbnailTime - time);
if (difference < minDifference) {
minDifference = difference;
closestThumbnail = thumbnail;
}
});
return closestThumbnail;
}
}
registerPlugin('vttThumbnails', vttThumbnails);
})(window.videojs);