Easy Video Player - Version 1.1.5

Version Description

  • Updated the player to version 7.0.2.
Download this release

Release Info

Developer naa986
Plugin Icon 128x128 Easy Video Player
Version 1.1.5
Comparing to
See all releases

Code changes from version 1.1.4 to 1.1.5

Files changed (43) hide show
  1. easy-video-player.php +27 -19
  2. lib/embed.min.js +0 -1
  3. lib/flowplayer.js +9391 -2049
  4. lib/flowplayer.min.js +6 -3
  5. lib/flowplayer.swf +0 -0
  6. lib/flowplayerhls.swf +0 -0
  7. lib/skin/all-skins.css +0 -700
  8. lib/skin/functional.css +0 -232
  9. lib/skin/icons/flowplayer.eot +0 -0
  10. lib/skin/icons/flowplayer.svg +98 -0
  11. lib/skin/icons/flowplayer.ttf +0 -0
  12. lib/skin/icons/flowplayer.woff +0 -0
  13. lib/skin/icons/flowplayer.woff2 +0 -0
  14. lib/skin/img/black.png +0 -0
  15. lib/skin/img/black@x2.png +0 -0
  16. lib/skin/img/black_rtl.png +0 -0
  17. lib/skin/img/black_rtl@x2.png +0 -0
  18. lib/skin/img/flowplayer.png +0 -0
  19. lib/skin/img/flowplayer@2x.png +0 -0
  20. lib/skin/img/play_black.png +0 -0
  21. lib/skin/img/play_black@x2.png +0 -0
  22. lib/skin/img/play_black_rtl.png +0 -0
  23. lib/skin/img/play_black_rtl@x2.png +0 -0
  24. lib/skin/img/play_white.png +0 -0
  25. lib/skin/img/play_white@x2.png +0 -0
  26. lib/skin/img/play_white_rtl.png +0 -0
  27. lib/skin/img/play_white_rtl@x2.png +0 -0
  28. lib/skin/img/playful_black.png +0 -0
  29. lib/skin/img/playful_black@x2.png +0 -0
  30. lib/skin/img/playful_black_rtl.png +0 -0
  31. lib/skin/img/playful_black_rtl@x2.png +0 -0
  32. lib/skin/img/playful_white.png +0 -0
  33. lib/skin/img/playful_white@x2.png +0 -0
  34. lib/skin/img/playful_white_rtl.png +0 -0
  35. lib/skin/img/playful_white_rtl@x2.png +0 -0
  36. lib/skin/img/white.png +0 -0
  37. lib/skin/img/white@x2.png +0 -0
  38. lib/skin/img/white_rtl.png +0 -0
  39. lib/skin/img/white_rtl@x2.png +0 -0
  40. lib/skin/minimalist.css +0 -232
  41. lib/skin/playful.css +0 -236
  42. lib/skin/skin.css +1010 -0
  43. readme.txt +8 -3
easy-video-player.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  Plugin Name: Easy Video Player
4
- Version: 1.1.4
5
  Plugin URI: http://noorsplugin.com/wordpress-video-plugin/
6
  Author: naa986
7
  Author URI: http://noorsplugin.com/
@@ -17,7 +17,7 @@ if (!class_exists('EASY_VIDEO_PLAYER')) {
17
 
18
  class EASY_VIDEO_PLAYER {
19
 
20
- var $plugin_version = '1.1.4';
21
 
22
  function __construct() {
23
  define('EASY_VIDEO_PLAYER_VERSION', $this->plugin_version);
@@ -26,7 +26,7 @@ if (!class_exists('EASY_VIDEO_PLAYER')) {
26
 
27
  function plugin_includes() {
28
  if (is_admin()) {
29
- add_filter('plugin_action_links', array(&$this, 'easy_video_player_plugin_action_links'), 10, 2);
30
  }
31
  add_action('plugins_loaded', array($this, 'plugins_loaded_handler'));
32
  add_action('wp_enqueue_scripts', 'easy_video_player_enqueue_scripts');
@@ -109,7 +109,7 @@ function easy_video_player_enqueue_scripts() {
109
  }
110
  wp_register_script('flowplayer-js', $plugin_url . '/lib/flowplayer.min.js');
111
  wp_enqueue_script('flowplayer-js');
112
- wp_register_style('flowplayer-css', $plugin_url . '/lib/skin/all-skins.css');
113
  wp_enqueue_style('flowplayer-css');
114
  }
115
  }
@@ -128,19 +128,19 @@ function easy_video_player_header() {
128
 
129
  function evp_embed_video_handler($atts) {
130
  extract(shortcode_atts(array(
131
- 'url' => '',
132
- 'width' => '',
133
- 'height' => '',
134
- 'ratio' => '0.417',
135
- 'autoplay' => 'false',
136
- 'poster' => '',
137
- 'loop' => '',
138
- 'muted' => '',
139
- 'preload' => 'metadata',
140
- 'video_id' => '',
141
- 'class' => '',
142
- 'template' => '',
143
- ), $atts));
144
  //check if mediaelement template is specified
145
  if($template=='mediaelement'){
146
  $attr = array();
@@ -189,6 +189,7 @@ function evp_embed_video_handler($atts) {
189
  else{
190
  $muted = "";
191
  }
 
192
  $player = "fp" . uniqid();
193
  $color = '';
194
  if (!empty($poster)) {
@@ -200,10 +201,11 @@ function evp_embed_video_handler($atts) {
200
  if (!empty($width)) {
201
  $size_attr = "max-width: {$width}px;max-height: auto;";
202
  }
 
203
  $class_array = array('flowplayer', 'minimalist');
204
  if(!empty($class)){
205
  $shortcode_class_array = array_map('trim', explode(' ', $class));
206
- $shortcode_class_array = array_filter( $shortcode_class_array, 'strlen' );
207
  $shortcode_class_array = array_values($shortcode_class_array);
208
  if(in_array("functional", $shortcode_class_array) || in_array("playful", $shortcode_class_array)){
209
  $class_array = array_diff($class_array, array('minimalist'));
@@ -214,6 +216,12 @@ function evp_embed_video_handler($atts) {
214
  }
215
 
216
  $classes = implode(" ", $class_array);
 
 
 
 
 
 
217
  $styles = <<<EOT
218
  <style>
219
  #$player {
@@ -224,7 +232,7 @@ function evp_embed_video_handler($atts) {
224
  EOT;
225
 
226
  $output = <<<EOT
227
- <div id="$player" data-ratio="$ratio" class="{$classes}">
228
  <video{$video_id}{$autoplay}{$loop}{$muted}>
229
  <source type="video/mp4" src="$url"/>
230
  </video>
1
  <?php
2
  /*
3
  Plugin Name: Easy Video Player
4
+ Version: 1.1.5
5
  Plugin URI: http://noorsplugin.com/wordpress-video-plugin/
6
  Author: naa986
7
  Author URI: http://noorsplugin.com/
17
 
18
  class EASY_VIDEO_PLAYER {
19
 
20
+ var $plugin_version = '1.1.5';
21
 
22
  function __construct() {
23
  define('EASY_VIDEO_PLAYER_VERSION', $this->plugin_version);
26
 
27
  function plugin_includes() {
28
  if (is_admin()) {
29
+ add_filter('plugin_action_links', array($this, 'easy_video_player_plugin_action_links'), 10, 2);
30
  }
31
  add_action('plugins_loaded', array($this, 'plugins_loaded_handler'));
32
  add_action('wp_enqueue_scripts', 'easy_video_player_enqueue_scripts');
109
  }
110
  wp_register_script('flowplayer-js', $plugin_url . '/lib/flowplayer.min.js');
111
  wp_enqueue_script('flowplayer-js');
112
+ wp_register_style('flowplayer-css', $plugin_url . '/lib/skin/skin.css');
113
  wp_enqueue_style('flowplayer-css');
114
  }
115
  }
128
 
129
  function evp_embed_video_handler($atts) {
130
  extract(shortcode_atts(array(
131
+ 'url' => '',
132
+ 'width' => '',
133
+ 'height' => '',
134
+ 'ratio' => '0.417',
135
+ 'autoplay' => 'false',
136
+ 'poster' => '',
137
+ 'loop' => '',
138
+ 'muted' => '',
139
+ 'preload' => 'metadata',
140
+ 'video_id' => '',
141
+ 'class' => '',
142
+ 'template' => '',
143
+ ), $atts));
144
  //check if mediaelement template is specified
145
  if($template=='mediaelement'){
146
  $attr = array();
189
  else{
190
  $muted = "";
191
  }
192
+
193
  $player = "fp" . uniqid();
194
  $color = '';
195
  if (!empty($poster)) {
201
  if (!empty($width)) {
202
  $size_attr = "max-width: {$width}px;max-height: auto;";
203
  }
204
+ /*
205
  $class_array = array('flowplayer', 'minimalist');
206
  if(!empty($class)){
207
  $shortcode_class_array = array_map('trim', explode(' ', $class));
208
+ $shortcode_class_array = array_filter( $shortcode_class_array, 'strlen' ); //remove NULL, FALSE and Empty Strings (""), but leave values of 0 (zero)
209
  $shortcode_class_array = array_values($shortcode_class_array);
210
  if(in_array("functional", $shortcode_class_array) || in_array("playful", $shortcode_class_array)){
211
  $class_array = array_diff($class_array, array('minimalist'));
216
  }
217
 
218
  $classes = implode(" ", $class_array);
219
+ */
220
+
221
+ if(!empty($class)){
222
+ $class = " ".$class;
223
+ }
224
+
225
  $styles = <<<EOT
226
  <style>
227
  #$player {
232
  EOT;
233
 
234
  $output = <<<EOT
235
+ <div id="$player" data-ratio="$ratio" class="flowplayer{$class}">
236
  <video{$video_id}{$autoplay}{$loop}{$muted}>
237
  <source type="video/mp4" src="$url"/>
238
  </video>
lib/embed.min.js DELETED
@@ -1 +0,0 @@
1
- !function(){function e(e,t,n){if(e)return n(e);if(window.fp5ecc[t])return window.fp5ecc[t].push(n);window.fp5ecc[t]=[n];var r=document.createElement("script");r.onload=r.onreadystatechange=function(){var e=r.readyState;if(void 0===e||/complete|loaded/.test(e))for(var n=window.fp5ecc[t],i=0;i<n.length;i++)n[i]()},r.async=!0,r.src=t,a.insertBefore(r,a.firstChild)}function t(e){if(!window.fp5ecssc[e]){window.fp5ecssc[e]=!0;var t=document.createElement("link");t.rel="stylesheet",t.type="text/css",t.href=e,a.insertBefore(t,a.firstChild)}}for(var n,r=document.getElementsByTagName("script"),i=document.createElement("div"),o=0;o<r.length;o++)if(-1!==r[o].innerHTML.indexOf("<video")){n=r[o],n.parentNode.insertBefore(i,n),n.parentNode.removeChild(n);break}var a=document.getElementsByTagName("head")[0],c="//releases.flowplayer.org/5.5.0/commercial",f=n.getAttribute("data-library")||c+"/flowplayer.min.js",d=n.getAttribute("data-swf")||c+"/flowplayer.swf",s=n.getAttribute("data-skin")||c+"/skin/minimalist.css",l="//www.google-analytics.com/ga.js",u="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js";window.fp5ecc=window.fp5ecc||{},window.fp5ecssc=window.fp5ecssc||{};var p="undefined"!=typeof jQuery?jQuery().jquery:"",w=p.split("."),m="undefined"!=typeof $&&jQuery!=$;e(Number(w[0])>=1&&Number(w[1])>=7,u,function(r){var o;!r&&m&&(o=jQuery.noConflict());var a=!r&&""!==p;e("undefined"!=typeof _gat,l,function(){e("undefined"!=typeof flowplayer,f,function(e){e||t(s),o=o||jQuery;var r=o(n),c=r.attr("src"),l=o(r.html().replace(/^[ \t\n\r]+/gm,"").replace(/[ \n\t\r]+$/gm,""));o(i).replaceWith(l),l.find(":not(video, source)").remove(),l.flowplayer({swf:d,e:1}),l.data("flowplayer").conf.embed={library:f,swf:d,script:c},a&&o.noConflict(!0)})})})}();
 
lib/flowplayer.js CHANGED
@@ -1,2685 +1,10027 @@
1
  /*!
2
 
3
- Flowplayer v5.5.2 (Thursday, 27. November 2014 10:32AM) | flowplayer.org/license
4
 
5
  */
6
- !function($) {
7
-
8
- /*
9
- jQuery.browser for 1.9+
10
-
11
- We all love feature detection but that's sometimes not enough.
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- @author Tero Piirainen
14
- */
15
- !function($) {
16
-
17
- if (!$.browser) {
18
-
19
- var b = $.browser = {},
20
- ua = navigator.userAgent.toLowerCase(),
21
- match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
22
- /(safari)[ \/]([\w.]+)/.exec(ua) ||
23
- /(webkit)[ \/]([\w.]+)/.exec(ua) ||
24
- /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
25
- /(msie) ([\w.]+)/.exec(ua) ||
26
- ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
27
-
28
- if (match[1]) {
29
- b[match[1]] = true;
30
- b.version = match[2] || "0";
31
- }
32
 
33
- }
 
 
34
 
35
- }(jQuery);
36
- // auto-install (any video tag with parent .flowplayer)
37
- $(function() {
38
- if (typeof $.fn.flowplayer == 'function') {
39
- $("video").parent(".flowplayer").flowplayer();
40
- }
41
- });
42
 
43
- var instances = [],
44
- extensions = [],
45
- UA = window.navigator.userAgent;
 
46
 
 
 
 
 
 
 
 
47
 
48
- /* flowplayer() */
49
- window.flowplayer = function(fn) {
50
- return $.isFunction(fn) ? extensions.push(fn) :
51
- typeof fn == 'number' || fn === undefined ? instances[fn || 0] :
52
- $(fn).data("flowplayer");
 
 
 
 
 
 
53
  };
54
 
55
- $(window).on('beforeunload', function() {
56
- $.each(instances, function(i, api) {
57
- if (api.conf.splash) {
58
- api.unload();
 
 
 
59
  } else {
60
- api.bind("error", function () {
61
- $(".flowplayer.is-error .fp-message").remove();
62
- });
63
  }
64
- });
65
- });
66
-
67
- var supportLocalStorage = false;
68
- try {
69
- if (typeof window.localStorage == "object") {
70
- window.localStorage.flowplayerTestStorage = "test";
71
- supportLocalStorage = true;
72
  }
73
- } catch (ignored) {}
74
 
75
- var isSafari = /Safari/.exec(navigator.userAgent) && !/Chrome/.exec(navigator.userAgent);
76
- m = /(\d+\.\d+) Safari/.exec(navigator.userAgent),
77
- safariVersion = m ? Number(m[1]) : 100;
 
 
 
 
78
 
79
- $.extend(flowplayer, {
 
 
80
 
81
- version: '5.5.2',
 
 
82
 
83
- engine: {},
 
 
 
84
 
85
- conf: {},
 
 
 
86
 
87
- support: {},
 
 
88
 
89
- defaults: {
90
 
91
- debug: false,
 
 
 
 
 
92
 
93
- // true = forced playback
94
- disabled: false,
 
 
 
 
95
 
96
- // first engine to try
97
- engine: 'html5',
98
 
99
- fullscreen: window == window.top,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
- // keyboard shortcuts
102
- keyboard: true,
 
 
 
 
103
 
104
- // default aspect ratio
105
- ratio: 9 / 16,
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
- adaptiveRatio: false,
 
 
 
 
 
108
 
109
- // scale flash object to video's aspect ratio in normal mode?
110
- flashfit: false,
 
 
 
 
111
 
112
- rtmp: 0,
 
 
113
 
114
- splash: false,
 
 
 
 
 
 
 
115
 
116
- live: false,
 
 
117
 
118
- swf: "//releases.flowplayer.org/5.5.2/flowplayer.swf",
 
 
 
 
 
 
 
 
 
119
 
120
- speeds: [0.25, 0.5, 1, 1.5, 2],
 
 
 
 
 
 
121
 
122
- tooltip: true,
 
 
123
 
124
- // initial volume level
125
- volume: !supportLocalStorage ? 1 : localStorage.muted == "true" ? 0 : !isNaN(localStorage.volume) ? localStorage.volume || 1 : 1,
 
 
126
 
127
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#error-codes
128
- errors: [
 
 
 
129
 
130
- // video exceptions
131
- '',
132
- 'Video loading aborted',
133
- 'Network error',
134
- 'Video not properly encoded',
135
- 'Video file not found',
 
 
136
 
137
- // player exceptions
138
- 'Unsupported video',
139
- 'Skin not found',
140
- 'SWF file not found',
141
- 'Subtitles not found',
142
- 'Invalid RTMP URL',
143
- 'Unsupported video format. Try installing Adobe Flash.'
144
- ],
145
- errorUrls: ['','','','','','','','','','',
146
- 'http://get.adobe.com/flashplayer/'
147
- ],
148
- playlist: [],
149
-
150
- hlsFix: isSafari && safariVersion < 8
151
 
152
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
- });
 
 
 
155
 
156
- // keep track of players
157
- var playerCount = 1;
158
-
159
- // jQuery plugin
160
- $.fn.flowplayer = function(opts, callback) {
161
-
162
- if (typeof opts == 'string') opts = { swf: opts }
163
- if ($.isFunction(opts)) { callback = opts; opts = {} }
164
-
165
- return !opts && this.data("flowplayer") || this.each(function() {
166
-
167
- // private variables
168
- var root = $(this).addClass("is-loading"),
169
- conf = $.extend({}, flowplayer.defaults, flowplayer.conf, opts, root.data()),
170
- videoTag = $("video", root).addClass("fp-engine").removeAttr("controls"),
171
- urlResolver = videoTag.length ? new URLResolver(videoTag) : null,
172
- storage = {},
173
- lastSeekPosition,
174
- engine;
175
-
176
- if (conf.playlist.length) { // Create initial video tag if called without
177
- var preload = conf.preload || videoTag.attr('preload'), placeHolder;
178
- if (videoTag.length) videoTag.replaceWith(placeHolder = $('<p />'));
179
- videoTag = $('<video />').addClass('fp-engine');
180
- placeHolder ? placeHolder.replaceWith(videoTag) : root.prepend(videoTag);
181
- if (flowplayer.support.video) videoTag.attr('preload', preload);
182
- if (typeof conf.playlist[0] === 'string') videoTag.attr('src', conf.playlist[0]);
183
- else {
184
- $.each(conf.playlist[0], function(i, plObj) {
185
- for (var type in plObj) {
186
- if (plObj.hasOwnProperty(type)) {
187
- videoTag.append($('<source />').attr({type: 'video/' + type, src: plObj[type]}));
188
- }
189
- }
190
- });
191
- }
192
- urlResolver = new URLResolver(videoTag);
193
 
194
- }
 
 
195
 
196
- //stop old instance
197
- var oldApi = root.data('flowplayer');
198
- if (oldApi) oldApi.unload();
 
 
199
 
200
- root.data('fp-player_id', root.data('fp-player_id') || playerCount++);
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
- try {
203
- storage = supportLocalStorage ? window.localStorage : storage;
204
- } catch(e) {}
205
 
206
- var isRTL = (this.currentStyle && this.currentStyle['direction'] === 'rtl')
207
- || (window.getComputedStyle && window.getComputedStyle(this, null).getPropertyValue('direction') === 'rtl');
 
208
 
209
- if (isRTL) root.addClass('is-rtl');
 
 
210
 
211
- /*** API ***/
212
- var api = oldApi || {
 
213
 
214
- // properties
215
- conf: conf,
216
- currentSpeed: 1,
217
- volumeLevel: typeof conf.volume === "undefined" ? storage.volume * 1 : conf.volume,
218
- video: {},
219
 
220
- // states
221
- disabled: false,
222
- finished: false,
223
- loading: false,
224
- muted: storage.muted == "true" || conf.muted,
225
- paused: false,
226
- playing: false,
227
- ready: false,
228
- splash: false,
229
- rtl: isRTL,
230
 
231
- // methods
232
- load: function(video, callback) {
 
 
233
 
234
- if (api.error || api.loading || api.disabled) return;
235
 
236
- // resolve URL
237
- video = urlResolver.resolve(video);
238
- $.extend(video, engine.pick(video.sources));
 
239
 
240
- if (video.src) {
241
- var e = $.Event("load");
242
- root.trigger(e, [api, video, engine]);
 
243
 
244
- if (!e.isDefaultPrevented()) {
245
- engine.load(video);
 
246
 
247
- // callback
248
- if ($.isFunction(video)) callback = video;
249
- if (callback) root.one("ready", callback);
250
- } else {
251
- api.loading = false;
252
- }
253
- }
254
 
255
- return api;
256
- },
257
 
258
- pause: function(fn) {
259
- if (api.ready && !api.seeking && !api.disabled && !api.loading) {
260
- engine.pause();
261
- api.one("pause", fn);
262
- }
263
- return api;
264
- },
265
 
266
- resume: function() {
267
 
268
- if (api.ready && api.paused && !api.disabled) {
269
- engine.resume();
 
 
 
 
 
 
270
 
271
- // Firefox (+others?) does not fire "resume" after finish
272
- if (api.finished) {
273
- api.trigger("resume", [api]);
274
- api.finished = false;
275
- }
276
- }
277
 
278
- return api;
279
- },
 
 
280
 
281
- toggle: function() {
282
- return api.ready ? api.paused ? api.resume() : api.pause() : api.load();
283
- },
284
 
285
- /*
286
- seek(1.4) -> 1.4s time
287
- seek(true) -> 10% forward
288
- seek(false) -> 10% backward
289
- */
290
- seek: function(time, callback) {
291
- if (api.ready && !api.live) {
292
 
293
- if (typeof time == "boolean") {
294
- var delta = api.video.duration * 0.1;
295
- time = api.video.time + (time ? delta : -delta);
296
- }
297
- time = lastSeekPosition = Math.min(Math.max(time, 0), api.video.duration).toFixed(1);
298
- var ev = $.Event('beforeseek');
299
- root.trigger(ev, [api, time]);
300
- if (!ev.isDefaultPrevented()) {
301
- engine.seek(time);
302
- if ($.isFunction(callback)) root.one("seek", callback);
303
- } else {
304
- api.seeking = false;
305
- root.toggleClass("is-seeking", api.seeking); // remove loading indicator
306
- }
307
  }
308
- return api;
309
- },
 
 
 
 
 
310
 
311
- /*
312
- seekTo(1) -> 10%
313
- seekTo(2) -> 20%
314
- seekTo(3) -> 30%
315
- ...
316
- seekTo() -> last position
317
- */
318
- seekTo: function(position, fn) {
319
- var time = position === undefined ? lastSeekPosition : api.video.duration * 0.1 * position;
320
- return api.seek(time, fn);
321
- },
322
 
323
- mute: function(flag) {
324
- if (flag === undefined) flag = !api.muted;
325
- storage.muted = api.muted = flag;
326
- storage.volume = !isNaN(storage.volume) ? storage.volume : conf.volume; // make sure storage has volume
327
- api.volume(flag ? 0 : storage.volume, true);
328
- api.trigger("mute", flag);
329
- return api;
330
- },
331
 
332
- volume: function(level, skipStore) {
333
- if (api.ready) {
334
- level = Math.min(Math.max(level, 0), 1);
335
- if (!skipStore) storage.volume = level;
336
- engine.volume(level);
337
- }
338
 
339
- return api;
340
- },
 
341
 
342
- speed: function(val, callback) {
 
 
 
 
 
 
 
 
 
 
 
343
 
344
- if (api.ready) {
 
 
345
 
346
- // increase / decrease
347
- if (typeof val == "boolean") {
348
- val = conf.speeds[$.inArray(api.currentSpeed, conf.speeds) + (val ? 1 : -1)] || api.currentSpeed;
349
- }
350
 
351
- engine.speed(val);
352
- if (callback) root.one("speed", callback);
 
 
 
 
 
 
 
 
 
 
 
 
353
  }
 
354
 
355
- return api;
356
- },
357
 
 
 
358
 
359
- stop: function() {
360
- if (api.ready) {
361
- api.pause();
362
- api.seek(0, function() {
363
- root.trigger("stop");
364
- });
 
365
  }
366
- return api;
367
- },
368
 
369
- unload: function() {
370
- if (!root.hasClass("is-embedding")) {
 
 
 
 
 
 
 
 
 
 
 
371
 
372
- if (conf.splash) {
373
- api.trigger("unload");
374
- engine.unload();
375
- } else {
376
- api.stop();
377
- }
378
- }
379
- return api;
380
- },
381
 
382
- disable: function(flag) {
383
- if (flag === undefined) flag = !api.disabled;
384
 
385
- if (flag != api.disabled) {
386
- api.disabled = flag;
387
- api.trigger("disable", flag);
388
  }
389
- return api;
390
- }
391
-
392
- };
393
 
394
- api.conf = $.extend(api.conf, conf);
 
 
 
 
 
 
395
 
 
 
396
 
397
- /* event binding / unbinding */
398
- $.each(['bind', 'one', 'unbind'], function(i, key) {
399
- api[key] = function(type, fn) {
400
- root[key](type, fn);
401
- return api;
402
- };
403
- });
404
 
405
- api.trigger = function(event, arg) {
406
- root.trigger(event, [api, arg]);
407
- return api;
408
- };
409
 
 
410
 
411
- /*** Behaviour ***/
412
- if (!root.data('flowplayer')) { // Only bind once
413
- root.bind("boot", function() {
414
 
415
- // conf
416
- $.each(['autoplay', 'loop', 'preload', 'poster'], function(i, key) {
417
- var val = videoTag.attr(key);
418
- if (val !== undefined) conf[key] = val ? val : true;
 
 
 
419
  });
420
 
421
- // splash
422
- if (conf.splash || root.hasClass("is-splash") || !flowplayer.support.firstframe) {
423
- api.forcedSplash = !conf.splash && !root.hasClass("is-splash");
424
- api.splash = conf.splash = conf.autoplay = true;
425
- root.addClass("is-splash");
426
- if (flowplayer.support.video) videoTag.attr("preload", "none");
427
- }
428
-
429
- if (conf.live || root.hasClass('is-live')) {
430
- api.live = conf.live = true;
431
- root.addClass('is-live');
432
- }
433
 
434
- // extensions
435
- $.each(extensions, function(i) {
436
- this(api, root);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
437
  });
438
 
439
- // 1. use the configured engine
440
- engine = flowplayer.engine[conf.engine];
441
- if (engine) engine = engine(api, root);
442
-
443
- if (engine.pick(urlResolver.initialSources)) {
444
- api.engine = conf.engine;
445
-
446
- // 2. failed -> try another
447
- } else {
448
- $.each(flowplayer.engine, function(name, impl) {
449
- if (name != conf.engine) {
450
- engine = this(api, root);
451
- if (engine.pick(urlResolver.initialSources)) {
452
- api.engine = name;
453
- return false;
454
- }
455
- }
456
- });
457
- }
458
 
459
- // instances
460
- instances.push(api);
 
461
 
462
- // no engine
463
- if (!api.engine) return api.trigger("error", { code: flowplayer.support.flashVideo ? 5 : 10 });
464
 
465
- // start
466
- conf.splash ? api.unload() : api.load();
 
 
467
 
468
- // disabled
469
- if (conf.disabled) api.disable();
470
 
471
- //initial volumelevel
472
- engine.volume(api.volumeLevel);
473
 
474
- // initial callback
475
- root.one("ready", callback);
 
 
476
 
 
477
 
478
- }).bind("load", function(e, api, video) {
 
 
 
 
 
 
 
 
 
479
 
480
- // unload others
481
- if (conf.splash) {
482
- $(".flowplayer").filter(".is-ready, .is-loading").not(root).each(function() {
483
- var api = $(this).data("flowplayer");
484
- if (api.conf.splash) api.unload();
485
- });
486
- }
487
 
488
- // loading
489
- root.addClass("is-loading");
490
- api.loading = true;
491
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
492
 
493
- }).bind("ready", function(e, api, video) {
494
- video.time = 0;
495
- api.video = video;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
 
497
- function notLoading() {
498
- root.removeClass("is-loading");
499
- api.loading = false;
500
- }
501
 
502
- if (conf.splash) root.one("progress", notLoading);
503
- else notLoading();
504
 
505
- // saved state
506
- if (api.muted) api.mute(true);
507
- else api.volume(api.volumeLevel);
508
 
509
- // see https://github.com/flowplayer/flowplayer/issues/479
 
510
 
511
- var hlsFix = api.conf.hlsFix && /mpegurl/i.exec(video.type);
512
- root.toggleClass('hls-fix', !!hlsFix);
513
 
514
- }).bind("unload", function(e) {
515
- if (conf.splash) videoTag.remove();
516
- root.removeClass("is-loading");
517
- api.loading = false;
 
 
 
 
 
 
 
 
518
 
 
519
 
520
- }).bind("ready unload", function(e) {
521
- var is_ready = e.type == "ready";
522
- root.toggleClass("is-splash", !is_ready).toggleClass("is-ready", is_ready);
523
- api.ready = is_ready;
524
- api.splash = !is_ready;
525
 
 
 
 
526
 
527
- }).bind("progress", function(e, api, time) {
528
- api.video.time = time;
529
 
 
 
 
530
 
531
- }).bind("speed", function(e, api, val) {
532
- api.currentSpeed = val;
 
 
 
 
 
 
533
 
534
- }).bind("volume", function(e, api, level) {
535
- api.volumeLevel = Math.round(level * 100) / 100;
536
- if (!api.muted) storage.volume = level;
537
- else if (level) api.mute(false);
538
 
 
 
 
 
539
 
540
- }).bind("beforeseek seek", function(e) {
541
- api.seeking = e.type == "beforeseek";
542
- root.toggleClass("is-seeking", api.seeking);
543
 
544
- }).bind("ready pause resume unload finish stop", function(e, _api, video) {
 
545
 
546
- // PAUSED: pause / finish
547
- api.paused = /pause|finish|unload|stop/.test(e.type);
 
 
 
 
 
548
 
549
- // SHAKY HACK: first-frame / preload=none
550
- if (e.type == "ready") {
551
- api.paused = conf.preload == 'none';
552
- if (video) {
553
- api.paused = !video.duration || !conf.autoplay && (conf.preload != 'none');
554
- }
555
- }
556
 
557
- // the opposite
558
- api.playing = !api.paused;
559
 
560
- // CSS classes
561
- root.toggleClass("is-paused", api.paused).toggleClass("is-playing", api.playing);
562
 
563
- // sanity check
564
- if (!api.load.ed) api.pause();
565
 
566
- }).bind("finish", function(e) {
567
- api.finished = true;
 
 
 
568
 
569
- }).bind("error", function() {
570
- videoTag.remove();
571
- });
572
- }
573
 
574
- // boot
575
- root.trigger("boot", [api, root]).data("flowplayer", api);
576
 
577
- });
 
 
578
 
579
- };
 
 
 
 
 
 
580
 
581
- !function() {
 
582
 
583
- var parseIpadVersion = function(UA) {
584
- var e = /Version\/(\d\.\d)/.exec(UA);
585
- if (e && e.length > 1) {
586
- return parseFloat(e[1], 10);
587
- }
588
- return 0;
589
- };
 
 
 
 
590
 
591
- var s = flowplayer.support,
592
- browser = $.browser,
593
- video = $("<video loop autoplay preload/>")[0],
594
- UA = navigator.userAgent,
595
- IS_IE = browser.msie || /Trident\/7/.test(UA),
596
- IS_IPAD = /iPad|MeeGo/.test(UA) && !/CriOS/.test(UA),
597
- IS_IPAD_CHROME = /iPad/.test(UA) && /CriOS/.test(UA),
598
- IS_IPHONE = /iP(hone|od)/i.test(UA) && !/iPad/.test(UA),
599
- IS_ANDROID = /Android/.test(UA) && !/Firefox/.test(UA),
600
- IS_ANDROID_FIREFOX = /Android/.test(UA) && /Firefox/.test(UA),
601
- IS_SILK = /Silk/.test(UA),
602
- IS_WP = /IEMobile/.test(UA),
603
- WP_VER = IS_WP ? parseFloat(/Windows\ Phone\ (\d+\.\d+)/.exec(UA)[1], 10) : 0,
604
- IE_MOBILE_VER = IS_WP ? parseFloat(/IEMobile\/(\d+\.\d+)/.exec(UA)[1], 10) : 0,
605
- IPAD_VER = IS_IPAD ? parseIpadVersion(UA) : 0,
606
- ANDROID_VER = IS_ANDROID ? parseFloat(/Android\ (\d\.\d)/.exec(UA)[1], 10) : 0;
607
- $.extend(s, {
608
- subtitles: !!video.addTextTrack,
609
- fullscreen: typeof document.webkitCancelFullScreen == 'function' && !/Mac OS X 10_5.+Version\/5\.0\.\d Safari/.test(UA) ||
610
- document.mozFullScreenEnabled ||
611
- typeof document.exitFullscreen == 'function' ||
612
- typeof document.msExitFullscreen == 'function',
613
- inlineBlock: !(IS_IE && browser.version < 8),
614
- touch: ('ontouchstart' in window),
615
- dataload: !IS_IPAD && !IS_IPHONE && !IS_WP,
616
- zeropreload: !IS_IE && !IS_ANDROID, // IE supports only preload=metadata
617
- volume: !IS_IPAD && !IS_ANDROID && !IS_IPHONE && !IS_SILK && !IS_IPAD_CHROME,
618
- cachedVideoTag: !IS_IPAD && !IS_IPHONE && !IS_IPAD_CHROME && !IS_WP,
619
- firstframe: !IS_IPHONE && !IS_IPAD && !IS_ANDROID && !IS_SILK && !IS_IPAD_CHROME && !IS_WP && !IS_ANDROID_FIREFOX,
620
- inlineVideo: !IS_IPHONE && (!IS_WP || (WP_VER >= 8.1 && IE_MOBILE_VER >= 11)) && (!IS_ANDROID || ANDROID_VER >= 3),
621
- hlsDuration: !IS_ANDROID && (!browser.safari || IS_IPAD || IS_IPHONE || IS_IPAD_CHROME),
622
- seekable: !IS_IPAD && !IS_IPAD_CHROME
623
- });
624
 
625
- // flashVideo
626
- try {
627
- var plugin = navigator.plugins["Shockwave Flash"],
628
- ver = IS_IE ? new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable('$version') : plugin.description;
629
- if (!IS_IE && !plugin[0].enabledPlugin) s.flashVideo = false;
630
- else {
 
631
 
632
- ver = ver.split(/\D+/);
633
- if (ver.length && !ver[0]) ver = ver.slice(1);
634
 
635
- s.flashVideo = ver[0] > 9 || ver[0] == 9 && ver[3] >= 115;
636
- }
 
 
637
 
638
- } catch (ignored) {}
639
- try {
640
- s.video = !!video.canPlayType;
641
- s.video && video.canPlayType('video/mp4');
642
- } catch (e) {
643
- s.video = false;
644
- }
645
 
646
- // animation
647
- s.animation = (function() {
648
- var vendors = ['','Webkit','Moz','O','ms','Khtml'], el = $("<p/>")[0];
 
 
649
 
650
- for (var i = 0; i < vendors.length; i++) {
651
- if (el.style[vendors[i] + 'AnimationName'] !== 'undefined') return true;
652
- }
653
- })();
 
 
654
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
 
 
656
 
657
- }();
658
 
 
 
 
 
 
 
 
 
 
 
659
 
660
- /* The most minimal Flash embedding */
 
 
 
 
 
 
661
 
662
- // movie required in opts
663
- function embed(swf, flashvars, wmode) {
664
- wmode = wmode || "transparent";
 
 
 
 
 
 
665
 
666
- var id = "obj" + ("" + Math.random()).slice(2, 15),
667
- tag = '<object class="fp-engine" id="' + id+ '" name="' + id + '" ';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
668
 
669
- tag += $.browser.msie ? 'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">' :
670
- ' data="' + swf + '" type="application/x-shockwave-flash">';
 
671
 
672
- var opts = {
673
- width: "100%",
674
- height: "100%",
675
- allowscriptaccess: "always",
676
- wmode: wmode,
677
- quality: "high",
678
- flashvars: "",
 
679
 
680
- // https://github.com/flowplayer/flowplayer/issues/13#issuecomment-9369919
681
- movie: swf + ($.browser.msie ? "?" + id : ""),
682
- name: id
683
- };
684
 
685
- // flashvars
686
- $.each(flashvars, function(key, value) {
687
- opts.flashvars += key + "=" + value + "&";
688
- });
689
 
690
- // parameters
691
- $.each(opts, function(key, value) {
692
- tag += '<param name="' + key + '" value="'+ value +'"/>';
693
- });
694
 
695
- tag += "</object>";
 
 
 
696
 
697
- return $(tag);
698
- }
 
699
 
 
 
 
700
 
701
- // Flash is buggy allover
702
- if (window.attachEvent) {
703
- window.attachEvent("onbeforeunload", function() {
704
- __flash_savedUnloadHandler = __flash_unloadHandler = function() {};
705
- });
706
- }
707
 
 
 
 
 
 
 
 
708
 
709
- flowplayer.engine.flash = function(player, root) {
 
 
 
 
 
710
 
711
- var conf = player.conf,
712
- video = player.video,
713
- callbackId,
714
- objectTag,
715
- api;
 
 
 
 
 
 
 
 
 
 
 
716
 
717
- var win = $(window);
718
 
719
- var readyCallback = function () {
720
- // write out video url to handle fullscreen toggle and api load
721
- // in WebKit and Safari - see also fsResume
722
- if (VENDOR == "webkit" || IS_SAFARI) {
723
- var flashvars = $("object param[name='flashvars']", root),
724
- flashprops = (flashvars.attr("value") || '').split("&");
725
 
726
- $.each(flashprops, function (i, prop) {
727
- prop = prop.split("=");
728
- if (prop[0] == "url" && prop[1] != player.video.url) {
729
- flashprops[i] = "url=" + player.video.url;
730
- flashvars.attr({value: flashprops.join("&")});
731
- return false;
732
- }
733
- });
734
  }
 
735
 
736
- };
737
- var fullscreenCallback = function(e) {
738
- // handle Flash object aspect ratio
739
- var origH = root.height(),
740
- origW = root.width();
741
-
742
- if (player.conf.flashfit || /full/.test(e.type)) {
743
-
744
- var fs = player.isFullscreen,
745
- truefs = fs && FS_SUPPORT,
746
- ie7 = !flowplayer.support.inlineBlock,
747
- screenW = fs ? (truefs ? screen.width : win.width()) : origW,
748
- screenH = fs ? (truefs ? screen.height : win.height()) : origH,
749
-
750
- // default values for fullscreen-exit without flashfit
751
- hmargin = 0,
752
- vmargin = 0,
753
- objwidth = ie7 ? origW : '',
754
- objheight = ie7 ? origH : '',
755
-
756
- aspectratio, dataratio;
757
-
758
- if (player.conf.flashfit || e.type === "fullscreen") {
759
- aspectratio = player.video.width / player.video.height,
760
- dataratio = player.video.height / player.video.width,
761
- objheight = Math.max(dataratio * screenW),
762
- objwidth = Math.max(aspectratio * screenH);
763
- objheight = objheight > screenH ? objwidth * dataratio : objheight;
764
- objheight = Math.min(Math.round(objheight), screenH);
765
- objwidth = objwidth > screenW ? objheight * aspectratio : objwidth;
766
- objwidth = Math.min(Math.round(objwidth), screenW);
767
- vmargin = Math.max(Math.round((screenH + vmargin - objheight) / 2), 0);
768
- hmargin = Math.max(Math.round((screenW + hmargin - objwidth) / 2), 0);
769
  }
 
770
 
771
- $("object", root).css({
772
- width: objwidth,
773
- height: objheight,
774
- marginTop: vmargin,
775
- marginLeft: hmargin
776
- });
777
- }
778
- };
779
 
 
 
780
 
781
- var engine = {
 
 
 
 
 
 
782
 
783
- pick: function(sources) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
784
 
785
- if (flowplayer.support.flashVideo) {
786
 
787
- // always pick video/flash first
788
- var flash = $.grep(sources, function(source) { return source.type == 'flash'; })[0];
789
- if (flash) return flash;
790
 
791
- for (var i = 0, source; i < sources.length; i++) {
792
- source = sources[i];
793
- if (/mp4|flv/i.test(source.type)) return source;
 
794
  }
795
- }
796
- },
797
 
798
- load: function(video) {
 
 
 
799
 
800
- function escapeURL(url) {
801
- return url.replace(/&amp;/g, '%26').replace(/&/g, '%26').replace(/=/g, '%3D');
802
- }
803
 
804
- var html5Tag = $("video", root),
805
- url = escapeURL(video.src);
806
- is_absolute = /^https?:/.test(url);
807
 
808
- var removeTag = function() {
809
- html5Tag.remove();
810
- };
811
- var hasSupportedSource = function(sources) {
812
- return $.grep(sources, function(src) {
813
- return !!html5Tag[0].canPlayType('video/' + src.type);
814
- }).length > 0;
815
- };
816
- if (flowplayer.support.video &&
817
- html5Tag.prop('autoplay') &&
818
- hasSupportedSource(video.sources)) html5Tag.one('timeupdate', removeTag);
819
- else removeTag();
820
 
821
- // convert to absolute
822
- if (!is_absolute && !conf.rtmp) url = $("<img/>").attr("src", url)[0].src;
823
 
824
- if (api) {
825
- api.__play(url);
826
 
827
- } else {
 
828
 
829
- player.bind('ready', readyCallback)
830
- .bind("ready fullscreen fullscreen-exit", fullscreenCallback);
831
 
832
- callbackId = "fp" + ("" + Math.random()).slice(3, 15);
833
 
834
- var opts = {
835
- hostname: conf.embedded ? conf.hostname : location.hostname,
836
- url: url,
837
- callback: "jQuery."+ callbackId
838
- };
839
- if (root.data("origin")) {
840
- opts.origin = root.data("origin");
841
- }
842
 
843
- if (is_absolute) delete conf.rtmp;
 
 
 
 
 
 
 
844
 
845
- // optional conf
846
- $.each(['key', 'autoplay', 'preload', 'rtmp', 'subscribe', 'live', 'loop', 'debug', 'splash', 'poster', 'rtmpt'], function(i, key) {
847
- if (conf.hasOwnProperty(key)) opts[key] = conf[key];
848
- });
849
- // bufferTime might be 0
850
- if (conf.bufferTime !== undefined) opts.bufferTime = conf.bufferTime;
851
 
852
- // issues #376
853
- if (opts.rtmp) {
854
- opts.rtmp = escapeURL(opts.rtmp);
855
- }
 
856
 
857
- // issues #387
858
- opts.initialVolume = player.volumeLevel;
 
 
 
 
859
 
860
- objectTag = embed(conf.swf, opts, conf.wmode);
 
 
 
 
 
 
 
 
 
 
 
861
 
862
- objectTag.prependTo(root);
863
 
864
- api = objectTag[0];
865
 
866
- // throw error if no loading occurs
867
- setTimeout(function() {
868
- try {
869
- if (!api.PercentLoaded()) {
870
- return root.trigger("error", [player, { code: 7, url: conf.swf }]);
871
  }
872
- } catch (e) {}
873
- }, 5000);
874
 
875
- // detect disabled flash
876
- setTimeout(function() {
877
- if (typeof api.PercentLoaded === 'undefined') {
878
- root.trigger('flashdisabled', [player]);
879
- }
880
- }, 1000);
881
 
882
- api.pollInterval = setInterval(function () {
883
- if (!api) return;
884
- var status = api.__status ? api.__status() : null;
885
- if (!status) return;
886
 
887
- player.trigger("progress", status.time);
 
 
888
 
889
- video.buffer = status.buffer / video.bytes * video.duration;
890
- player.trigger("buffer", video.buffer);
 
 
 
 
 
 
 
891
 
892
- if (!video.buffered && status.time > 0) {
893
- video.buffered = true;
894
- player.trigger("buffered");
895
- }
896
 
897
- }, 250);
898
 
899
- // listen
900
- $[callbackId] = function(type, arg) {
 
 
901
 
902
- if (conf.debug) console.log("--", type, arg);
 
903
 
904
- var event = $.Event(type);
905
 
906
- switch (type) {
907
 
908
- // RTMP sends a lot of finish events in vain
909
- // case "finish": if (conf.rtmp) return;
910
- case "ready": arg = $.extend(video, arg); break;
911
- case "click": event.flash = true; break;
912
- case "keydown": event.which = arg; break;
913
- case "seek": video.time = arg; break;
914
- }
915
 
916
- if (type != 'buffered') {
917
- // add some delay so that player is truly ready after an event
918
- setTimeout(function() { player.trigger(event, arg); }, 1)
919
- }
920
 
921
- };
922
 
923
- }
924
 
925
- },
 
 
 
 
926
 
927
- // not supported yet
928
- speed: $.noop,
 
 
 
929
 
 
 
 
 
 
 
 
930
 
931
- unload: function() {
932
- api && api.__unload && api.__unload();
933
- delete $[callbackId];
934
- $("object", root).remove();
935
- api = 0;
936
- player.unbind('ready', readyCallback).unbind('ready fullscreen fullscreen-exit', fullscreenCallback);
937
- clearInterval(api.pollInterval);
938
- }
939
 
940
- };
 
 
 
 
941
 
942
- $.each("pause,resume,seek,volume".split(","), function(i, name) {
943
 
944
- engine[name] = function(arg) {
945
- try {
946
- if (player.ready) {
 
 
947
 
948
- if (name == 'seek' && player.video.time && !player.paused) {
949
- player.trigger("beforeseek");
950
- }
951
 
952
- if (arg === undefined) {
953
- api["__" + name]();
954
 
955
- } else {
956
- api["__" + name](arg);
957
- }
 
 
 
 
 
958
 
959
- }
960
- } catch (e) {
961
- if (typeof api["__" + name] === 'undefined') { //flash lost it's methods
962
- return root.trigger('flashdisabled', [player]);
963
- }
964
- throw e;
965
- }
966
- };
967
 
968
- });
969
 
970
- return engine;
 
971
 
972
- };
 
 
 
 
973
 
 
974
 
975
- var VIDEO = $('<video/>')[0];
976
 
977
- // HTML5 --> Flowplayer event
978
- var EVENTS = {
979
 
980
- // fired
981
- ended: 'finish',
982
- pause: 'pause',
983
- play: 'resume',
984
- progress: 'buffer',
985
- timeupdate: 'progress',
986
- volumechange: 'volume',
987
- ratechange: 'speed',
988
- //seeking: 'beforeseek',
989
- seeked: 'seek',
990
- // abort: 'resume',
991
 
992
- // not fired
993
- loadeddata: 'ready',
994
- // loadedmetadata: 0,
995
- // canplay: 0,
 
 
 
 
 
 
 
 
 
996
 
997
- // error events
998
- // load: 0,
999
- // emptied: 0,
1000
- // empty: 0,
1001
- error: 'error',
1002
- dataunavailable: 'error'
1003
 
1004
- };
1005
 
1006
- function round(val, per) {
1007
- per = per || 100;
1008
- return Math.round(val * per) / per;
1009
- }
1010
 
1011
- function getType(type) {
1012
- return /mpegurl/i.test(type) ? "application/x-mpegurl" : "video/" + type;
1013
- }
 
 
 
 
1014
 
1015
- function canPlay(type) {
1016
- if (!/^(video|application)/i.test(type))
1017
- type = getType(type);
1018
- return !!VIDEO.canPlayType(type).replace("no", '');
1019
- }
1020
 
1021
- function findFromSourcesByType(sources, type) {
1022
- var arr = $.grep(sources, function(s) {
1023
- return s.type === type;
1024
- });
1025
- return arr.length ? arr[0] : null;
1026
- }
1027
 
1028
- var videoTagCache;
1029
- var createVideoTag = function(video) {
1030
- if (videoTagCache) {
1031
- return videoTagCache.attr({type: getType(video.type), src: video.src});
1032
  }
1033
- return (videoTagCache = $("<video/>", {
1034
- src: video.src,
1035
- type: getType(video.type),
1036
- 'class': 'fp-engine',
1037
- 'autoplay': 'autoplay',
1038
- preload: 'none',
1039
- 'x-webkit-airplay': 'allow'
1040
- }));
1041
- }
1042
 
1043
- flowplayer.engine.html5 = function(player, root) {
1044
 
1045
- var videoTag = $("video", root),
1046
- support = flowplayer.support,
1047
- track = $("track", videoTag),
1048
- conf = player.conf,
1049
- self,
1050
- timer,
1051
- api,
1052
- volumeLevel;
1053
 
1054
- return self = {
 
 
 
 
1055
 
1056
- pick: function(sources) {
1057
- if (support.video) {
1058
- if (conf.videoTypePreference) {
1059
- var mp4source = findFromSourcesByType(sources, conf.videoTypePreference);
1060
- if (mp4source) return mp4source;
1061
- }
1062
- for (var i = 0, source; i < sources.length; i++) {
1063
- if (canPlay(sources[i].type)) return sources[i];
1064
- }
1065
- }
1066
- },
1067
 
1068
- load: function(video) {
1069
 
1070
- if (conf.splash && !api) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1071
 
1072
- videoTag = createVideoTag(video).prependTo(root);
 
 
1073
 
1074
- if (!support.inlineVideo) {
1075
- videoTag.css({
1076
- position: 'absolute',
1077
- top: '-9999em'
1078
- });
1079
- }
1080
 
1081
- //if (track.length) videoTag.append(track.prop("default", true));
 
 
1082
 
1083
- if (conf.loop) videoTag.attr("loop", "loop");
 
 
1084
 
1085
- api = videoTag[0];
1086
- if (typeof volumeLevel !== 'undefined') {
1087
- api.volume = volumeLevel;
1088
- }
 
 
 
 
 
 
 
 
 
 
 
1089
 
1090
- } else {
 
 
 
 
 
 
1091
 
1092
- api = videoTag[0];
1093
- var sources = videoTag.find('source');
1094
- if (!api.src && sources.length) {
1095
- api.src = video.src;
1096
- sources.remove();
1097
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1098
 
1099
- // change of clip
1100
- if (player.video.src && video.src != player.video.src) {
1101
- videoTag.attr("autoplay", "autoplay");
1102
- api.src = video.src;
1103
 
1104
- // preload=none or no initial "loadeddata" event
1105
- } else if (conf.preload == 'none' || !support.dataload) {
 
 
 
1106
 
1107
- if (support.zeropreload) {
1108
- player.trigger("ready", video).trigger("pause").one("ready", function() {
1109
- root.trigger("resume", [player]);
1110
- });
1111
 
1112
- } else {
1113
- player.one("ready", function() {
1114
- root.trigger("pause", [player]);
1115
- });
1116
- }
1117
- }
1118
 
1119
- }
1120
 
1121
- listen(api, $("source", videoTag).add(videoTag), video);
 
 
 
1122
 
1123
- // iPad (+others?) demands load()
1124
- if (conf.preload != 'none' && video.type != "mpegurl" || !support.zeropreload || !support.dataload) api.load();
1125
- if (conf.splash) api.load();
1126
- },
1127
 
1128
- pause: function() {
1129
- api.pause();
1130
- },
 
 
 
 
1131
 
1132
- resume: function() {
1133
- api.play();
1134
- },
 
 
 
 
 
1135
 
1136
- speed: function(val) {
1137
- api.playbackRate = val;
1138
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1139
 
1140
- seek: function(time) {
1141
- try {
1142
- var pausedState = player.paused;
1143
- api.currentTime = time;
1144
- if (pausedState) api.pause();
1145
- } catch (ignored) {}
1146
- },
1147
 
1148
- volume: function(level) {
1149
- volumeLevel = level;
1150
- if (api) {
1151
- api.volume = level;
1152
- }
1153
- },
1154
 
1155
- unload: function() {
1156
- $("video.fp-engine", root).remove();
1157
- if (!support.cachedVideoTag) videoTagCache = null;
1158
- timer = clearInterval(timer);
1159
- api = 0;
1160
- }
1161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1162
  };
1163
 
1164
- function listen(api, sources, video) {
1165
- // listen only once
1166
-
1167
- if (api.listeners && api.listeners.hasOwnProperty(root.data('fp-player_id'))) return;
1168
- (api.listeners || (api.listeners = {}))[root.data('fp-player_id')] = true;
1169
 
1170
- sources.bind("error", function(e) {
1171
- try {
1172
- if (e.originalEvent && $(e.originalEvent.originalTarget).is('img')) return e.preventDefault();
1173
- if (canPlay($(e.target).attr("type"))) {
1174
- player.trigger("error", { code: 4 });
1175
- }
1176
- } catch (er) {
1177
- // Most likely: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
1178
- }
1179
- });
1180
 
1181
- $.each(EVENTS, function(type, flow) {
 
 
 
 
1182
 
1183
- api.addEventListener(type, function(e) {
1184
 
1185
- // safari hack for bad URL (10s before fails)
1186
- if (flow == "progress" && e.srcElement && e.srcElement.readyState === 0) {
1187
- setTimeout(function() {
1188
- if (!player.video.duration && (!player.conf.live || (player.video.type === 'mpegurl' && support.hlsDuration))) {
1189
- flow = "error";
1190
- player.trigger(flow, { code: 4 });
1191
- }
1192
- }, 10000);
1193
- }
1194
 
1195
- if (conf.debug && !/progress/.test(flow)) console.log(type, "->", flow, e);
1196
 
1197
- // no events if player not ready
1198
- if (!player.ready && !/ready|error/.test(flow) || !flow || !$("video", root).length) { return; }
1199
 
1200
- var event = $.Event(flow), arg, vtype;
 
1201
 
1202
- switch (flow) {
 
1203
 
1204
- case "ready":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1205
 
1206
- arg = $.extend(video, {
1207
- duration: api.duration,
1208
- width: api.videoWidth,
1209
- height: api.videoHeight,
1210
- url: api.currentSrc,
1211
- src: api.currentSrc
1212
- });
1213
 
1214
- try {
1215
- arg.seekable = !conf.live && /mpegurl/i.test(video ? (video.type || '') : '') && api.duration || api.seekable && api.seekable.end(null);
1216
 
1217
- } catch (ignored) {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1218
 
1219
- // buffer
1220
- timer = timer || setInterval(function() {
1221
 
1222
- try {
1223
- arg.buffer = api.buffered.end(null);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1224
 
1225
- } catch (ignored) {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1226
 
1227
- if (arg.buffer) {
1228
- if (round(arg.buffer, 1000) < round(arg.duration, 1000) && !arg.buffered) {
1229
- player.trigger("buffer", e);
 
 
 
 
 
 
 
 
1230
 
1231
- } else if (!arg.buffered) {
1232
- arg.buffered = true;
1233
- player.trigger("buffer", e).trigger("buffered", e);
1234
- clearInterval(timer);
1235
- timer = 0;
1236
- }
1237
- }
1238
 
1239
- }, 250);
 
 
 
 
 
 
 
 
 
 
 
1240
 
1241
- if (!conf.live && !arg.duration && !support.hlsDuration && type === "loadeddata") {
1242
- var durationChanged = function() {
1243
- arg.duration = api.duration;
1244
- try {
1245
- arg.seekable = api.seekable && api.seekable.end(null);
1246
 
1247
- } catch (ignored) {}
1248
- player.trigger(event, arg);
1249
- api.removeEventListener('durationchange', durationChanged);
1250
- };
1251
- api.addEventListener('durationchange', durationChanged);
1252
- return;
1253
- }
1254
 
1255
- break;
1256
 
1257
- case "progress": case "seek":
 
 
1258
 
1259
- var dur = player.video.duration
1260
 
1261
- if (api.currentTime > 0 || player.live) {
1262
- arg = Math.max(api.currentTime, 0);
1263
- break;
1264
 
1265
- } else if (flow == 'progress') {
1266
- return;
1267
- }
1268
 
 
1269
 
1270
- case "speed":
1271
- arg = round(api.playbackRate);
1272
- break;
 
1273
 
1274
- case "volume":
1275
- arg = round(api.volume);
1276
- break;
1277
 
1278
- case "error":
1279
- try {
1280
- arg = (e.srcElement || e.originalTarget).error;
1281
- } catch (er) {
1282
- // Most likely https://bugzilla.mozilla.org/show_bug.cgi?id=208427
1283
- return;
1284
  }
1285
- }
 
 
1286
 
1287
- player.trigger(event, arg);
 
 
 
 
 
 
 
1288
 
1289
- }, false);
 
 
1290
 
1291
- });
 
1292
 
1293
- }
1294
 
1295
- };
1296
- var TYPE_RE = /\.(\w{3,4})(\?.*)?$/i;
 
 
1297
 
1298
- function parseSource(el) {
 
 
 
1299
 
1300
- var src = el.attr("src"),
1301
- type = el.attr("type") || "",
1302
- suffix = src.split(TYPE_RE)[1];
1303
-
1304
- type = /mpegurl/i.test(type) ? "mpegurl" : type.replace("video/", "");
1305
-
1306
- return { src: src, suffix: suffix || type, type: type || suffix };
1307
- }
1308
 
1309
- /* Resolves video object from initial configuration and from load() method */
1310
- function URLResolver(videoTag) {
 
 
 
 
 
 
 
1311
 
1312
- var self = this,
1313
- sources = [];
 
 
 
 
 
1314
 
1315
- // initial sources
1316
- $("source", videoTag).each(function() {
1317
- sources.push(parseSource($(this)));
1318
  });
1319
 
1320
- if (!sources.length) sources.push(parseSource(videoTag));
1321
 
1322
- self.initialSources = sources;
 
 
 
 
 
 
 
1323
 
1324
- self.resolve = function(video) {
1325
- if (!video) return { sources: sources };
1326
 
1327
- if ($.isArray(video)) {
 
 
 
1328
 
1329
- video = { sources: $.map(video, function(el) {
1330
- var type, ret = $.extend({}, el);
1331
- $.each(el, function(key, value) { type = key; });
1332
- ret.type = type;
1333
- ret.src = el[type];
1334
- delete ret[type];
1335
- return ret;
1336
- })};
1337
 
1338
- } else if (typeof video == 'string') {
 
 
 
 
1339
 
1340
- video = { src: video, sources: [] };
 
 
 
 
1341
 
1342
- $.each(sources, function(i, source) {
1343
- if (source.type != 'flash') {
1344
- video.sources.push({
1345
- type: source.type,
1346
- src: video.src.replace(TYPE_RE, "." + source.suffix + "$2")
1347
- });
1348
- }
1349
- });
1350
- }
1351
 
1352
- return video;
1353
- };
1354
 
1355
- };
1356
- /* A minimal jQuery Slider plugin with all goodies */
 
 
 
 
1357
 
1358
- // skip IE policies
1359
- // document.ondragstart = function () { return false; };
1360
 
 
 
 
 
 
 
 
 
 
 
 
1361
 
1362
- // execute function every <delay> ms
1363
- $.throttle = function(fn, delay) {
1364
- var locked;
1365
 
1366
- return function () {
1367
- if (!locked) {
1368
- fn.apply(this, arguments);
1369
- locked = 1;
1370
- setTimeout(function () { locked = 0; }, delay);
1371
- }
1372
- };
1373
- };
1374
 
 
1375
 
1376
- $.fn.slider2 = function(rtl) {
 
1377
 
1378
- var IS_IPAD = /iPad/.test(navigator.userAgent) && !/CriOS/.test(navigator.userAgent);
 
 
 
 
1379
 
1380
- return this.each(function() {
 
 
1381
 
1382
- var root = $(this),
1383
- doc = $(document),
1384
- progress = root.children(":last"),
1385
- disabled,
1386
- offset,
1387
- width,
1388
- height,
1389
- vertical,
1390
- size,
1391
- maxValue,
1392
- max,
1393
- skipAnimation = false,
1394
-
1395
- /* private */
1396
- calc = function() {
1397
- offset = root.offset();
1398
- width = root.width();
1399
- height = root.height();
1400
-
1401
- /* exit from fullscreen can mess this up.*/
1402
- // vertical = height > width;
1403
-
1404
- size = vertical ? height : width;
1405
- max = toDelta(maxValue);
1406
- },
1407
 
1408
- fire = function(value) {
1409
- if (!disabled && value != api.value && (!maxValue || value < maxValue)) {
1410
- root.trigger("slide", [ value ]);
1411
- api.value = value;
1412
- }
1413
- },
1414
 
1415
- mousemove = function(e) {
1416
- var pageX = e.pageX;
1417
- if (!pageX && e.originalEvent && e.originalEvent.touches && e.originalEvent.touches.length) {
1418
- pageX = e.originalEvent.touches[0].pageX;
1419
- }
1420
- var delta = vertical ? e.pageY - offset.top : pageX - offset.left;
1421
- delta = Math.max(0, Math.min(max || size, delta));
1422
 
1423
- var value = delta / size;
1424
- if (vertical) value = 1 - value;
1425
- if (rtl) value = 1 - value;
1426
- return move(value, 0, true);
1427
- },
1428
 
1429
- move = function(value, speed) {
1430
- if (speed === undefined) { speed = 0; }
1431
- if (value > 1) value = 1;
1432
 
1433
- var to = (Math.round(value * 1000) / 10) + "%";
 
 
 
1434
 
1435
- if (!maxValue || value <= maxValue) {
1436
- if (!IS_IPAD && !skipAnimation) progress.stop(); // stop() broken on iPad
1437
- if (skipAnimation) {
1438
- progress.css('width', to);
1439
- } else {
1440
- progress.animate(vertical ? { height: to } : { width: to }, speed, "linear");
1441
- }
1442
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1443
 
1444
- return value;
1445
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1446
 
1447
- toDelta = function(value) {
1448
- return Math.max(0, Math.min(size, vertical ? (1 - value) * height : value * width));
1449
- },
 
 
 
 
 
 
 
 
 
 
1450
 
1451
- /* public */
1452
- api = {
1453
 
1454
- max: function(value) {
1455
- maxValue = value;
1456
- },