UNPKG

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