/**
* @file text-track.js
* /
importar TextTrackCueList desde './text-track-cue-list';
importar * como Fn desde '../utils/fn.js';
importar {TextTrackKind, TextTrackMode} desde './track-enums';
importar registro desde '../utils/log.js';
importar ventana desde 'global/window';
importar pista desde './track.js';
importar { isCrossOrigin } desde '../utils/url.js';
importar XHR desde '@videojs/xhr';
importar combinación desde '../utils/merge-options';
/**
* Toma el contenido de un archivo webvtt y lo analiza en señales
*
* @param {cadena} srcContent
* contenido del archivo webVTT
*
* @param {TextTrack} pista
* TextTrack para agregar pistas. Las señales provienen de srcContent.
*
* @privado
* /
const parseCues = function(srcContent, track) {
const analizador = nueva ventana.WebVTT.Parser(
ventana,
ventana.vttjs,
ventana.WebVTT.StringDecoder()
);
const errores = [];
analizador.oncue = function(señal) {
pista.addCue(cue);
};
analizador.onparsingerror = función (error) {
errores.push(error);
};
analizador.onflush = function() {
pista.disparador({
tipo: 'datos cargados',
objetivo: pista
});
};
analizador.parse(srcContent);
if (errores.longitud > 0) {
si (ventana.consola && window.console.groupCollapsed) {
window.console.groupCollapsed(`Text Track errores de análisis para ${track.src}`);
}
errores.forEach((error) => log.error(error));
si (ventana.consola && ventana.consola.groupEnd) {
ventana.consola.groupEnd();
}
}
analizador.flush();
};
/**
* Cargue un `TextTrack` desde una URL específica.
*
* @param {cadena} src
* Url desde donde cargar la pista.
*
* @param {TextTrack} pista
* Pista para agregar señales. Viene del contenido al final de `url`.
*
* @privado
* /
const loadTrack = function(origen, pista) {
const opciones = {
uri: origen
};
const crossOrigin = isCrossOrigin(src);
si (origen cruzado) {
opts.cors = crossOrigin;
}
const withCredentials = track.tech_.crossOrigin() === 'usar-credenciales';
si (con Credenciales) {
opts.withCredentials = withCredentials;
}
XHR(opts, Fn.bind(this, function(err, respuesta, cuerpo de respuesta) {
si (err) {
return log.error(err, respuesta);
}
pista.cargado_ = verdadero;
// Asegúrese de que vttjs se haya cargado, de lo contrario, espere hasta que termine de cargarse
// NOTA: esto solo se usa para la compilación alt/video.novtt.js
if (tipo de ventana.WebVTT !== 'función') {
si (pista.tech_) {
// para evitar el uso antes de definir el error eslint, definimos loadHandler
// como dejar aquí
track.tech_.any(['vttjsloaded', 'vttjserror'], (evento) => {
if (evento.tipo === 'vttjserror') {
log.error(`vttjs no se pudo cargar, dejó de intentar procesar ${track.src}`);
devolver;
}
return parseCues(cuerpo de respuesta, pista);
});
}
} else {
parseCues(cuerpo de respuesta, pista);
}
}));
};
/**
* Una representación de un solo `TextTrack`.
*
* @ver [Especificación]{@enlace https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack}
* @extiende Pista
* /
clase TextTrack extiende Pista {
/**
* Crear una instancia de esta clase.
*
* @param {Objeto} opciones={}
* Objeto de nombres y valores de opciones
*
* @param {Tecnología} opciones.tecnología
* Una referencia a la tecnología propietaria de este TextTrack.
*
* @param {TextTrack~Tipo} [opciones.tipo='subtítulos']
* Un tipo de pista de texto válido.
*
* @param {TextTrack~Mode} [opciones.modo='deshabilitado']
* Un modo de seguimiento de texto válido.
*
* @param {cadena} [opciones.id='vjs_track_' + Guid.nuevoGUID()]
* Una identificación única para este TextTrack.
*
* @param {cadena} [opciones.etiqueta='']
* La etiqueta del menú para esta pista.
*
* @param {cadena} [opciones.idioma='']
* Un código de idioma válido de dos caracteres.
*
* @param {cadena} [opciones.srclang='']
* Un código de idioma válido de dos caracteres. Una alternativa, pero despriorizada
* versión de `options.language`
*
* @param {cadena} [opciones.src]
* Una url a las señales de TextTrack.
*
* @param {booleano} [opciones.predeterminado]
* Si esta pista debería estar activada o desactivada de forma predeterminada.
* /
constructor(opciones = {}) {
if (!opciones.tecnología) {
throw new Error('No se proporcionó una tecnología.');
}
configuración constante = fusionar (opciones, {
amable: TextTrackKind[opciones.tipo] || 'subtitulos',
idioma: opciones.idioma || opciones.srclang || ''
});
let mode = TextTrackMode[settings.mode] || 'desactivado';
const predeterminado_ = configuración.predeterminado;
if (configuraciones.tipo === 'metadatos' || configuraciones.tipo === 'capítulos') {
modo = 'oculto';
}
super(configuraciones);
this.tech_ = configuración.tech;
esto.cues_ = [];
this.activeCues_ = [];
this.preload_ = this.tech_.preloadTextTracks !== falso;
const cues = nueva TextTrackCueList(this.cues_);
const activeCues = new TextTrackCueList(this.activeCues_);
dejar cambiado = falso;
this.timeupdateHandler = Fn.bind(this, function(event = {}) {
si (this.tech_.isDisposed()) {
devolver;
}
si (!esta.tecnología_.estáListo_) {
if (evento.tipo !== 'actualización de tiempo') {
this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);
}
devolver;
}
// Accediendo a this.activeCues para los efectos secundarios de actualizarse a sí mismo
// debido a su naturaleza como función getter. No elimine o las señales se
// deja de actualizar!
// Usar el setter para evitar la eliminación de uglify (regla pure_getters)
this.activeCues = this.activeCues;
si (cambiado) {
this.trigger('cambio de señal');
cambiado = falso;
}
if (evento.tipo !== 'actualización de tiempo') {
this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);
}
});
const disposeHandler = () => {
this.stopTracking();
};
this.tech_.one('dispose', disposeHandler);
if (modo !== 'deshabilitado') {
this.startTracking();
}
Objeto.defineProperties(esto, {
/**
* @miembro de TextTrack
* @member {booleano} por defecto
* Si esta pista se configuró como activada o desactivada de forma predeterminada. No se puede cambiar después
* creación.
* @instancia
*
* @solo lectura
* /
por defecto: {
conseguir() {
volver por defecto_;
},
colocar() {}
},
/**
* @miembro de TextTrack
* modo @member {cadena}
* Configure el modo de este TextTrack en un {@link TextTrack~Mode} válido. Voluntad
* no se establecerá si se establece en un modo no válido.
* @instancia
*
* @fires TextTrack#cambio de modo
* /
modo: {
conseguir() {
modo de retorno;
},
establecer (nuevo modo) {
if (!TextTrackMode[nuevoModo]) {
devolver;
}
if (modo === nuevoModo) {
devolver;
}
modo = nuevoModo;
si (!esta.precarga_ && modo !== 'deshabilitado' && this.cues.length === 0) {
// Carga bajo demanda.
loadTrack(este.src, este);
}
this.stopTracking();
if (modo !== 'deshabilitado') {
this.startTracking();
}
/**
* Un evento que se activa cuando cambia el modo en esta pista. Esto permite
* la TextTrackList que contiene esta pista para actuar en consecuencia.
*
* > Nota: ¡Esto no forma parte de la especificación!
*
* @event TextTrack#cambio de modo
* @type {Objetivo del evento~Evento}
* /
this.trigger('cambio de modo');
}
},
/**
* @miembro de TextTrack
* @member {TextTrackCueList} señales
* La lista de pistas de la pista de texto para este TextTrack.
* @instancia
* /
señales: {
conseguir() {
if (!this.loaded_) {
devolver nulo;
}
señales de retorno;
},
colocar() {}
},
/**
* @miembro de TextTrack
* @member {TextTrackCueList} activeCues
* La lista de pistas de texto que están actualmente activas para este TextTrack.
* @instancia
* /
señales activas: {
conseguir() {
if (!this.loaded_) {
devolver nulo;
}
// Nada que hacer
if (this.cues.length === 0) {
devuelve las señales activas;
}
const ct = this.tech_.currentTime();
const activo = [];
for (sea i = 0, l = this.cues.length; i < yo; i++) {
const señal = this.cues[i];
si (cue.startTime < = ct && cue.endTime > = ct) {
activo.push(cue);
} else if (cue.startTime === cue.endTime &&
cue.startTime < = ct &&
cue.startTime + 0.5 > = ct) {
activo.push(cue);
}
}
cambiado = falso;
if (activo.longitud !== this.activeCues_.longitud) {
cambiado = verdadero;
} else {
para (sea i = 0; i < longitud.activa; i++) {
if (this.activeCues_.indexOf(active[i]) === -1) {
cambiado = verdadero;
}
}
}
this.activeCues_ = activo;
activeCues.setCues_(this.activeCues_);
devuelve las señales activas;
},
// /!\ Mantenga este setter vacío (consulte el controlador de actualización de tiempo anterior)
colocar() {}
}
});
si (configuraciones.src) {
this.src = configuración.src;
si (!esta.precarga_) {
// Las pistas se cargarán a pedido.
// Actuar como si estuviéramos cargados para otros propósitos.
esto.cargado_ = verdadero;
}
if (this.preload_ || (settings.kind !== 'subtítulos' && settings.kind !== 'subtítulos')) {
loadTrack(este.src, este);
}
} else {
esto.cargado_ = verdadero;
}
}
iniciarseguimiento() {
// Señales más precisas basadas en requestVideoFrameCallback con un respaldo de requestAnimationFram
this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);
// También escuche la actualización de tiempo en caso de que rVFC/rAF se detenga (ventana en segundo plano, audio en video el)
this.tech_.on('timeupdate', this.timeupdateHandler);
}
detener el seguimiento () {
si (esto.rvf_) {
this.tech_.cancelVideoFrameCallback(this.rvf_);
esto.rvf_ = indefinido;
}
this.tech_.off('timeupdate', this.timeupdateHandler);
}
/**
* Agregar una señal a la lista interna de señales.
*
* @param {TextTrack~Cue} entrada
* La señal para agregar a nuestra lista interna
* /
addCue(originalCue) {
let cue = originalCue;
si (ventana.vttjs && !(instancia Cue original de window.vttjs.VTTCue)) {
cue = nueva ventana.vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text);
for (const prop en originalCue) {
if (!(prop en señal)) {
señal[prop] = originalCue[prop];
}
}
// asegúrese de que `id` se copia
cue.id = originalCue.id;
cue.originalCue_ = originalCue;
}
const pistas = this.tech_.textTracks();
para (sea i = 0; i < pistas.longitud; i++) {
if (pistas[i] !== esto) {
pistas[i].removeCue(cue);
}
}
this.cues_.push(cue);
this.cues.setCues_(this.cues_);
}
/**
* Eliminar una señal de nuestra lista interna
*
* @param {TextTrack~Cue} removeCue
* La señal para eliminar de nuestra lista interna
* /
eliminarCue(eliminarCue) {
let i = this.cues_.length;
mientras yo--) {
const señal = this.cues_[i];
if (cue === removeCue || (cue.originalCue_ && cue.originalCue_ === removeCue)) {
this.cues_.splice(i, 1);
this.cues.setCues_(this.cues_);
romper;
}
}
}
}
/**
* cuechange - Una o más señales en la pista se activaron o dejaron de estar activas.
* /
TextTrack.prototype.allowedEvents_ = {
cambio de señal: 'cambio de señal'
};
exportar TextTrack predeterminado;