UNPKG

3.36 kBJavaScriptView Raw
1import videojs from 'video.js';
2
3const defaultOptions = {
4 errorInterval: 30,
5 getSource(next) {
6 let tech = this.tech({ IWillNotUseThisInPlugins: true });
7 let sourceObj = tech.currentSource_;
8
9 return next(sourceObj);
10 }
11};
12
13/**
14 * Main entry point for the plugin
15 *
16 * @param {Player} player a reference to a videojs Player instance
17 * @param {Object} [options] an object with plugin options
18 * @private
19 */
20const initPlugin = function(player, options) {
21 let lastCalled = 0;
22 let seekTo = 0;
23 let localOptions = videojs.mergeOptions(defaultOptions, options);
24
25 player.ready(() => {
26 player.trigger({type: 'usage', name: 'hls-error-reload-initialized'});
27 });
28
29 /**
30 * Player modifications to perform that must wait until `loadedmetadata`
31 * has been triggered
32 *
33 * @private
34 */
35 const loadedMetadataHandler = function() {
36 if (seekTo) {
37 player.currentTime(seekTo);
38 }
39 };
40
41 /**
42 * Set the source on the player element, play, and seek if necessary
43 *
44 * @param {Object} sourceObj An object specifying the source url and mime-type to play
45 * @private
46 */
47 const setSource = function(sourceObj) {
48 if (sourceObj === null || sourceObj === undefined) {
49 return;
50 }
51 seekTo = (player.duration() !== Infinity && player.currentTime()) || 0;
52
53 player.one('loadedmetadata', loadedMetadataHandler);
54
55 player.src(sourceObj);
56 player.trigger({type: 'usage', name: 'hls-error-reload'});
57 player.play();
58 };
59
60 /**
61 * Attempt to get a source from either the built-in getSource function
62 * or a custom function provided via the options
63 *
64 * @private
65 */
66 const errorHandler = function() {
67 // Do not attempt to reload the source if a source-reload occurred before
68 // 'errorInterval' time has elapsed since the last source-reload
69 if (Date.now() - lastCalled < localOptions.errorInterval * 1000) {
70 player.trigger({type: 'usage', name: 'hls-error-reload-canceled'});
71 return;
72 }
73
74 if (!localOptions.getSource ||
75 typeof localOptions.getSource !== 'function') {
76 videojs.log.error(
77 'ERROR: reloadSourceOnError - The option getSource must be a function!');
78 return;
79 }
80 lastCalled = Date.now();
81
82 return localOptions.getSource.call(player, setSource);
83 };
84
85 /**
86 * Unbind any event handlers that were bound by the plugin
87 *
88 * @private
89 */
90 const cleanupEvents = function() {
91 player.off('loadedmetadata', loadedMetadataHandler);
92 player.off('error', errorHandler);
93 player.off('dispose', cleanupEvents);
94 };
95
96 /**
97 * Cleanup before re-initializing the plugin
98 *
99 * @param {Object} [newOptions] an object with plugin options
100 * @private
101 */
102 const reinitPlugin = function(newOptions) {
103 cleanupEvents();
104 initPlugin(player, newOptions);
105 };
106
107 player.on('error', errorHandler);
108 player.on('dispose', cleanupEvents);
109
110 // Overwrite the plugin function so that we can correctly cleanup before
111 // initializing the plugin
112 player.reloadSourceOnError = reinitPlugin;
113};
114
115/**
116 * Reload the source when an error is detected as long as there
117 * wasn't an error previously within the last 30 seconds
118 *
119 * @param {Object} [options] an object with plugin options
120 */
121const reloadSourceOnError = function(options) {
122 initPlugin(this, options);
123};
124
125export default reloadSourceOnError;