import { WebVTT } from "./WebVTT.js";
export { WebVTTThumbnail }
/**
* Class that handles webVTT files for thumbnails.
* @extends WebVTT
* @author ckraemme <ckraemme@awi.de>
*/
class WebVTTThumbnail extends WebVTT {
/**
* Build a webVTT object for thumbnails, ready to be filled with thumbnail related data.
* @param {string} webVTTPath - Path to the webVTT file containing thumbnail information.
*/
constructor(webVTTPath) {
super(webVTTPath);
this.manifestData = [];
this.thumbnailLoadingState = [];
}
/**
* Read in the thumbnail manifest file (webVTT) and store its information in a machine readable form. Afterwards preload thumbnails.
* @param {callback} - Function to be executed subsequently.
* @param {Number} num - Number of thumbnails that should be preloaded. If num=-1, load all.
* @param {boolean} sparse - If true, load the thumbnails spread over the whole video, otherwise sequentially from the beginning (for separated thumbnail images only).
* @returns {Promise} Promise that is resolved after thumbnails were loaded successfully.
*/
init(num, sparse) {
return this.readFile().then(() => {
this.reduceManifestViaTimestamps_();
this.extractUrlsInManifest_();
return this.preloadThumbnails_(num, sparse);
});
}
/**
* Remove all lines in the manifest file that do not contain timestamps and data.
* @private
*/
reduceManifestViaTimestamps_() {
this.manifestSource.forEach(line => {
if (line['time_start'] != null && line['time_end'] != null && line['data'] != null)
this.manifestData.push(line);
});
}
/**
* For each thumbnail image, extract the pure thumbnail URL, i.e., removing trailing coordinate information if available, and create the absolute URL path.
* @private
*/
extractUrlsInManifest_() {
var urlWebVTTPath = new URL(this.webVTTPath);
for (let i = 0; i < this.manifestData.length; i++) {
const urlWebVTTImage = this.manifestData[i]['data'].split('#')[0];
var regexAbsoluteUrl = new RegExp('^(?:[a-z+]+:)?//', 'i');
var regexRootUrl = new RegExp('^/(?!/)', 'i');
const isAbsoluteUrl = regexAbsoluteUrl.test(urlWebVTTImage);
const isRootUrl = regexRootUrl.test(urlWebVTTImage);
const isRelativeUrl = !isAbsoluteUrl && !isRootUrl;
var base;
if (isAbsoluteUrl)
base = undefined;
else if (isRootUrl)
base = urlWebVTTPath.protocol + '//' + urlWebVTTPath.hostname;
else if (isRelativeUrl)
base = this.webVTTPath.substring(0, this.webVTTPath.lastIndexOf("/")) + '/';
const urlObject = new URL(urlWebVTTImage, base);
this.manifestData[i]['url'] = urlObject['href'];
}
}
/**
* Preload thumbnail images and write the image data into this.thumbnailLoadingState.
* @param {Number} num - Number of thumbnails that should be preloaded. If num=-1, load all.
* @param {boolean} sparse - If true, load the thumbnails spread over the whole video, otherwise sequentially from the beginning (for separated thumbnail images only).
* @private
*/
preloadThumbnails_(num, sparse) {
if (num == -1)
num = this.manifestData.length;
let delta = 1;
if (sparse == true) {
delta = Math.floor(this.manifestData.length / num);
delta = Math.max(delta, 1); //in case of wrong configuration
}
for (let i = 0; i < this.manifestData.length; i++)
this.manifestData[i]['image'] = undefined;
for (let i = 0; i < this.manifestData.length; i = i + delta) {
this.loadThumbnail_(i);
if (i == (num - 1) * delta)
break;
}
return Promise.all(this.thumbnailLoadingState);
}
/**
* Load the thumbnail image.
* @param {Number} pos - Position of the thumbnail in this.manifestData.
* @private
*/
loadThumbnail_(pos) {
if (this.thumbnailLoadingState[pos] === undefined) {
this.thumbnailLoadingState[pos] = new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => {
this.manifestData[pos]['image'] = image;
resolve(image);
};
image.onerror = reject;
image.src = this.manifestData[pos]['url'];
});
}
}
}