PluginProbe
FV Player 8 / 8.0.21
FV Player 8 v8.0.21
trunk 8.0.18 8.0.19 8.0.20 8.0.21 8.0.25 8.0.27 8.1 8.1.3
fv-player / models / fv-player.php

fv-player.php in FV Player 8 8.0.21, at models/fv-player.php

3,325 lines 121.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /* FV Folopress Base Class - set of useful functions for Wordpress plugins
3 Copyright (C) 2013 Foliovision
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 if( file_exists( dirname(__FILE__) . '/../includes/fp-api.php') ) {
24 require_once( dirname(__FILE__) . '/../includes/fp-api.php' );
25 }
26
27 if( file_exists( dirname(__FILE__) . '/../includes/fp-api-private.php') ) {
28 require_once( dirname(__FILE__) . '/../includes/fp-api-private.php' );
29 }
30
31 class flowplayer extends FV_Wordpress_Flowplayer_Plugin_Private {
32 private $count = 0;
33 /**
34 * Relative URL path
35 */
36 const FV_FP_RELATIVE_PATH = '';
37 /**
38 * Where the config file should be
39 */
40 private $conf_path = '';
41 /**
42 * Configuration variables array
43 */
44 public $conf = array();
45
46 public $load_tabs = false;
47 /**
48 * Store scripts to load in footer
49 */
50 public $scripts = array();
51
52 var $ajax_count = 0;
53
54 var $ret = array('html' => false, 'script' => false);
55
56 var $hash = false;
57
58 var $bCSSInline = false;
59
60 var $bCSSPlaylists = false;
61
62 public $overlay_css_default = ".wpfp_custom_ad { position: absolute; bottom: 10%; z-index: 20; width: 100%; }\n.wpfp_custom_ad_content { background: white; margin: 0 auto; position: relative }";
63
64 public $overlay_css_bottom = ".wpfp_custom_ad { position: absolute; bottom: 0; z-index: 20; width: 100%; }\n.wpfp_custom_ad_content { background: white; margin: 0 auto; position: relative }";
65
66 public $load_dash = false;
67
68 public $load_hlsjs = false;
69
70 public $bCSSLoaded = false;
71
72 public $aDefaultSkins = array(
73 'skin-custom' => array(
74 'hasBorder' => false,
75 'borderColor' => false,
76 'durationColor' => '#eeeeee',
77 'progressColor' => '#bb0000',
78 'backgroundColor' => '#333333',
79 'font-face' =>'Tahoma, Geneva, sans-serif',
80 'design-timeline' => 'fp-full',
81 'design-icons' => ' '
82 ),
83 'skin-slim' => array(
84 'hasBorder' => false,
85 'borderColor' => false,
86 'backgroundColor' => 'transparent',
87 'font-face' => 'Tahoma, Geneva, sans-serif',
88 'durationColor' => false,
89 'design-timeline' => 'fp-slim',
90 'design-icons' => 'fp-edgy'
91 ),
92 'skin-youtuby' => array(
93 'hasBorder' => false,
94 'borderColor' => false,
95 'backgroundColor' => 'rgba(0, 0, 0, 0.5)',
96 'font-face' =>'Tahoma, Geneva, sans-serif',
97 'durationColor' => false,
98 'design-timeline' => 'fp-full',
99 'design-icons' => ' '
100 )
101 );
102
103 public $css_logo_positions = array(
104 'bottom-left' => "margin: auto auto 2% 2%",
105 'bottom-right' => "margin: auto 2% 2% auto",
106 'top-left' => "margin: 2% auto auto 2%",
107 'top-right' => "margin: 2% 2% auto auto",
108 );
109
110 private $help_html = array(
111 'a' => array( 'href' => array(), 'target' => array() ),
112 'code' => array(),
113 'img' => array( 'src' => array(), 'srcset' => array(), 'width' => array() ),
114 'small' => array(),
115 );
116
117
118 public function __construct() {
119 //load conf data into stack
120 $this->_get_conf();
121
122 if( is_admin() ) {
123 // update notices
124 $this->readme_URL = 'https://plugins.trac.wordpress.org/browser/fv-player/trunk/readme.txt?format=txt';
125 if( !has_action( 'in_plugin_update_message-fv-player/fv-player.php' ) ) {
126 add_action( 'in_plugin_update_message-fv-player/fv-player.php', array( &$this, 'plugin_update_message' ) );
127 }
128
129 // pointer boxes
130 parent::__construct();
131 }
132
133 // define needed constants
134 if (!defined('FV_FP_RELATIVE_PATH')) {
135 define('FV_FP_RELATIVE_PATH', flowplayer::get_plugin_url() );
136 }
137
138 //add_filter( 'fv_flowplayer_caption', array( $this, 'get_duration_playlist' ), 10, 3 );
139 add_filter( 'fv_flowplayer_inner_html', array( $this, 'get_duration_video' ), 10, 2 );
140
141 add_filter( 'fv_flowplayer_video_src', array( $this, 'get_amazon_secure') );
142
143 add_action( 'init', array( $this, 'enable_cdn_rewrite_maybe') );
144
145 add_filter( 'fv_flowplayer_splash', array( $this, 'get_amazon_secure_long') );
146 add_filter( 'fv_flowplayer_playlist_splash', array( $this, 'get_amazon_secure_long') );
147 add_filter( 'fv_flowplayer_resource', array( $this, 'get_amazon_secure_long') );
148
149 add_action( 'wp_enqueue_scripts', array( $this, 'css_enqueue' ) );
150 add_action( 'admin_enqueue_scripts', array( $this, 'css_enqueue' ) );
151
152 add_action( 'init', array( $this, 'fv_player_embed_rewrite_endpoint' ) );
153
154 add_filter( 'rewrite_rules_array', array( $this, 'fv_player_embed_rewrite_rules_fix' ), PHP_INT_MAX );
155 add_filter( 'query_vars', array( $this, 'rewrite_vars' ) );
156
157 add_filter( 'fv_player_custom_css', array( $this, 'popup_css' ), 10 );
158 add_filter( 'fv_player_custom_css', array( $this, 'custom_css' ), 11 );
159
160 add_action( 'template_redirect', array( $this, 'template_preview' ), 0 );
161
162 add_action( 'wp_head', array( $this, 'template_embed_buffer' ), PHP_INT_MAX);
163 add_action( 'wp_footer', array( $this, 'template_embed' ), 0 );
164
165 add_action( 'do_rocket_lazyload', array( $this, 'preview_no_lazy_load' ) );
166
167 add_filter( 'fv_flowplayer_video_src', array( $this, 'add_fake_extension' ) );
168 add_filter('fv_player_item', array($this, 'get_video_checker_media') );
169
170 add_filter( 'searchwp_pre_set_post', array( $this, 'searchwp_pre_post_content' ) );
171 add_filter( 'searchwp_set_post', array( $this, 'searchwp_post_content' ) );
172 }
173
174
175 public function _get_checkbox() {
176 $args_num = func_num_args();
177
178 // new method syntax with all options in the first parameter (which will be an array)
179 if ($args_num == 1) {
180 $options = func_get_arg(0);
181
182 // options must be an array
183 if (!is_array($options)) {
184 throw new Exception('Options parameter passed to the _get_checkbox() method needs to be an array!');
185 }
186
187 $first_td_class = ( ! empty( $options['first_td_class'] ) ? $options['first_td_class'] : '' );
188 $key = (!empty($options['key']) ? $options['key'] : '');
189 $name = (!empty($options['name']) ? $options['name'] : '');
190 $help = (!empty($options['help']) ? $options['help'] : '');
191 $more = (!empty($options['more']) ? $options['more'] : '');
192 $disabled = !empty($options['disabled']);
193
194 if (!$key || !$name) {
195 throw new Exception('Both, "name" and "key" options need to be set for _get_checkbox()!');
196 }
197 } else if ($args_num >= 2) {
198 // old method syntax with function parameters defined as ($name, $key, $help = false, $more = false)
199 $first_td_class = 'first';
200 $name = func_get_arg(0);
201 $key = func_get_arg(1);
202 $help = ($args_num >= 3 ? func_get_arg(2) : false);
203 $more = ($args_num >= 4 ? func_get_arg(3) : false);
204
205 $disabled = false;
206
207 } else {
208 throw new Exception('Invalid number of arguments passed to the _get_checkbox() method!');
209 }
210
211 $checked = $this->_get_option( $key );
212 if ( $checked === 'false' ) {
213 $checked = false;
214 }
215
216 if ( is_array( $key ) && count( $key ) > 1 ) {
217 $key = $key[0] . '[' . $key[1] . ']';
218 }
219 ?>
220 <tr>
221 <td<?php echo $first_td_class ? ' class="' . esc_attr( $first_td_class ) . '"' : ''; ?>><label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $name ); ?>:</label></td>
222 <td>
223 <p class="description">
224 <input type="hidden" name="<?php echo esc_attr( $key ); ?>" value="false"/>
225 <input type="checkbox" name="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $key ); ?>" value="true"<?php
226 if ( $checked ) { echo ' checked="checked"'; }
227 if ( $disabled ) { echo ' disabled'; }
228
229 if (isset($options) && isset($options['data']) && is_array($options['data'])) {
230 foreach ($options['data'] as $data_item => $data_value) {
231 echo ' data-' . esc_attr( $data_item ) . '="' . esc_attr( $data_value ) . '"';
232 }
233 }
234 ?> />
235 <?php if ( $help ) {
236 echo wp_kses( $help, $this->help_html );
237 } ?>
238 <?php if ( $more ) { ?>
239 <span class="more"><?php echo wp_kses( $more, $this->help_html ); ?></span> <a href="#" class="show-more">(&hellip;)</a>
240 <?php } ?>
241 </p>
242 </td>
243 </tr>
244 <?php
245
246 // Disabled inputs are not sent in POST so if it's checked we retain the value using hidden input
247 if ( $disabled && $checked ) {
248 ?>
249 <input type="hidden" name="<?php echo esc_attr( $key ); ?>" value="true"/>
250 <?php
251 }
252 }
253
254
255 public function _get_radio($options) {
256 // options must be an array
257 if (!is_array($options)) {
258 throw new Exception('Options parameter passed to the _get_radio() method needs to be an array!');
259 }
260
261 $first_td_class = ( ! empty( $options['first_td_class'] ) ? $options['first_td_class'] : '' );
262 $key = (!empty($options['key']) ? $options['key'] : '');
263 $name = (!empty($options['name']) ? $options['name'] : '');
264 $values = (!empty($options['values']) ? $options['values'] : '');
265 $value_keys = (is_array($values) ? array_keys($values) : array());
266 $help = (!empty($options['help']) ? $options['help'] : '');
267 $more = (!empty($options['more']) ? $options['more'] : '');
268 $default = (!empty($options['default']) ? $options['default'] : reset($value_keys));
269
270 if (!$key || !$values) {
271 throw new Exception('The "name", "key" and "values" options need to be set for _get_radio()!');
272 }
273
274 $saved_value = $this->_get_option( $key );
275 $selected = $default;
276
277 // check if any of the given values match the saved one and store it for a pre-select
278 foreach ($values as $index => $input_value) {
279 if ($saved_value == $index) {
280 $selected = $index;
281 break;
282 }
283 }
284
285 if ( is_array( $key ) && count( $key ) > 1 ) {
286 $key = $key[0] . '[' . $key[1] . ']';
287 }
288
289 // determine style (display all checkboxes below each other or next to each other in multiple columns
290 $style = (!empty($options['style']) ? $options['style'] : 'rows');
291
292 // rows style
293 if ($style == 'rows') {
294 ?>
295 <tr>
296 <td<?php echo $first_td_class ? ' class="' . esc_attr( $first_td_class ) . '"' : ''; ?>><label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $name ); ?>:</label></td>
297 <td>
298 <fieldset>
299 <p>
300 <?php
301 foreach ( $values as $index => $input_value ) {
302 ?>
303
304 &nbsp;<input type="radio" name="<?php echo esc_attr( $key ); ?>"
305 id="<?php echo esc_attr( $key . '-' . $input_value ); ?>" value="<?php echo esc_html( $index ); ?>"<?php
306 if ( ( $selected == $index ) ) {
307 echo ' checked="checked"';
308 }
309
310 if ( isset( $options ) && isset( $options['data'] ) && is_array( $options['data'] ) ) {
311 foreach ( $options['data'] as $data_item => $data_value ) {
312 echo ' data-' . esc_attr( $data_item ) . '="' . esc_attr( $data_value ) . '"';
313 }
314 }
315 ?> /> <label for="<?php echo esc_attr( $key . '-' . $input_value ); ?>"><?php echo esc_html( $input_value ); ?></label><br/>
316
317 <?php
318 }
319 ?>
320
321 </p>
322 </fieldset>
323 <?php if ( $help ) {
324 echo wp_kses( $help, $this->help_html );
325 } ?>
326 <?php if ( $more ) { ?>
327 <span class="more"><?php echo wp_kses( $more, $this->help_html ); ?></span> <a href="#" class="show-more">(&hellip;)</a>
328 <?php } ?>
329 </td>
330 </tr>
331 <?php
332 } else {
333
334 // columns style
335 ?>
336 <tr>
337 <?php
338 foreach ( $values as $index => $input_value ) {
339 ?>
340 <td style="white-space: nowrap">
341 <fieldset>
342 <p>
343 &nbsp;<input type="radio" name="<?php echo esc_attr( $key ); ?>"
344 id="<?php echo esc_attr( $key . '-' . $input_value ); ?>"
345 value="<?php echo esc_attr( $index ); ?>"<?php
346 if ( ( $selected == $index ) ) {
347 echo ' checked="checked"';
348 }
349
350 if ( isset( $options ) && isset( $options['data'] ) && is_array( $options['data'] ) ) {
351 foreach ( $options['data'] as $data_item => $data_value ) {
352 echo ' data-' . esc_attr( $data_item ) . '="' . esc_attr( $data_value ) . '"';
353 }
354 }
355 ?> /> <label for="<?php echo esc_attr( $key . '-' . $input_value ); ?>"><?php echo esc_html( $input_value ); ?></label><br/>
356 </p>
357 </fieldset>
358 <?php if ( $help ) {
359 echo wp_kses( $help, $this->help_html );
360 } ?>
361 <?php if ( $more ) { ?>
362 <span class="more"><?php echo wp_kses( $more, $this->help_html ); ?></span> <a href="#" class="show-more">(&hellip;)</a>
363 <?php } ?>
364 </td>
365 <?php
366 }
367 ?>
368 </tr>
369
370 <?php
371 }
372 }
373
374 public function _get_censored_val($val) {
375 $censored_val = '';
376
377 for ($i = 0; $i < strlen($val); $i++) {
378 // Reveal first and last 2 chars
379 if( $i < 2 || $i >= strlen($val) - 2 ) {
380 $censored_val .= $val[$i];
381 } else {
382 $censored_val .= '*';
383 }
384 }
385
386 return $censored_val;
387 }
388
389 public function _get_input_text($options = array()) {
390 // options must be an array
391 if (!is_array($options)) {
392 throw new Exception('Options parameter passed to the _get_input_text() method needs to be an array!');
393 }
394
395 $first_td_class = ! empty( $options['first_td_class'] ) ? $options['first_td_class'] : '';
396 $class_name = (!empty($options['class']) ? esc_attr($options['class']) : '');
397 $key = (!empty($options['key']) ? $options['key'] : '');
398 $name = (!empty($options['name']) ? $options['name'] : '');
399 $title = ! empty( $options['title'] ) ? $options['title'] : '';
400 $default = (!empty($options['default']) ? $options['default'] : '');
401 $help = (!empty($options['help']) ? $options['help'] : '');
402 $autocomplete = ! empty( $options['autocomplete'] ) ? ' autocomplete="' . esc_attr( $options['autocomplete'] ) . '"' : '';
403
404 // Only use fields with secret values obfuscated if FV Player Pro is not there or is ready for it
405 if(
406 !function_exists('FV_Player_Pro') ||
407 ( function_exists('FV_Player_Pro') && version_compare( str_replace( '.beta','',FV_Player_Pro()->version ),'7.5.25.728', '>=') )
408 ) {
409 $secret = (!empty($options['secret']) ? $options['secret'] : false);
410
411 } else {
412 $secret = false;
413 }
414
415 if (!$key || !$name) {
416 throw new Exception('Both, "name" and "key" options need to be set for _get_input_text()!');
417 }
418
419 $saved_value = esc_attr( $this->_get_option($key) );
420 if ( is_array( $key ) && count( $key ) > 1 ) {
421 if( $secret ) {
422 $secret_key = $key[0] . '[_is_secret_' . $key[1] . ']'; // add _is_secret_ prefix to key
423 }
424 $key = $key[0] . '[' . $key[1] . ']';
425 }
426
427 // use the default value if the setting is empty
428 // however in case of numeric settings you might wish to enter 0 and we need to accept that
429 // so we just check if the default if a number and if it is, we allow even 0 value
430 $val = is_numeric($default) || !empty($saved_value) ? $saved_value : $default;
431
432 // censor original value
433 if( $secret ) {
434 $censored_val = $this->_get_censored_val($val);
435 $val = '';
436 $class_name = 'code ' . $class_name;
437 }
438
439 ?>
440 <tr>
441 <td<?php echo $first_td_class ? ' class="' . esc_attr( $first_td_class ) . '"' : ''; ?>><label for="<?php echo esc_attr( $key ); ?>"><?php echo wp_kses( $name, $this->help_html ); ?><?php if( $help ) echo ' <a href="#" class="show-info"><span class="dashicons dashicons-info"></span></a>'; ?>:</label></td>
442 <td>
443 <input class="<?php echo esc_attr( $class_name ); ?>" <?php if($secret && !empty($censored_val)) echo 'style="display: none;"'; ?> id="<?php echo esc_attr($key); ?>" name="<?php echo esc_attr($key); ?>" <?php if ($title) { echo 'title="' . esc_attr( $title ) . '" '; } ?>type="text" value="<?php echo esc_attr($val); ?>"<?php
444 if (isset($options['data']) && is_array($options['data'])) {
445 foreach ($options['data'] as $data_item => $data_value) {
446 echo ' data-' . esc_attr( $data_item ) . '="' . esc_attr( $data_value ) . '"';
447 }
448 }
449
450 echo $autocomplete;
451 ?> />
452 <?php if ( $help ) { ?>
453 <p class="description fv-player-admin-tooltip"><span class="info"><?php echo wp_kses( $help, $this->help_html ); ?></span></p>
454 <?php } ?>
455
456 <?php if ( $secret ): ?>
457 <input name="<?php echo esc_attr($secret_key); ?>" value="<?php echo ! empty( $censored_val ) ? '1' : '0'; ?>" type="hidden" />
458 <?php if(!empty($censored_val)): ?>
459 <code class="secret-preview"><?php echo esc_html( $censored_val ); ?></code>
460 <a href="#" data-is-empty="0" data-setting-change="<?php echo esc_attr($secret_key); ?>" >Change</a>
461 <?php endif; ?>
462 <?php endif; ?>
463 </td>
464 </tr>
465
466 <?php
467 }
468
469
470 public function _get_input_hidden($options = array()) {
471 // options must be an array
472 if (!is_array($options)) {
473 throw new Exception('Options parameter passed to the _get_input_hidden() method needs to be an array!');
474 }
475
476 $key = (!empty($options['key']) ? $options['key'] : '');
477 $default = (isset($options['default']) ? $options['default'] : '');
478
479 if (!$key) {
480 throw new Exception('The "key" option need to be set for _get_input_hidden()!');
481 }
482
483 $saved_value = esc_attr( $this->_get_option($key) );
484 if ( is_array( $key ) && count( $key ) > 1 ) {
485 $key = $key[0] . '[' . $key[1] . ']';
486 }
487 ?>
488 <input id="<?php echo esc_attr( $key ); ?>" name="<?php echo esc_attr( $key ); ?>" type="hidden" value="<?php echo (!empty($saved_value) ? $saved_value : $default); ?>"<?php
489 if (isset($options['data']) && is_array($options['data'])) {
490 foreach ($options['data'] as $data_item => $data_value) {
491 echo ' data-' . esc_attr( $data_item ) . '="' . esc_attr( $data_value ) . '"';
492 }
493 }
494 ?> />
495
496 <?php
497 }
498
499
500 public function _get_select() {
501 $args_num = func_num_args();
502
503 // new method syntax with all options in the first parameter (which will be an array)
504 if ($args_num == 1) {
505 $options = func_get_arg(0);
506
507 // options must be an array
508 if (!is_array($options)) {
509 throw new Exception('Options parameter passed to the _get_select() method needs to be an array!');
510 }
511
512 $first_td_class = ! empty( $options['first_td_class'] ) ? $options['first_td_class'] : '';
513 $key = (!empty($options['key']) ? $options['key'] : '');
514 $name = (!empty($options['name']) ? $options['name'] : '');
515 $aOptions = (!empty($options['options']) ? $options['options'] : '');
516 $class_name = ! empty( $options['class'] ) ? $options['class'] : '';
517 $help = (!empty($options['help']) ? $options['help'] : '');
518 $more = (!empty($options['more']) ? $options['more'] : '');
519 $default = (isset($options['default']) ? $options['default'] : '');
520
521 if (!$key || !$name || !$aOptions) {
522 throw new Exception('The items "name", "key" and "options" need to be set in options for _get_select()!');
523 }
524 } else if ($args_num >= 5) {
525 // old method syntax with function parameters defined as ($name, $key, $help = false, $more = false)
526 $first_td_class = '';
527 $name = func_get_arg(0);
528 $key = func_get_arg(1);
529 $aOptions = func_get_arg(4);
530 $help = ($args_num >= 3 ? func_get_arg(2) : false);
531 $more = ($args_num >= 4 ? func_get_arg(3) : false);
532 $class_name = '';
533 $default = '';
534 } else {
535 throw new Exception('Invalid number of arguments passed to the _get_checkbox() method!');
536 }
537
538 // check which option should be selected by default
539 $option = $this->_get_option($key);
540 foreach( $aOptions AS $k => $v ) {
541 if ($k == $option) {
542 $selected = $k;
543 }
544 }
545
546 // if no option is selected, make a default one selected
547 if (!isset($selected) && $default) {
548 $selected = $default;
549 }
550
551 if ( is_array( $key ) && count( $key ) > 1 ) {
552 $key = $key[0] . '[' . $key[1] . ']';
553 }
554
555 $key = esc_attr($key);
556 ?>
557 <tr>
558 <td<?php echo $first_td_class ? ' class="' . esc_attr( $first_td_class ) . '"' : ''; ?>><label for="<?php echo esc_attr( $key ); ?>"><?php echo esc_attr( $name ); ?></label></td>
559 <td>
560 <select <?php echo $class_name ? 'class="' . esc_attr( $class_name ) . '"' : ''; ?>id="<?php echo esc_attr( $key ); ?>" name="<?php echo esc_attr( $key ); ?>"<?php
561 if (!isset($options) || !isset($options['data']) || !isset($options['data']['fv-preview'])) { echo ' data-fv-preview=""'; }
562
563 if (isset($options) && isset($options['data']) && is_array($options['data'])) {
564 foreach ($options['data'] as $data_item => $data_value) {
565 echo ' data-' . esc_attr( $data_item ) . '="' . esc_attr( $data_value ) . '"';
566 }
567 }
568 ?>>
569 <?php foreach( $aOptions AS $k => $v ) : ?>
570 <option value="<?php echo esc_attr($k); ?>"<?php if( (isset($selected) && strcmp($selected ,$k) == 0 ) || (strcmp($option,$k) == 0) ) echo ' selected="selected"'; ?>><?php echo esc_html( $v ); ?></option>
571 <?php endforeach; ?>
572 </select>
573
574 <?php if ( $help ) {
575 echo wp_kses( $help, $this->help_html );
576 } ?>
577 <?php if ( $more ) { ?>
578 <span class="more"><?php echo wp_kses( $more, $this->help_html ); ?></span> <a href="#" class="show-more">(&hellip;)</a>
579 <?php } ?>
580 </td>
581 </tr>
582
583 <?php
584 }
585
586
587 public function _get_conf() {
588 $conf = get_option( 'fvwpflowplayer' );
589 if( !is_array($conf) ) {
590 $conf = array();
591 }
592
593 if( empty($conf) ) { // new install
594 // hide some of the notices
595 $conf['nag_fv_player_8'] = true;
596 $conf['notice_user_video_positions_conversion'] = true;
597 $conf['notice_xml_sitemap_iframes'] = true;
598 $conf['video_position_save_enable'] = true;
599 $conf['js-optimize'] = true;
600 }
601
602 if( !isset( $conf['googleanalytics'] ) ) $conf['googleanalytics'] = 'false';
603 if( !isset( $conf['chromecast'] ) ) $conf['chromecast'] = 'false';
604 if( !isset( $conf['key'] ) ) $conf['key'] = 'false';
605 if( !isset( $conf['logo'] ) ) $conf['logo'] = 'false';
606 if( !isset( $conf['logo_over_video'] ) ) $conf['logo_over_video'] = 'true';
607 if( !isset( $conf['rtmp'] ) ) $conf['rtmp'] = 'false';
608
609 if( !isset( $conf['popupbox'] ) ) $conf['popupbox'] = 'false';
610 if( !isset( $conf['allowfullscreen'] ) ) $conf['allowfullscreen'] = 'true';
611 if( !isset( $conf['postthumbnail'] ) ) $conf['postthumbnail'] = 'false';
612
613 if( !isset( $conf['overlayTextColor'] ) ) $conf['overlayTextColor'] = '#888';
614 if( !isset( $conf['overlayLinksColor'] ) ) $conf['overlayLinksColor'] = '#ff3333';
615 if( !isset( $conf['subtitleBgColor'] ) ) $conf['subtitleBgColor'] = 'rgba(0,0,0,0.5)';
616 if( !isset( $conf['subtitleSize'] ) ) $conf['subtitleSize'] = 16;
617
618 //unset( $conf['playlistBgColor'], $conf['playlistFontColor'], $conf['playlistSelectedColor']);
619 if( !isset( $conf['playlistBgColor'] ) ) $conf['playlistBgColor'] = '#808080';
620 if( !isset( $conf['playlistFontColor'] ) ) $conf['playlistFontColor'] = '';
621 if( !isset( $conf['playlistSelectedColor'] ) ) $conf['playlistSelectedColor'] = '#bb0000';
622 if( !isset( $conf['logoPosition'] ) ) $conf['logoPosition'] = 'bottom-left';
623
624 //
625
626 if( !isset( $conf['parse_commas'] ) ) $conf['parse_commas'] = 'false';
627 if( !isset( $conf['width'] ) ) $conf['width'] = '1280';
628 if( !isset( $conf['height'] ) ) $conf['height'] = '720';
629 if( !isset( $conf['engine'] ) ) $conf['engine'] = 'false';
630 if( !isset( $conf['overlay'] ) ) $conf['overlay'] = '';
631 if( !isset( $conf['overlay_width'] ) ) $conf['overlay_width'] = '';
632 if( !isset( $conf['overlay_height'] ) ) $conf['overlay_height'] = '';
633 if( !isset( $conf['overlay_css'] ) ) $conf['overlay_css'] = $this->overlay_css_default;
634 if( !isset( $conf['overlay_show_after'] ) ) $conf['overlay_show_after'] = 0;
635 if( !isset( $conf['disable_videochecker'] ) ) $conf['disable_videochecker'] = 'false';
636 if( isset( $conf['videochecker'] ) && $conf['videochecker'] == 'off' ) { $conf['disable_videochecker'] = 'true'; unset($conf['videochecker']); }
637 if( !isset( $conf['interface'] ) ) $conf['interface'] = array( 'playlist' => false, 'redirect' => false, 'autoplay' => false, 'loop' => false, 'splashend' => false, 'embed' => false, 'subtitles' => false, 'ads' => false, 'mobile' => false, 'align' => false );
638 if( !isset( $conf['interface']['popup'] ) ) $conf['interface']['popup'] = 'true';
639 if( !isset( $conf['amazon_bucket'] ) || !is_array($conf['amazon_bucket']) ) $conf['amazon_bucket'] = array('');
640 if( !isset( $conf['amazon_key'] ) || !is_array($conf['amazon_key']) ) $conf['amazon_key'] = array('');
641 if( !isset( $conf['amazon_secret'] ) || !is_array($conf['amazon_secret']) ) $conf['amazon_secret'] = array('');
642 if( !isset( $conf['amazon_region'] ) || !is_array($conf['amazon_region']) ) $conf['amazon_region'] = array('');
643 if( !isset( $conf['amazon_expire'] ) ) $conf['amazon_expire'] = '5';
644 if( !isset( $conf['amazon_expire_force'] ) ) $conf['amazon_expire_force'] = 'false';
645 if( !isset( $conf['js-everywhere'] ) ) $conf['js-everywhere'] = 'false';
646 if( !isset( $conf['volume'] ) ) $conf['volume'] = '0.7';
647 if( !isset( $conf['playlist_advance'] ) ) $conf['playlist_advance'] = '';
648 if( empty( $conf['sharing_email_text'] ) ) $conf['sharing_email_text'] = __( 'Check out the amazing video here', 'fv-player' );
649
650
651 if( !isset( $conf['liststyle'] ) ) $conf['liststyle'] = 'horizontal';
652 if( !isset( $conf['ui_airplay'] ) ) $conf['ui_airplay'] = true;
653 if( !isset( $conf['ui_speed_increment'] ) ) $conf['ui_speed_increment'] = 0.25;
654 if( !isset( $conf['popups_default'] ) ) $conf['popups_default'] = 'no';
655 if( !isset( $conf['email_lists'] ) ) $conf['email_lists'] = array();
656
657 if( !isset( $conf['sticky_video'] ) ) $conf['sticky_video'] = 'off';
658 if( !isset( $conf['sticky_place'] ) ) $conf['sticky_place'] = 'right-bottom';
659 if( !isset( $conf['sticky_width'] ) ) $conf['sticky_width'] = '380';
660 if( !isset( $conf['sticky_width_mobile'] ) ) $conf['sticky_width_mobile'] = '100';
661
662 if( !isset( $conf['playlist-design'] ) ) $conf['playlist-design'] = '2017';
663
664 if (!isset($conf['skin-slim'])) $conf['skin-slim'] = array();
665 if (!isset($conf['skin-youtuby'])) $conf['skin-youtuby'] = array();
666
667 if ( ! isset( $conf['youtube_browser_chrome'] ) ) $conf['youtube_browser_chrome'] = 'standard';
668
669 // Avoiding negavite checkboxes, like "Disable Embed Button"
670 foreach( array(
671 'disableembedding' => 'ui_embed',
672 'disablesharing' => 'ui_sharing',
673 'disable_video_hash_links' => 'ui_video_links'
674 ) as $old_key => $new_key ) {
675 if ( ! isset( $conf[ $new_key ] ) ) {
676 if ( ! empty( $conf[ $old_key ] ) && 'false' === $conf[ $old_key ] ) {
677 $conf[ $new_key ] = 'true';
678 } else {
679 $conf[ $new_key ] = 'false';
680 }
681 }
682 }
683
684 // apply existing colors from old config values to the new, skin-based config array
685 if (!isset($conf['skin-custom'])) {
686 $conf['skin-custom'] = $this->aDefaultSkins['skin-custom'];
687
688 // iterate over old keys and bring them in to the new
689 $old_skinless_settings_array = array(
690 'hasBorder', 'borderColor', 'backgroundColor',
691 'font-face', 'progressColor', 'durationColor',
692 'design-timeline', 'design-icons'
693 );
694
695 foreach ($old_skinless_settings_array as $configKey) {
696 if (isset($conf[$configKey])) {
697 $conf['skin-custom'][ $configKey ] = $conf[$configKey];
698 }
699 }
700
701 $conf['skin-slim']['progressColor'] = '#bb0000';
702 $conf['skin-youtuby']['progressColor'] = '#bb0000';
703 }
704
705 // set to slim, if no skin set
706 if (!isset($conf['skin'])) $conf['skin'] = 'slim';
707
708 if ( ! empty( $conf['sticky_video'] ) && 'true' === $conf['sticky_video'] ) {
709 $conf['sticky_video'] = 'desktop';
710 }
711
712 $conf = apply_filters('fv_player_conf_defaults', $conf);
713
714 update_option( 'fvwpflowplayer', $conf );
715
716 // hard-coded defaults for the skin preset
717 $conf['skin-slim'] = array_merge( $conf['skin-slim'], $this->aDefaultSkins['skin-slim'] );
718 $conf['skin-youtuby'] = array_merge( $conf['skin-youtuby'], $this->aDefaultSkins['skin-youtuby'] );
719
720 $conf = apply_filters('fv_player_conf_loaded', $conf);
721
722 $this->conf = $conf;
723 return true;
724 /// End of addition
725 }
726
727
728 public function _get_option($key) {
729 $conf = $this->conf;
730 $value = false;
731 if( is_array($key) && count($key) === 2) {
732 if( isset($conf[$key[0]]) && isset($conf[$key[0]][$key[1]]) ) {
733 $value = $conf[$key[0]][$key[1]];
734 }
735 } elseif( isset($conf[$key]) ) {
736 $value = $conf[$key];
737 }
738
739 if( is_string($value) ) $value = trim($value);
740
741 if($value === 'false')
742 $value = false;
743 else if($value === 'true')
744 $value = true;
745
746 return $value;
747 }
748
749
750 public function _set_conf( $aNewOptions = false ) {
751
752 if ( ! $aNewOptions & ! empty( $_POST['fv_flowplayer_settings_ajax_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['fv_flowplayer_settings_ajax_nonce'] ) ), 'fv_flowplayer_settings_ajax_nonce' ) ) {
753
754 $popups_fields = array();
755 for( $i = 0; $i < 1000; $i++ ) {
756 $popups_fields[] = array(
757 'css',
758 'html',
759 );
760 }
761
762 $html_fields = apply_filters(
763 'fv_player_settings_html',
764 array(
765 'overlay',
766 'popups' => $popups_fields,
767 'pro' => array(
768 'download_template',
769 )
770 )
771 );
772
773 $multiline_fields = apply_filters(
774 'fv_player_settings_multiline',
775 array(
776 'customCSS',
777 'overlay_css',
778 'pro' => array(
779 'cf_pk',
780 )
781 )
782 );
783
784 $settings = apply_filters(
785 'fv_player_settings',
786 array(
787 'allowfullscreen',
788 'amazon_bucket',
789 'amazon_expire',
790 'amazon_expire_force',
791 'amazon_key',
792 'amazon_region',
793 'amazon_secret',
794 '_is_secret_amazon_secret', // make sure the flag for obfuscated fields is carried over
795 'autoplay_preload',
796 'bunny_stream',
797 'chromecast',
798 'closedpostboxesnonce',
799 'cloudflare_stream', // FV Player Cloudflare Stream extension
800 'coconut', // FV Player Coconut extension
801 'coconut_video_variants', // FV Player Coconut extension
802 'css_disable',
803 'css_writeout',
804 'customCSS',
805 'digitalocean_spaces',
806 'disable_convert_db_save',
807 'disable_localstorage',
808 'disable_videochecker',
809 'email_lists',
810 'engine',
811 'fv-player-pro-release', // FV Player Pro extension
812 'fv_player_admin_pro_quality_alive', // FV Player Pro extension
813 'googleanalytics',
814 'hd_streaming',
815 'height',
816 'indie_video_ads', // FV Player Indie Video Ads extension
817 'integrations',
818 'interface',
819 'js-everywhere',
820 'js-optimize',
821 'jw_player', // FV Player JW Player extension
822 'key',
823 'lightbox_force',
824 'lightbox_images',
825 'lightbox_improve_galleries',
826 'linode_object_storage',
827 'liststyle',
828 'logo',
829 'logo_over_video',
830 'logoPosition',
831 'mailchimp_api',
832 'mailchimp_label',
833 'mailchimp_list',
834 'matomo_domain',
835 'matomo_site_id',
836 'meta-box-order-nonce',
837 'mobile_alternative_fullscreen',
838 'mobile_force_fullscreen',
839 'mobile_native_fullscreen',
840 'multiple_playback',
841 'overlay',
842 'overlayLinksColor',
843 'overlayTextColor',
844 'overlay_css',
845 'overlay_height',
846 'overlay_show_after',
847 'overlay_width',
848 'parse_commas',
849 'parse_comments',
850 'playlist-design',
851 'playlistBgColor',
852 'playlistFontColor',
853 'playlistFontColor-proxy',
854 'playlistSelectedColor',
855 'playlist_advance',
856 'popupbox',
857 'popups',
858 'popups_default',
859 'postthumbnail',
860 'pro', // FV Player Pro extension
861 'profile_videos_enable_bio',
862 'remove_all_data',
863 'rtmp',
864 's3_browser',
865 'sharing_email_text',
866 'show_controlbar',
867 'skin',
868 'skin-custom',
869 'skin-slim',
870 'skin-youtuby',
871 'splash',
872 'sticky_place',
873 'sticky_video',
874 'sticky_width',
875 'sticky_width_mobile',
876 'subtitleBgColor',
877 'subtitleFontFace',
878 'subtitleOn',
879 'subtitleSize',
880 'ui_airplay',
881 'ui_embed',
882 'ui_no_picture_button',
883 'ui_repeat_button',
884 'ui_rewind_button',
885 'ui_sharing',
886 'ui_speed',
887 'ui_speed_increment',
888 'ui_video_links',
889 'user_playlist', // FV Player Bookmarks extension
890 'version',
891 'video_position_save_enable',
892 'video_sitemap',
893 'video_sitemap_meta',
894 'video_stats_enable',
895 'video_stats_enable_guest',
896 'viloud', // FV Player Viloud extension
897 'volume',
898 'width',
899 'wistia_use_fv_player',
900 'youtube_browser_chrome',
901 )
902 );
903
904 $aNewOptions = array();
905 foreach( $settings as $key ) {
906 if ( isset( $_POST[ $key ] ) ) {
907 $aNewOptions[ $key ] = $this->_set_conf_sanitize( $_POST[ $key ], $key, $settings, $html_fields, $multiline_fields );
908 }
909 }
910 }
911
912 $aNewOptions = fv_player_handle_secrets( $aNewOptions, $this->conf);
913
914 $is_ajax = isset($aNewOptions['fv-wp-flowplayer-submit-ajax']);
915
916 if( $is_ajax ) {
917 unset($aNewOptions['fv-wp-flowplayer-submit-ajax']);
918 unset($aNewOptions['fv_flowplayer_settings_ajax_nonce']);
919 } else {
920 unset($aNewOptions['fv-wp-flowplayer-submit']);
921 }
922
923 $sKey = !$is_ajax && !empty($aNewOptions['key']) ? trim($aNewOptions['key']) : false;
924
925 // make sure the preset Skin properties are not over-written
926 foreach( $this->aDefaultSkins AS $skin => $aSettings ) {
927 if ( 'skin-custom' === $skin ) {
928 continue;
929 }
930
931 foreach( $aSettings AS $k => $v ) {
932 unset($aNewOptions[$skin][$k]);
933 }
934 }
935
936 if(isset($aNewOptions['popups'])){
937 unset($aNewOptions['popups']['#fv_popup_dummy_key#']);
938
939 foreach( $aNewOptions['popups'] AS $key => $value ) {
940 $aNewOptions['popups'][$key]['css'] = stripslashes($value['css']);
941 $aNewOptions['popups'][$key]['html'] = stripslashes($value['html']);
942 }
943
944 update_option('fv_player_popups',$aNewOptions['popups']);
945 unset($aNewOptions['popups']);
946 }
947
948 foreach( $aNewOptions AS $key => $value ) {
949 if( is_array($value) ) {
950 $aNewOptions[$key] = $value;
951
952 // now that we have skin colors separated in an arrayed sub-values,
953 // we also need to check their values for HEX colors
954 foreach ($value as $sub_array_key => $sub_array_value) {
955 if ( strpos( $sub_array_key, 'Color' ) !== FALSE && strpos($sub_array_value, 'rgba') === FALSE) {
956 $aNewOptions[$key][$sub_array_key] = (strpos($sub_array_value, '#') === FALSE ? '#' : '').strtolower($sub_array_value);
957 }
958 }
959 } else if( in_array( $key, array('width', 'height') ) ) {
960 $aNewOptions[$key] = trim( preg_replace('/[^0-9%]/', '', $value) );
961 } else if( !in_array( $key, array('amazon_region', 'amazon_bucket', 'amazon_key', 'amazon_secret', 'font-face', 'overlay', 'overlay_css', 'subtitleFontFace','sharing_email_text','mailchimp_label','email_lists','playlist-design','subtitleBgColor', 'customCSS') ) ) {
962 $aNewOptions[$key] = trim( preg_replace('/[^A-Za-z0-9.:\-_\/,]/', '', $value) );
963 } else {
964 $aNewOptions[$key] = stripslashes(trim($value));
965 }
966 if ( strpos( $key, 'Color' ) !== FALSE && strpos($aNewOptions[$key], 'rgba') === FALSE) {
967 $aNewOptions[$key] = (strpos($aNewOptions[$key], '#') === FALSE ? '#' : '').strtolower($aNewOptions[$key]);
968 }
969 }
970
971 if( $sKey ) $aNewOptions['key'] = trim($sKey);
972
973 $aOldOptions = is_array(get_option('fvwpflowplayer')) ? get_option('fvwpflowplayer') : array();
974
975 // add pro options if they are not set
976 if( !isset($aOldOptions['pro']) || !is_array($aOldOptions['pro']) ) {
977 $aOldOptions['pro'] = array();
978 }
979
980 // merge pro options
981 if( isset($aNewOptions['pro']) ) $aNewOptions['pro'] = array_merge($aOldOptions['pro'],$aNewOptions['pro']);
982
983 // merge the rest of the options
984 $aNewOptions = array_replace_recursive( $aOldOptions, $aNewOptions );
985
986 // Ensure only one of "Load FV Flowplayer JS everywhere" and
987 // "Optimize FV Flowplayer JS loading" can be enabled
988 // The first one takes priority as it's safer
989 if( !empty($aNewOptions['js-everywhere']) && $aNewOptions['js-everywhere'] == 'true' && !empty($aNewOptions['js-optimize']) ) {
990 unset($aNewOptions['js-optimize']);
991 }
992
993 $aNewOptions = apply_filters( 'fv_flowplayer_settings_save', $aNewOptions, $aOldOptions );
994
995 update_option( 'fvwpflowplayer', $aNewOptions );
996
997 $this->_get_conf();
998
999 $this->css_writeout();
1000
1001 // We might be saving the settings in front-end too (plugin update hook)
1002 // so in that case we need to not do this
1003 if( function_exists('fv_wp_flowplayer_delete_extensions_transients') ) {
1004 fv_wp_flowplayer_delete_extensions_transients();
1005 }
1006
1007 if( empty($aOldOptions['key']) || $aOldOptions['key'] != $sKey ) {
1008 global $FV_Player_Pro_loader;
1009 if( isset($FV_Player_Pro_loader) ) {
1010 $FV_Player_Pro_loader->license_key = $sKey;
1011 }
1012 }
1013
1014 // Was "Remove all data" activated or deactivated?
1015 if ( ! empty( $_POST['fv_flowplayer_settings_ajax_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['fv_flowplayer_settings_ajax_nonce'] ) ), 'fv_flowplayer_settings_ajax_nonce' ) ) {
1016
1017 $put_in_uninstall_php = false;
1018 $remove_uninstall_php = false;
1019
1020 // Enabled
1021 if (
1022 ( empty( $aOldOptions['remove_all_data'] ) || 'false' === $aOldOptions['remove_all_data'] ) &&
1023 ! empty( $aNewOptions['remove_all_data'] ) && 'true' === $aNewOptions['remove_all_data']
1024 ) {
1025 $put_in_uninstall_php = true;
1026
1027 // Disabled
1028 } else if (
1029 ! empty( $aOldOptions['remove_all_data'] ) && 'true' === $aOldOptions['remove_all_data'] &&
1030 ( empty( $aNewOptions['remove_all_data'] ) || 'false' === $aNewOptions['remove_all_data'] )
1031 ) {
1032 $remove_uninstall_php = true;
1033 }
1034
1035 if ( $put_in_uninstall_php || $remove_uninstall_php ) {
1036 fv_player_setup_uninstall_script( $put_in_uninstall_php, $remove_uninstall_php );
1037 }
1038 }
1039
1040 return true;
1041 }
1042
1043 /**
1044 * Sanitize the value of the option.
1045 *
1046 * TODO: Also check if the option is allowed to be saved by looking it up in $settings.
1047 * All the plugins would have to register their settings arrays with fv_player_settings filter.
1048 *
1049 * @param string $value The value of the option.
1050 * @param string $key The key of the option.
1051 * @param array $settings The settings array.
1052 * @param array $html_fields The fields that should be sanitized as HTML.
1053 * @param array $multiline_fields The fields that should be sanitized as multiline text.
1054 *
1055 * @return string|array The sanitized value.
1056 */
1057 function _set_conf_sanitize( $value, $key, $settings, $html_fields, $multiline_fields ) {
1058
1059 if ( is_array( $value ) ) {
1060 foreach( $value as $nested_key => $nested_value ) {
1061 $value[ $nested_key ] = $this->_set_conf_sanitize(
1062 $nested_value,
1063 $nested_key,
1064 ! empty( $settings[ $key ] ) ? $settings[ $key ] : array(),
1065 ! empty( $html_fields[ $key ] ) ? $html_fields[ $key ] : array(),
1066 ! empty( $multiline_fields[ $key ] ) ? $multiline_fields[ $key ] : array()
1067 );
1068 }
1069 return $value;
1070 }
1071
1072 if ( in_array( $key, $html_fields ) ) {
1073 add_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_permit' ), 999, 2 );
1074 add_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_permit_settings' ), 999, 2 );
1075 add_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_permit_scripts' ), 999, 2 );
1076
1077 $value = wp_kses( wp_unslash( $value ), 'post' );
1078
1079 remove_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_permit' ), 999, 2 );
1080 remove_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_permit_settings' ), 999, 2 );
1081 remove_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_permit_scripts' ), 999, 2 );
1082
1083 } else if ( in_array( $key, $multiline_fields ) ) {
1084 $value = sanitize_textarea_field( $value );
1085
1086 } else {
1087 $value = sanitize_text_field( $value );
1088 }
1089
1090 return $value;
1091 }
1092
1093 public function _set_option($key, $value) {
1094 $aOldOptions = get_option( 'fvwpflowplayer', array() );
1095
1096 if( ! is_array($key) ) {
1097 $aNewOptions = array_merge($aOldOptions,array($key => $value));
1098 } else {
1099 $aNewOptions = $aOldOptions;
1100
1101 if( !isset($aNewOptions[$key[0]]) || !is_array($aNewOptions[$key[0]]) ) {
1102 $aNewOptions[$key[0]] = array();
1103 }
1104
1105 $aNewOptions[$key[0]][$key[1]] = $value;
1106 }
1107
1108 update_option( 'fvwpflowplayer', $aNewOptions );
1109
1110 $this->_get_conf();
1111 }
1112
1113 /**
1114 * Salt function - returns pseudorandom string hash.
1115 * @return Pseudorandom string hash.
1116 */
1117 public function _salt() {
1118 $salt = substr(md5(uniqid( wp_rand(), true) ), 0, 10);
1119 return $salt;
1120 }
1121
1122 public function get_video_checker_media($mediaData , $src1 = false, $src2 = false, $rtmp = false) {
1123 global $FV_Player_Pro;
1124 $media = $mediaData['sources'];
1125
1126 static $enabled;
1127 if( !isset($enabled) ) {
1128 $enabled = current_user_can('manage_options') && !$this->_get_option('disable_videochecker') && ( $this->_get_option('video_checker_agreement') || $this->_get_option('key_automatic') );
1129 }
1130
1131 if( $enabled && $this->ajax_count < 100 ) {
1132 $this->ajax_count++;
1133
1134 if( stripos($rtmp,'rtmp://') === false && $rtmp ) {
1135 list( $rtmp_server, $rtmp ) = $this->get_rtmp_server($rtmp);
1136 $rtmp = trailingslashit($rtmp_server).$rtmp;
1137 }
1138
1139 $aTest_media = array();
1140 foreach( $media as $h => $v ) {
1141 if( $v ) {
1142 // allow checker skip using filter
1143 if( apply_filters( 'fv_player_video_checker_skip', false, $v['src'] ) ) {
1144 continue;
1145 }
1146
1147 $temp_media = $this->get_video_src( $v['src'], array( 'dynamic' => true ) );
1148
1149 if( isset($FV_Player_Pro) && $FV_Player_Pro ) {
1150 if (
1151 method_exists( $FV_Player_Pro, 'is_vimeo') && $FV_Player_Pro->is_vimeo($temp_media) ||
1152 method_exists( $FV_Player_Pro, 'is_vimeo_event' ) && $FV_Player_Pro->is_vimeo_event($temp_media)
1153 ) {
1154 continue;
1155 }
1156 }
1157
1158 if( strcmp( $v['type'], 'video/youtube') === 0 ) {
1159 continue;
1160 }
1161
1162 $aTest_media[] = $temp_media;
1163 }
1164 }
1165
1166 if( !empty($this->aCurArgs['mobile']) ) {
1167 $aTest_media[] = $this->get_video_src($this->aCurArgs['mobile'], array( 'dynamic' => true ) );
1168 }
1169
1170 if( isset($aTest_media) && count($aTest_media) > 0 ) {
1171 $mediaData['video_checker'] = $aTest_media;
1172 return $mediaData;
1173 }
1174 }
1175
1176 return $mediaData;
1177 }
1178
1179
1180 public function add_fake_extension( $media ) {
1181 if( stripos( $media, '(format=m3u8' ) !== false ) { // http://*.streaming.mediaservices.windows.net/*.ism/manifest(format=m3u8-aapl)
1182 $media .= '#.m3u8'; // if this is not added then the Flowpalyer Flash HLS won't play the HLS stream!
1183 }
1184 return $media;
1185 }
1186
1187
1188 private function build_playlist_html( $aArgs, $sSplashImage, $sItemCaption, $aPlayer, $index ) {
1189 $aPlayer = apply_filters( 'fv_player_item', $aPlayer, $index, $aArgs );
1190
1191 $aItem = isset($aPlayer['sources']) && isset($aPlayer['sources'][0]) ? $aPlayer['sources'][0] : false;
1192 $sListStyle = !empty($aArgs['liststyle']) ? $aArgs['liststyle'] : false;
1193
1194 $sItemCaption = flowplayer::filter_possible_html($sItemCaption);
1195
1196 if ($this->current_video()) {
1197 if ( $this->current_video()->getTitleHide() && $this->current_video()->getToggleAdvancedSettings() ) {
1198 $sItemCaption = false;
1199 }
1200 }
1201
1202 if( !$sItemCaption && $sListStyle == 'text' ) $sItemCaption = 'Video '.($index+1);
1203
1204 $sItemCaptionOriginal = $sItemCaption;
1205
1206 if( !empty($aArgs['members_only']) ) {
1207 $sHTML = "\t\t<a href='".esc_attr($aArgs['members_only'])."' data-fancybox>";
1208 } else {
1209 $arg = !empty($this->aCurArgs['lazy']) ? 'data-item-lazy' : 'data-item';
1210 $sHTML = "\t\t<a href='#' ".$arg."='".$this->json_encode($aPlayer)."'>";
1211 }
1212
1213 $tDuration = false;
1214 if( isset($aPlayer['fv_start']) && isset($aPlayer['fv_end']) ) { // change duration if using custom startend
1215 $tDuration = $aPlayer['fv_end'] - $aPlayer['fv_start'];
1216 } else {
1217 if ($this->current_video()) {
1218 $tDuration = $this->current_video()->getDuration();
1219 }
1220
1221 if( !empty($aArgs['durations']) ) {
1222 $aDurations = explode( ';', $aArgs['durations'] );
1223 if( !empty($aDurations[$index]) ) {
1224 $tDuration = $aDurations[$index];
1225 }
1226 }
1227
1228 global $post;
1229 if( !$tDuration && $post && isset($post->ID) && !empty($aItem['src']) ) {
1230 $tDuration = flowplayer::get_duration( $post->ID, $aItem['src'], true );
1231 }
1232
1233 if( isset($aPlayer['fv_start']) && !empty($tDuration) ) { // custom start only
1234 $tDuration = flowplayer::hms_to_seconds( $tDuration ) - $aPlayer['fv_start'];
1235 }
1236
1237 if( isset($aPlayer['fv_end']) ) { // custom end only
1238 $tDuration = $aPlayer['fv_end'];
1239 }
1240
1241 }
1242
1243 if( $sListStyle != 'text' ) {
1244 $current_video_splash_id = false;
1245
1246 $current_video = $this->current_video();
1247 if ( $current_video ) {
1248 $current_video_splash_id = $current_video->getSplashAttachmentId();
1249 }
1250
1251 if ( $current_video_splash_id || $sSplashImage ) {
1252 $sHTML .= "<div class='fvp-playlist-thumb-img'>";
1253
1254 $image_html = false;
1255
1256 // Load from WordPress Media Library
1257 if ( $current_video_splash_id ) {
1258 $image_html = wp_get_attachment_image( $current_video_splash_id, 'medium', false, array( 'fv_sizes' => '25vw, 50vw, 100vw', 'loading' => 'lazy' ) );
1259 }
1260
1261 // Fall back to URL is the image is not in the Media Library
1262 if( ! $image_html && $sSplashImage ) {
1263 if( !( defined( 'DONOTROCKETOPTIMIZE' ) && DONOTROCKETOPTIMIZE ) && function_exists( 'get_rocket_option' ) && get_rocket_option( 'lazyload' ) && apply_filters( 'do_rocket_lazyload', true ) ) {
1264 $image_html = "<img src='data:image/gif;base64,R0lGODdhAQABAPAAAP///wAAACwAAAAAAQABAEACAkQBADs=' data-lazy-src='" . esc_attr( $sSplashImage ) . "' />";
1265
1266 } else {
1267 $image_html = "<img ". ( get_query_var('fv_player_embed') || get_query_var('fv_player_cms_id') ? "data-no-lazy='1'" : "" ) . " src='" . esc_attr( $sSplashImage ) . "' loading='lazy' />";
1268 }
1269
1270 }
1271
1272 $sHTML .= $image_html;
1273
1274 } else {
1275 $sHTML .= "<div class='fvp-playlist-thumb-img no-image'>";
1276 }
1277
1278 if( !empty($tDuration) && intval($tDuration) && ( !empty($this->aCurArgs['saveposition']) || $this->_get_option('video_position_save_enable') ) && is_user_logged_in() ) {
1279 $tDuration = flowplayer::hms_to_seconds( $tDuration );
1280 $tPosition = !empty($aItem['position']) ? $aItem['position'] : 0;
1281 if( $tPosition > 0 && !empty($aPlayer['fv_start']) ) {
1282 $tPosition -= $aPlayer['fv_start'];
1283 if( $tPosition < 0 ) {
1284 $tPosition = 0;
1285 }
1286 }
1287
1288 if( !empty($aItem['saw']) ) {
1289 $tPosition = $tDuration;
1290 }
1291
1292 $sHTML .= '<span class="fvp-progress-wrap"><span class="fvp-progress" style="width: '.( 100 * $tPosition / $tDuration ).'%" data-duration="'.esc_attr($tDuration).'"></
1293 span></span>';
1294 } else if( !empty($aItem['saw']) ) {
1295 $sHTML .= '<span class="fvp-progress-wrap"><span class="fvp-progress" style="width: 100%"></span></span>';
1296 }
1297 $sHTML .= "</div>"; // close .fvp-playlist-thumb-img
1298 }
1299
1300 if( $sListStyle == 'season' ) {
1301 $sHTML .= "<div class='fvp-playlist-item-info'>";
1302 if( $sItemCaption ) {
1303 $sHTML .= "<h4>".$sItemCaption."</h4>";
1304 }
1305 if ($this->current_video()) {
1306 $sSynopsis = $this->current_video()->getMetaValue('synopsis',true);
1307 if( $sSynopsis ) {
1308 $sHTML .= wpautop($sSynopsis);
1309 }
1310 }
1311
1312 if( !empty($aArgs['synopsis']) ) {
1313 // preserver semicolons
1314 $synopsis_items = str_replace( '\;', '{fv-player-semicolon}', $aArgs['synopsis'] );
1315
1316 $synopsis_items = explode( ';', $synopsis_items );
1317 if( !empty($synopsis_items[$index]) ) {
1318 // put back semicolons
1319 $sHTML .= wpautop( str_replace( '{fv-player-semicolon}', ';', $synopsis_items[$index] ) );
1320 }
1321 }
1322
1323 if( $tDuration ) {
1324 $sHTML .= '<i class="dur">('.ceil( flowplayer::hms_to_seconds($tDuration)/60).'m)</i>';
1325 }
1326
1327 $sHTML .= "</div>";
1328
1329 } else {
1330 if( $sItemCaption ) $sItemCaption = "<span>".$sItemCaption."</span>";
1331
1332 if( $tDuration ) {
1333 $sDuration = '<i class="dur">'.flowplayer::format_hms($tDuration).'</i>';
1334 if( !empty($this->aCurArgs['listdesign']) && $this->aCurArgs['listdesign'] == '2014' || empty($this->aCurArgs['listdesign']) && $this->_get_option('playlist-design') == 2014 ) {
1335 $sHTML .= $sDuration;
1336 } else {
1337 $sItemCaption .= $sDuration;
1338 }
1339 }
1340
1341 if( $sItemCaption || $this->is_audio_playlist() ) {
1342 $sHTML .= "<h4>".$sItemCaption."</h4>";
1343 }
1344
1345 }
1346
1347 $sHTML .= "</a>\n";
1348
1349 $sHTML = apply_filters( 'fv_player_item_html', $sHTML, $aArgs, $sSplashImage, $sItemCaptionOriginal, $aPlayer, $index, $tDuration );
1350
1351 return $sHTML;
1352 }
1353
1354 // todo: this could be parsing rtmp://host/path/mp4:rtmp_path links as well
1355 function build_playlist( $aArgs, $media, $src1, $src2, $rtmp, $splash_img, $suppress_filters = false ) {
1356
1357 $sShortcode = isset($aArgs['playlist']) ? $aArgs['playlist'] : false;
1358 $sCaption = isset($aArgs['caption']) ? $aArgs['caption'] : false;
1359 if( !$sCaption && isset($aArgs['title']) ) {
1360 $sCaption = $aArgs['title'];
1361 }
1362
1363 $replace_from = array('&amp;','\;', '\,');
1364 $replace_to = array('<!--amp-->','<!--semicolon-->','<!--comma-->');
1365 $sShortcode = str_replace( $replace_from, $replace_to, $sShortcode );
1366 $sItems = explode( ';', $sShortcode );
1367
1368 if( $sCaption ) {
1369 $replace_from = array('&amp;quot;','&amp;','\;','&quot;');
1370 $replace_to = array('"','<!--amp-->','<!--semicolon-->','"');
1371 $sCaption = str_replace( $replace_from, $replace_to, $sCaption );
1372 $aCaption = explode( ';', $sCaption );
1373 }
1374 if( isset($aCaption) && count($aCaption) > 0 ) {
1375 foreach( $aCaption AS $key => $item ) {
1376 $aCaption[$key] = str_replace('<!--amp-->','&',$item);
1377 $aCaption[$key] = str_replace('<!--semicolon-->',';',$item);
1378 }
1379 }
1380
1381 $aDurations = !empty($aArgs['durations']) ? explode( ';', $aArgs['durations'] ) : array();
1382
1383 $aItem = array();
1384
1385 if( $rtmp && stripos($rtmp,'rtmp://') === false ) {
1386 $rtmp = 'rtmp:'.$rtmp;
1387 }
1388
1389 if( isset($aArgs['toggle_advanced_settings']) && !$aArgs['toggle_advanced_settings'] ) { // disable alternative sources if advanced settings are hidden
1390 $src1 = $src2 = $rtmp = false;
1391 }
1392
1393 foreach( apply_filters( 'fv_player_media', array($media, $src1, $src2, $rtmp), $this ) AS $key => $media_item ) {
1394 if( !$media_item ) continue;
1395
1396 if( stripos($media_item,'rtmp:') === 0 && stripos($media_item,'rtmp://') === false ) {
1397 $media_item_tmp = preg_replace( '~^rtmp:~', '', $media_item );
1398 } else {
1399 $media_item_tmp = $media_item;
1400 }
1401
1402 $media_url = $this->get_video_src( $media_item_tmp, array( 'suppress_filters' => $suppress_filters ) );
1403
1404 // add domain for relative video URLs if it's not RTMP
1405 if( stripos($media_item,'rtmp://') === false && $key != 3 ) {
1406 $media_url = $this->get_video_url($media_url);
1407 }
1408
1409 if( stripos( $media_item, 'rtmp:' ) === 0 ) {
1410 if( !preg_match( '~^[a-z0-9]+:~', $media_url ) ) { // no RTMP extension provided
1411 $ext = $this->get_mime_type($media_url,false,true) ? $this->get_mime_type($media_url,false,true).':' : false;
1412 $aItem[] = array( 'src' => $ext.str_replace( '+', ' ', $media_url ), 'type' => 'video/flash' );
1413 } else {
1414 $aItem[] = array( 'src' => str_replace( '+', ' ', $media_url ), 'type' => 'video/flash' );
1415 }
1416 } else {
1417 $aItem[] = array( 'src' => $media_url, 'type' => $this->get_mime_type($media_url) );
1418 }
1419 }
1420
1421 $aItem = $this->process_preferred_video_type( $aItem );
1422
1423 $sItemCaption = ( isset($aCaption) ) ? array_shift($aCaption) : false;
1424
1425 list( $rtmp_server, $rtmp ) = $this->get_rtmp_server($rtmp);
1426
1427 if( !empty($aArgs['mobile']) ) {
1428 $mobile = $this->get_video_src( $this->get_video_url($aArgs['mobile']) );
1429 $aItem[] = array( 'src' => $mobile, 'type' => $this->get_mime_type($mobile), 'mobile' => true );
1430 }
1431
1432 if( isset($aArgs['toggle_advanced_settings']) && !$aArgs['toggle_advanced_settings'] ) {
1433 $mobile = false;
1434 }
1435
1436 $aPlayer = array( 'sources' => $aItem );
1437 if( $rtmp_server ) $aPlayer['rtmp'] = array( 'url' => $rtmp_server );
1438
1439 $aPlayer = apply_filters( 'fv_player_item_pre', $aPlayer, 0, $aArgs );
1440
1441 if ($this->current_video()) {
1442 if( !$splash_img ) $splash_img = $this->current_video()->getSplash();
1443 if( !$sItemCaption ) $sItemCaption = $this->current_video()->getTitle();
1444
1445 $remove_black_bars = $this->current_video()->getMetaValue( 'remove_black_bars', true );
1446 if ( $remove_black_bars && $aArgs['toggle_advanced_settings'] ) {
1447 $aPlayer['remove_black_bars'] = true;
1448 }
1449 }
1450
1451 $splash_img = apply_filters( 'fv_flowplayer_playlist_splash', $splash_img, !empty($aPlayer['sources'][0]['src']) ? $aPlayer['sources'][0]['src'] : false );
1452 $sItemCaption = apply_filters( 'fv_flowplayer_caption', $sItemCaption, $aItem, $aArgs );
1453
1454 if( $sItemCaption ) {
1455 $aPlayer['fv_title'] = $sItemCaption;
1456 if( $this->_get_option('matomo_domain') && $this->_get_option('matomo_site_id') ) {
1457 $aPlayer['matomoTitle'] = $sItemCaption;
1458 }
1459 }
1460
1461 if( $splash_img ) {
1462 $aPlayer['splash'] = $splash_img;
1463 }
1464
1465 if( empty($aPlayer['duration']) && !empty($aDurations[0]) ) {
1466 $aPlayer['duration'] = $aDurations[0];
1467 }
1468
1469 $aPlaylistItems[] = $aPlayer;
1470 $aSplashScreens[] = $splash_img;
1471 $aCaptions[] = $sItemCaption;
1472
1473
1474 $sHTML = array();
1475
1476 if( isset($aArgs['liststyle']) && !empty($aArgs['liststyle']) ){
1477
1478 $sHTML[] = $this->build_playlist_html( $aArgs, $splash_img, $sItemCaption, $aPlayer, 0 );
1479 }else{
1480 $sHTML[] = "<a href='#' class='is-active'><span ".( (isset($splash_img) && !empty($splash_img)) ? "style='background-image: url(\"".$splash_img."\")' " : "" )."></span>$sItemCaption</a>\n";
1481 }
1482
1483 if( count($sItems) > 0 ) {
1484 foreach( $sItems AS $iKey => $sItem ) {
1485
1486 if( !$sItem ) continue;
1487
1488 $index = $iKey + 1;
1489
1490 $aPlaylist_item = explode( ',', $sItem );
1491
1492 foreach( $aPlaylist_item AS $key => $item ) {
1493 if( $key > 0 && ( stripos($item,'http:') !== 0 && stripos($item,'https:') !== 0 && stripos($item,'rtmp:') !== 0 && stripos($item,'/') !== 0 ) ) {
1494 $aPlaylist_item[$key-1] .= ','.$item;
1495 $aPlaylist_item[$key] = $aPlaylist_item[$key-1];
1496 unset($aPlaylist_item[$key-1]);
1497 }
1498 $aPlaylist_item[$key] = str_replace( $replace_to, $replace_from, $aPlaylist_item[$key] );
1499 }
1500
1501 $aItem = array();
1502 $sSplashImage = false;
1503
1504 foreach( apply_filters( 'fv_player_media', $aPlaylist_item, $this ) AS $aPlaylist_item_i ) {
1505
1506 // check known image extensions
1507 // also accept i.vimeocdn.com which doesn't use image extensions
1508 if( preg_match('~\.(png|gif|jpg|jpe|jpeg)($|\?)~',$aPlaylist_item_i) || stripos($aPlaylist_item_i, 'i.vimeocdn.com') !== false ) {
1509 $sSplashImage = $aPlaylist_item_i;
1510 continue;
1511 }
1512
1513 $media_url = $this->get_video_src( preg_replace( '~^rtmp:~', '', $aPlaylist_item_i ), array( 'suppress_filters' => $suppress_filters ) );
1514
1515 if( stripos( $aPlaylist_item_i, 'rtmp:' ) === 0 ) {
1516 if( !preg_match( '~^[a-z0-9]+:~', $media_url ) ) { // no RTMP extension provided
1517 $ext = $this->get_mime_type($media_url,false,true) ? $this->get_mime_type($media_url,false,true).':' : false;
1518 $aItem[] = array( 'src' => $ext.str_replace( '+', ' ', $media_url ), 'type' => 'video/flash' );
1519 } else {
1520 $aItem[] = array( 'src' => str_replace( '+', ' ', $media_url ), 'type' => 'video/flash' );
1521 }
1522 } else {
1523 $aItem[] = array( 'src' => $media_url, 'type' => $this->get_mime_type($media_url) );
1524 }
1525
1526 }
1527
1528 $aPlayer = array( 'sources' => $aItem );
1529 if( $rtmp_server ) $aPlayer['rtmp'] = array( 'url' => $rtmp_server );
1530
1531 $sItemCaption = ( isset($aCaption[$iKey]) ) ? $aCaption[$iKey] : false;
1532
1533 $aPlayer = apply_filters( 'fv_player_item_pre', $aPlayer, $index, $aArgs );
1534
1535 $aPlayer['sources'] = $this->process_preferred_video_type( $aPlayer['sources'] );
1536
1537 if ($this->current_video()) {
1538 if( !$sSplashImage ) $sSplashImage = $this->current_video()->getSplash();
1539 if( !$sItemCaption ) $sItemCaption = $this->current_video()->getTitle();
1540
1541 $remove_black_bars = $this->current_video()->getMetaValue( 'remove_black_bars', true );
1542 if ( $remove_black_bars && $aArgs['toggle_advanced_settings'] ) {
1543 $aPlayer['remove_black_bars'] = true;
1544 }
1545 }
1546
1547 if( !$sSplashImage && $this->_get_option('splash') ) {
1548 $sSplashImage = $this->_get_option('splash');
1549 }
1550
1551 $sSplashImage = apply_filters( 'fv_flowplayer_playlist_splash', $sSplashImage, !empty($aPlayer['sources'][0]['src']) ? $aPlayer['sources'][0]['src'] : false );
1552 $sItemCaption = apply_filters( 'fv_flowplayer_caption', $sItemCaption, $aItem, $aArgs );
1553
1554 if( $sItemCaption ) {
1555 $aPlayer['fv_title'] = $sItemCaption;
1556 if( $this->_get_option('matomo_domain') && $this->_get_option('matomo_site_id') ) {
1557 $aPlayer['matomoTitle'] = $sItemCaption;
1558 }
1559 }
1560
1561 if( $sSplashImage ) {
1562 $aPlayer['splash'] = $sSplashImage;
1563 }
1564
1565 if( empty($aPlayer['duration']) && !empty($aDurations[$index]) ) {
1566 $aPlayer['duration'] = $aDurations[$index];
1567 }
1568
1569 $aPlaylistItems[] = $aPlayer;
1570
1571 $sHTML[] = $this->build_playlist_html( $aArgs, $sSplashImage, $sItemCaption, $aPlayer, $index );
1572 if( $sSplashImage ) {
1573 $aSplashScreens[] = $sSplashImage;
1574 }
1575 $aCaptions[] = $sItemCaption;
1576 }
1577 }
1578
1579 if(isset($this->aCurArgs['liststyle']) && $this->aCurArgs['liststyle'] != 'tabs'){
1580 $aPlaylistItems = apply_filters('fv_flowplayer_playlist_items',$aPlaylistItems,$this);
1581 }
1582
1583 $sHTML = apply_filters( 'fv_flowplayer_playlist_item_html', $sHTML );
1584
1585 $attributes = array();
1586 $attributes_html = '';
1587 $attributes['class'] = 'fp-playlist-external '.$this->get_playlist_class($aCaptions);
1588 $attributes['rel'] = 'wpfp_'.$this->hash;
1589 $attributes['id'] = 'wpfp_'.$this->hash.'_playlist';
1590
1591 // we put in enough to be sure it will fit in, later JS calculates a better value
1592 if( isset($this->aCurArgs['liststyle']) && $this->aCurArgs['liststyle'] == 'slider' ) {
1593 $slider_width = count( $aPlaylistItems ) * 200;
1594 $attributes['style'] = "width: " . absint( $slider_width ) . "px; max-width: " . absint( $slider_width ) . "px !important";
1595 }
1596
1597 $attributes = apply_filters( 'fv_player_playlist_attributes', $attributes, $media, $this );
1598 foreach( $attributes AS $attr_key => $attr_value ) {
1599 $attributes_html .= ' '.$attr_key.'="'.esc_attr( $attr_value ).'"';
1600 }
1601
1602 $items = implode( '', $sHTML );
1603
1604 if( isset($aArgs['liststyle']) ){
1605 $limit = 150;
1606 if( isset($aArgs['liststyle']) && in_array( $this->aCurArgs['liststyle'], array( 'version-one', 'version-two' ) ) ) {
1607 $limit = 200;
1608 }
1609
1610 if( in_array( $this->aCurArgs['liststyle'], array( 'version-one', 'version-two' ) ) ) {
1611 $items = "<div class='fv-playlist-draggable'>".$items."</div>";
1612 $items .= "<div class='fv-playlist-slider-controls'>
1613 <button class='fv-playlist-left-arrow'></button>
1614 <button class='fv-playlist-right-arrow'></button>
1615 </div>\n";
1616 }
1617 }
1618
1619 $sHTML = "\t<div$attributes_html>\n" . $items . "\t</div>\n";
1620
1621 /**
1622 * Pure-JavaScript version of freedomplayer_playlist_size_check() to avoid layout shift as the JavaScript loads.
1623 *
1624 * We don't need it if playlists is in lightbox = using slider playlist style.
1625 */
1626 if ( ! empty( $this->aCurArgs['liststyle'] ) && ! in_array( $this->aCurArgs['liststyle'], array( 'slider' ) ) ) {
1627 $script_fit_thumbs = '';
1628 if( isset($aArgs['liststyle']) && in_array( $this->aCurArgs['liststyle'], array( 'polaroid', 'version-one', 'version-two' ) ) ) {
1629 $script_fit_thumbs = "
1630 var w = getComputedStyle( el ).width;
1631 while ( w === 'auto' && el.parentNode ) {
1632 el = el.parentNode;
1633 w = getComputedStyle(el).width;
1634 }
1635 var f = Math.floor( parseInt( 'auto' === w ? 0 : w ) / " . absint( $limit ) . " );
1636 if( f > 8 ) f = 8;
1637 else if( f < 2 ) f = 2;
1638 el.style.setProperty('--fp-playlist-items-per-row', String(f));
1639 ";
1640 }
1641
1642 $script = "( function() {
1643 var el = document.getElementById( '" . $attributes['id'] ."' );
1644 if ( el.parentNode.getBoundingClientRect().width >= 900 ) {
1645 el.classList.add( 'is-wide' );
1646 } " . $script_fit_thumbs . "
1647 } )();";
1648
1649 // remove whitespace
1650 $script = preg_replace( '~\s+~m', ' ', $script );
1651
1652 $sHTML .= "\t<script>" . $script . "</script>\n";
1653 }
1654
1655 if( isset($aArgs['liststyle']) && $this->aCurArgs['liststyle'] == 'slider' ) {
1656 $sHTML = "<div class='fv-playlist-slider-wrapper'>".$sHTML."</div>\n";
1657 }
1658
1659 return array( $sHTML, $aPlaylistItems, $aSplashScreens, $aCaptions );
1660 }
1661
1662 public function check_license( $force ) {
1663 parent::setLicenseTransient( $force );
1664 }
1665
1666 function css_generate( $skip_style_tag = true ) {
1667 $this->_get_conf(); // todo: without this the colors for skin-slim might end up empty, why?
1668
1669 $sSubtitleBgColor = $this->_get_option('subtitleBgColor');
1670 if( $sSubtitleBgColor[0] == '#' && $this->_get_option('subtitleBgAlpha') ) {
1671 $sSubtitleBgColor = 'rgba('.hexdec(substr($sSubtitleBgColor,1,2)).','.hexdec(substr($sSubtitleBgColor,3,2)).','.hexdec(substr($sSubtitleBgColor,5,2)).','.$this->_get_option('subtitleBgAlpha').')';
1672 }
1673
1674 if( !$skip_style_tag ) : ?>
1675 <style type="text/css">
1676 <?php endif;
1677
1678 $css = '';
1679
1680 // generate CSS for all the available skin settings
1681 foreach( array('skin-slim','skin-youtuby','skin-custom') AS $skin ) {
1682 $sel = '.flowplayer.'.$skin;
1683
1684 $sBackground = $this->_get_option( array($skin, 'backgroundColor') );
1685 $sDuration = $this->_get_option( array($skin, 'durationColor') );
1686 $sProgress = $this->_get_option(array($skin, 'progressColor'));
1687 $sTimeline = $this->_get_option( array($skin, 'timelineColor') );
1688 $sAccent = $this->_get_option( array($skin, 'accent') );
1689
1690 if( $this->_get_option(array($skin, 'hasBorder')) ) {
1691 $css .= $sel." { border: 1px solid ".$this->_get_option(array($skin, 'borderColor'))."; }\n";
1692 }
1693
1694 $css .= $sel." .fp-color, ".$sel." .fp-selected, .fp-playlist-external.".$skin." .fvp-progress, .fp-color { background-color: ".$this->_get_option(array($skin, 'progressColor'))." !important; }\n";
1695 $css .= $sel." .fp-color-fill .svg-color, ".$sel." .fp-color-fill svg.fvp-icon, ".$sel." .fp-color-fill { fill: ".$this->_get_option(array($skin, 'progressColor'))." !important; color: ".$this->_get_option(array($skin, 'progressColor'))." !important; }\n";
1696 $css .= $sel." .fp-controls, .fv-player-buttons a:active, .fv-player-buttons a { background-color: ".$sBackground." !important; }\n";
1697 if( $sDuration ) {
1698 $css .= $sel." a.fp-play, ".$sel." a.fp-volumebtn, ".$sel." .fp-controls, ".$sel." .fv-ab-loop, .fv-player-buttons a:active, .fv-player-buttons a { color: ".$sDuration." }\n";
1699 $css .= $sel." .fp-controls .fv-fp-prevbtn:before, ".$sel." .fp-controls .fv-fp-nextbtn:before { border-color: ".$sDuration." !important; }\n";
1700 $css .= $sel." .fvfp_admin_error, ".$sel." .fvfp_admin_error a, #content ".$sel." .fvfp_admin_error a { color: ".$sDuration."; }\n";
1701 $css .= $sel." svg.fvp-icon { fill: ".$sDuration." !important; }\n";
1702
1703 $css .= $sel." .fp-elapsed, ".$sel." .fp-duration { color: ".$sDuration." !important; }\n";
1704 $css .= $sel." .fv-player-video-checker { color: ".$sDuration." !important; }\n";
1705 $css .= $sel." .fp-controls svg { fill: ".$sDuration."; stroke: ".$sDuration." }\n";
1706 }
1707
1708 if( $sTimeline ) {
1709 $css .= $sel." .fp-timeline { background-color: ".$sTimeline." !important; }\n";
1710 $css .= $sel. " .fp-bar span.chapter_unbuffered{ background-color: ".$sTimeline." !important; }\n";
1711 }
1712
1713 if( $sBackground != 'transparent' ) {
1714 $css .= $sel." .fv-ab-loop { background-color: ".$sBackground." !important; }\n";
1715 $css .= $sel." .fv_player_popup, .fvfp_admin_error_content { background: ".$sBackground."; }\n";
1716 }
1717
1718 if( $sAccent ) {
1719 $css .= $sel." .fv-ab-loop .noUi-connect { background-color: ".$sAccent." !important; }\n";
1720 }
1721
1722 $css .= $sel. " .fp-bar span.chapter_passed{ background-color: ".$sProgress." !important; }\n";
1723 $css .= ".fv-player-buttons a.current { background-color: ".$sProgress." !important; }\n";
1724 $css .= "#content ".$sel.", ".$sel." { font-family: ".$this->_get_option(array($skin, 'font-face'))."; }\n";
1725 $css .= $sel." .fp-dropdown li.active { background-color: ".$sProgress." !important }\n";
1726 }
1727
1728 echo esc_html( $css );
1729
1730 // rest is not depending of the skin settings or can use the default skin
1731 $skin = 'skin-'.$this->_get_option('skin');
1732
1733 ?>
1734
1735 .wpfp_custom_background { display: none; position: absolute; background-position: center center; background-repeat: no-repeat; background-size: contain; width: 100%; height: 100%; z-index: 1 }
1736 .wpfp_custom_popup { position: absolute; top: 10%; z-index: 20; text-align: center; width: 100%; color: #fff; }
1737 .wpfp_custom_popup h1, .wpfp_custom_popup h2, .wpfp_custom_popup h3, .wpfp_custom_popup h4 { color: #fff; }
1738 .is-finished .wpfp_custom_background { display: block; }
1739
1740 <?php echo esc_html( $this->_get_option('overlay_css') ); ?>
1741 .wpfp_custom_ad { color: <?php echo esc_html( $this->_get_option('overlayTextColor') ); ?>; z-index: 20 !important; }
1742 .wpfp_custom_ad a { color: <?php echo esc_html( $this->_get_option('overlayLinksColor') ); ?> }
1743
1744 .fp-playlist-external > a > span { background-color:<?php echo esc_html( $this->_get_option('playlistBgColor') ); ?>; }
1745 <?php if ( $this->_get_option('playlistFontColor') && $this->_get_option('playlistFontColor') !=='#') : ?>
1746 .fp-playlist-external a h4,
1747 .fp-playlist-external a:hover h4,
1748 .fp-playlist-external a.is-active:hover h4,
1749 .visible-captions.fp-playlist-external a h4 span,
1750 .fv-playlist-design-2014.fp-playlist-external a h4,
1751 .fv-playlist-design-2014.fp-playlist-external a:hover h4 { color:<?php echo esc_html( $this->_get_option('playlistFontColor') ); ?>; }
1752 <?php endif; ?>
1753 .fp-playlist-external > a.is-active > span { border-color:<?php echo esc_html( $this->_get_option('playlistSelectedColor') ); ?>; }
1754 .fp-playlist-external.fv-playlist-design-2014 a.is-active,
1755 .fp-playlist-external.fv-playlist-design-2014 a.is-active h4,
1756 .fp-playlist-external.fv-playlist-design-2014 a.is-active:hover h4,
1757 .fp-playlist-external.fp-playlist-only-captions a.is-active,
1758 .fp-playlist-external.fp-playlist-only-captions a.is-active h4,
1759 .fp-playlist-external.fp-playlist-only-captions a.is-active:hover h4 { color:<?php echo esc_html( $this->_get_option('playlistSelectedColor') ); ?>; }
1760 <?php if ( $this->_get_option('playlistBgColor') !=='#') : ?>.fp-playlist-vertical { background-color:<?php echo esc_html( $this->_get_option('playlistBgColor') ); ?>; }<?php endif; ?>
1761
1762 <?php if( $this->_get_option('subtitleSize') ) : ?>.flowplayer .fp-player .fp-captions p { font-size: <?php echo intval($this->_get_option('subtitleSize')); ?>px; }<?php endif; ?>
1763 <?php if( $this->_get_option('subtitleFontFace') ) : ?>.flowplayer .fp-player .fp-captions p { font-family: <?php echo esc_html( $this->_get_option('subtitleFontFace') ); ?>; }<?php endif; ?>
1764 <?php if( $this->_get_option('logoPosition') ) :
1765 $value = $this->_get_option('logoPosition');
1766 $sCSS = ! empty( $this->css_logo_positions[ $value ] ) ? $this->css_logo_positions[ $value ] : '';
1767 ?>.flowplayer > .fp-player > .fp-logo > img { <?php echo esc_html( $sCSS ); ?> }<?php endif; ?>
1768
1769 .flowplayer .fp-player .fp-captions p { background-color: <?php echo esc_html( $sSubtitleBgColor ); ?> }
1770
1771 .flowplayer .fp-player.is-sticky { max-width: <?php echo intval( $this->_get_option('sticky_width') ); ?>px }
1772 @media screen and ( max-width: 480px ) {
1773 .flowplayer .fp-player.is-sticky { max-width: <?php echo intval( $this->_get_option('sticky_width_mobile') ); ?>% }
1774 }
1775
1776 <?php echo apply_filters('fv_player_custom_css',''); ?>
1777 <?php if( !$skip_style_tag ) : ?>
1778 </style>
1779 <?php endif;
1780 }
1781
1782
1783 function css_enqueue( $force = false ) {
1784
1785 if(
1786 is_admin() && // do not load in wp-admin
1787 !did_action('admin_footer') && // if the footer was not yet shown
1788 !did_action('elementor/editor/wp_head') && // and if Elementor head was not yet loaded
1789 ( !isset($_GET['page']) || sanitize_key( $_GET['page'] ) != 'fvplayer' ) && // and unless it's the FV Player player
1790 !empty($_GET['legacy-widget-preview[idBase]']) // and unless it's the legacy widget preview of Gutenberg-powered WordPress 5.8 widgets
1791 ) {
1792 return;
1793 }
1794
1795 /*
1796 * Let's check if FV Player is going to be used before loading CSS!
1797 */
1798 global $posts, $post;
1799 if( !$posts || empty($posts) ) $posts = array( $post );
1800
1801 if( !$force && !$this->should_force_load_js() && isset($posts) && count($posts) > 0 ) {
1802 $bFound = false;
1803
1804
1805 foreach( $posts AS $objPost ) {
1806 if( !empty($objPost->post_content) && (
1807 stripos($objPost->post_content,'[fvplayer') !== false ||
1808 stripos($objPost->post_content,'[flowplayer') !== false ||
1809 stripos($objPost->post_content,'[video') !== false
1810 )
1811 ) {
1812 $bFound = true;
1813 break;
1814 }
1815
1816 if ( is_singular() ) {
1817 $post_meta = get_post_custom( $objPost->ID );
1818 if ( is_array( $post_meta ) ) {
1819 foreach ( $post_meta as $meta_values ) {
1820 foreach ( $meta_values as $meta_value ) {
1821 if ( stripos( $meta_value,'[fvplayer') !== false ) {
1822 $bFound = true;
1823 break 2;
1824 }
1825 }
1826 }
1827 }
1828 }
1829 }
1830
1831 if( !$bFound ) {
1832 return;
1833 }
1834 }
1835
1836 $this->bCSSLoaded = true;
1837
1838 global $fv_wp_flowplayer_ver;
1839 $this->bCSSInline = true;
1840 $sURL = FV_FP_RELATIVE_PATH.'/css/fv-player.min.css';
1841 $sVer = $fv_wp_flowplayer_ver;
1842 if( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) {
1843 $sVer = filemtime( dirname(__FILE__).'/../css/skin.css' );
1844 $sVerAdditions = filemtime( dirname(__FILE__).'/../css/fv-player-additions.css' );
1845
1846 $sURL = FV_FP_RELATIVE_PATH.'/css/skin.css';
1847 $sURLAdditions = FV_FP_RELATIVE_PATH.'/css/fv-player-additions.css';
1848 }
1849
1850 if( !( $this->_get_option('css_disable') || defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) && $this->_get_option($this->css_option()) ) {
1851 if( @file_exists($this->css_path()) ) {
1852 $sURL = $this->css_path('url');
1853 $sVer = $this->_get_option($this->css_option());
1854 $this->bCSSInline = false;
1855 $sURLAdditions = null;
1856 }
1857 }
1858
1859 if( is_admin() && did_action('admin_footer') ) {
1860 echo "<link rel='stylesheet' id='fv_freedomplayer-css' href='".esc_attr($sURL)."?ver=".$sVer."' type='text/css' media='all' />\n";
1861 if(isset($sURLAdditions)) {
1862 echo "<link rel='stylesheet' id='fv_freedomplayer-css-additions' href='".esc_attr($sURLAdditions)."?ver=".$sVerAdditions."' type='text/css' media='all' />\n";
1863 }
1864
1865 echo "<link rel='stylesheet' id='fv_freedomplayer_playlists-css' href='".esc_attr( FV_FP_RELATIVE_PATH.'/css/playlists.css' )."?ver=".filemtime( dirname(__FILE__).'/../css/playlists.css' )."' type='text/css' media='all' />\n";
1866
1867 echo "<link rel='stylesheet' id='fv_freedomplayer_admin' href='".FV_FP_RELATIVE_PATH."/css/admin.css?ver=" . filemtime( dirname(__FILE__).'/../css/admin.css' ) . "' type='text/css' media='all' />\n";
1868
1869 if( $this->bCSSInline ) {
1870 $this->css_generate(false);
1871 }
1872
1873 } else {
1874 $aDeps = array();
1875 if( class_exists('OptimizePress_Default_Assets') ) $aDeps = array('optimizepress-default'); // make sure the CSS loads after optimizePressPlugin
1876
1877 wp_enqueue_style( 'fv_flowplayer', $sURL, $aDeps, $sVer );
1878 if(isset($sURLAdditions)) {
1879 wp_enqueue_style( 'fv_freedomplayer_additions', $sURLAdditions, array('fv_flowplayer'), $sVerAdditions );
1880 }
1881
1882 if ( $this->bCSSPlaylists || $force || did_action( 'fv_player_force_load_assets' ) ) {
1883 wp_enqueue_style( 'fv_freedomplayer_playlists', FV_FP_RELATIVE_PATH.'/css/playlists.css', array('fv_flowplayer'), filemtime( dirname(__FILE__).'/../css/playlists.css' ) );
1884 }
1885
1886 if(is_user_logged_in()){
1887 wp_enqueue_style( 'fv_freedomplayer_admin', FV_FP_RELATIVE_PATH.'/css/admin.css', array(), filemtime( dirname(__FILE__).'/../css/admin.css' ) );
1888 }
1889
1890 if( $this->bCSSInline ) {
1891 add_action( did_action('wp_footer') ? 'wp_footer' : 'wp_head', array( $this, 'css_generate' ), 999 );
1892 add_action( 'admin_head', array( $this, 'css_generate' ) );
1893 }
1894
1895 }
1896
1897 }
1898
1899
1900 function css_option() {
1901 global $fv_wp_flowplayer_ver;
1902 return 'css_writeout-'.sanitize_title(home_url()) . '-' . $fv_wp_flowplayer_ver;
1903 }
1904
1905
1906 function css_path( $type = false ) {
1907 if( is_multisite() ) {
1908 global $blog_id;
1909 $site_id = $blog_id;
1910 } else {
1911 $site_id = 1;
1912 }
1913
1914 $name = 'fv-player-custom/style-'.$site_id.'.css';
1915 if( 'name' == $type ) {
1916 return $name;
1917 } else if( 'url' == $type ) {
1918 return trailingslashit( str_replace( array('/plugins','\\plugins'), '', plugins_url() )).$name;
1919 } else {
1920 return trailingslashit(WP_CONTENT_DIR).$name;
1921 }
1922 }
1923
1924
1925 function css_writeout() {
1926 if( $this->_get_option('css_disable') ) {
1927 return false;
1928 }
1929
1930 $aOptions = get_option( 'fvwpflowplayer' );
1931 $aOptions[$this->css_option()] = false;
1932 update_option( 'fvwpflowplayer', $aOptions );
1933
1934 /*$url = wp_nonce_url('admin.php?page=fvplayer','otto-theme-options');
1935 if( false === ($creds = request_filesystem_credentials($url, $method, false, false, $_POST) ) ) { // todo: no annoying notices here
1936 return false; // stop the normal page form from displaying
1937 } */
1938
1939 if ( ! WP_Filesystem(true) ) {
1940 return false;
1941 }
1942
1943 global $wp_filesystem;
1944 $filename = $wp_filesystem->wp_content_dir().$this->css_path('name');
1945
1946 // by this point, the $wp_filesystem global should be working, so let's use it to create a file
1947
1948 $bDirExists = false;
1949 if( !$wp_filesystem->exists($wp_filesystem->wp_content_dir().'fv-player-custom/') ) {
1950 if( $wp_filesystem->mkdir($wp_filesystem->wp_content_dir().'fv-player-custom/') ) {
1951 $bDirExists = true;
1952 }
1953 } else {
1954 $bDirExists = true;
1955 }
1956
1957 if( !$bDirExists ) {
1958 return false;
1959 }
1960
1961 ob_start();
1962 $this->css_generate(true);
1963
1964 $sCSS = "\n\n/*CSS writeout performed on FV Player Settings save on ".gmdate('r')."*/\n".ob_get_clean();
1965 if( !$sCSSCurrent = $wp_filesystem->get_contents( dirname(__FILE__).'/../css/fv-player.min.css' ) ) {
1966 return false;
1967 }
1968
1969 $sCSSCurrent = preg_replace_callback( '~url\(.*?\)~', array( $this, 'css_relative_paths_fix' ), $sCSSCurrent );
1970
1971 /**
1972 * Only keep relative paths by replacing the https://domain.com with an empty string
1973 */
1974 $home_url_parsed = wp_parse_url( home_url() );
1975
1976 if ( ! empty( $home_url_parsed['path'] ) ) {
1977 unset( $home_url_parsed['path'] );
1978 }
1979
1980 // reverse wp_parse_url for $home_url_parsed
1981 $home_url_without_path = $home_url_parsed['scheme'] . '://' . $home_url_parsed['host'] . ( isset( $home_url_parsed['port'] ) ? ':' . $home_url_parsed['port'] : '' );
1982
1983 $sCSSCurrent = str_replace( $home_url_without_path, '', $sCSSCurrent );
1984
1985 /**
1986 * Replace any left-over URLs with protocol agnostic URLs
1987 */
1988 $sCSSCurrent = str_replace( array('http://', 'https://'), array('//','//'), $sCSSCurrent );
1989
1990 if( !$wp_filesystem->put_contents( $filename, "/*\n * FV Player custom styles\n *\n * Warning: This file should not to be edited. Please put your custom CSS into your theme stylesheet or any custom CSS field of your template.\n */\n\n".$sCSSCurrent.$sCSS, FS_CHMOD_FILE) ) {
1991 return false;
1992 } else {
1993 $aOptions[$this->css_option()] = gmdate('U');
1994 update_option( 'fvwpflowplayer', $aOptions );
1995 $this->_get_conf();
1996 }
1997 }
1998
1999 /*
2000 * @param array $match
2001 * string $match[0] - CSS declaration with url() in "" or '' or without quotes,
2002 * using path like "icons/flowplayer.eot?#iefix"
2003 * or data URL like url("data:image/svg+xml;base64,PHN2...");
2004 *
2005 * @return string CSS declaration with fixed relative path.
2006 */
2007 function css_relative_paths_fix( $match ) {
2008 $path = self::get_plugin_url().'/css/';
2009 if(
2010 stripos($match[0],'data:') === false || // skip data URLs
2011 stripos($match[0],'//') === false // skip absolute paths
2012 ) {
2013 if( stripos($match[0],'url("') === 0 ) {
2014 $match[0] = str_replace( 'url("', 'url("'.$path, $match[0] );
2015 } else if( stripos($match[0],"url('") === 0 ) {
2016 $match[0] = str_replace( "url('", "url('".$path, $match[0] );
2017 } else if( stripos($match[0],'url(') === 0 ) {
2018 $match[0] = str_replace( 'url(', 'url('.$path, $match[0] );
2019 }
2020 }
2021 return $match[0];
2022 }
2023
2024 public function enable_cdn_rewrite( $item ) {
2025 if( is_admin() ) {
2026 return $item;
2027 }
2028
2029 foreach( $item['sources'] AS $k => $source ) {
2030
2031 // Not if the video URL has no path
2032 if ( empty( $source['src'] ) || ! wp_parse_url( $source['src'], PHP_URL_PATH ) ) {
2033 continue;
2034 }
2035
2036 if( function_exists('get_rocket_cdn_url') ) {
2037 $item['sources'][$k]['src'] = get_rocket_cdn_url($source['src']);
2038 }
2039
2040 if( method_exists('CDN_Enabler_Engine', 'rewriter') ) {
2041 $item['sources'][$k]['src'] = CDN_Enabler_Engine::rewriter($source['src']);
2042 }
2043
2044 if( class_exists('BunnyCDN') && class_exists('BunnyCDNFilter') && method_exists( 'BunnyCDN', 'getOptions' ) ) {
2045
2046 require_once dirname(__FILE__) . '/../includes/class.bunnycdn.rewrite.php';
2047
2048 $options = BunnyCDN::getOptions();
2049
2050 $fv_bunnycdn = new FV_Player_BunnyCDN_Rewrite($options["site_url"], (is_ssl() ? 'https://' : 'http://') . $options["cdn_domain_name"], $options["directories"], $options["excluded"], $options["disable_admin"]);
2051 $item['sources'][$k]['src'] = $fv_bunnycdn->rewrite_url($source['src']);
2052 }
2053
2054 }
2055
2056 return $item;
2057 }
2058
2059 function enable_cdn_rewrite_maybe() {
2060 // Support WordPress CDN plugins - can slow down the PHP if you have hundreds of videos on a single page
2061 // We tried to check if the video is using the site domain before checking with the WordPress CDN plugins
2062 // But there is just no way around this - even that would be slow
2063 // So if you greatly care about peformance use:
2064 //
2065 // add_filter( 'fv_player_performance_disable_wp_cdn', '__return_true' );
2066 if( !apply_filters( 'fv_player_performance_disable_wp_cdn', false ) ) {
2067 add_filter( 'fv_player_item', array( $this, 'enable_cdn_rewrite'), 11 );
2068 }
2069 }
2070
2071 public static function esc_caption( $caption ) {
2072 return str_replace( array(';','[',']'), array('\;','(',')'), $caption );
2073 }
2074
2075 /*
2076 * Use the heavy-duty WordPress HTML filtering if the value looks like it might be HTML
2077 *
2078 * @param string $content
2079 *
2080 * @return string Filtered string
2081 */
2082 public static function filter_possible_html( $content ) {
2083 if( stripos($content, '<') !== false || stripos($content, '>') !== false ) {
2084 $content = wp_kses( $content, 'post' );
2085 }
2086 return $content;
2087 }
2088
2089
2090 function get_amazon_secure( $media ) {
2091
2092 if( stripos($media,'X-Amz-Expires') !== false || stripos($media,'AWSAccessKeyId') !== false ) return $media;
2093
2094 global $fv_fp;
2095
2096 $amazon_key = -1;
2097 if( count($fv_fp->_get_option('amazon_key')) && count($fv_fp->_get_option('amazon_secret')) && count($fv_fp->_get_option('amazon_bucket')) ) {
2098 foreach( $fv_fp->_get_option('amazon_bucket') AS $key => $item ) {
2099 // The bucket name must be in the first folder
2100 // or the subdomain
2101 if(
2102 stripos($media,'.amazonaws.com/'.$item.'/') != false ||
2103 stripos($media,'.amazonaws.com.cn/'.$item.'/') != false ||
2104 stripos($media,'//'.$item.'.') != false
2105 ) {
2106 $amazon_key = $key;
2107 break;
2108 }
2109 }
2110 }
2111
2112 if( $amazon_key != -1 &&
2113 $fv_fp->_get_option( array('amazon_key', $amazon_key) ) &&$fv_fp->_get_option( array('amazon_secret', $amazon_key) ) && $fv_fp->_get_option( array('amazon_bucket', $amazon_key) ) && stripos( $media, $fv_fp->_get_option( array('amazon_bucket', $amazon_key) ) ) !== false && apply_filters( 'fv_flowplayer_amazon_secure_exclude', $media ) ) {
2114
2115 $resource = trim( $media );
2116
2117 if( !isset($fv_fp->expire_time) ) {
2118 $time = 60 * intval($fv_fp->_get_option('amazon_expire'));
2119 } else {
2120 $time = intval(ceil($fv_fp->expire_time));
2121 }
2122
2123 if( $fv_fp->_get_option('amazon_expire_force') ) {
2124 $time = 60 * intval($fv_fp->_get_option('amazon_expire'));
2125 }
2126
2127 if( $time < 900 ) {
2128 $time = 900;
2129 }
2130
2131 $time = apply_filters( 'fv_flowplayer_amazon_expires', $time, $media );
2132
2133 // Allow to set the expire time to 0 to disable it = use 1 week
2134 if ( ! $time ) {
2135 $time = WEEK_IN_SECONDS;
2136 }
2137
2138 $url_components = wp_parse_url($resource);
2139
2140 // decode the path, as it might come partially URL encoded already
2141 $url_components['path'] = urldecode( $url_components['path'] );
2142
2143 // URL encode the decoded path
2144 $url_components['path'] = rawurlencode( $url_components['path'] );
2145
2146 // Restore the directory separators
2147 $url_components['path'] = str_replace('%2F', '/', $url_components['path']);
2148
2149 $iAWSVersion = $fv_fp->_get_option( array( 'amazon_region', $amazon_key ) ) ? 4 : 2;
2150
2151 if( $iAWSVersion == 4 ) {
2152 $sXAMZDate = gmdate('Ymd\THis\Z');
2153 $sDate = gmdate('Ymd');
2154 $sCredentialScope = $sDate."/".$fv_fp->_get_option( array('amazon_region', $amazon_key ) )."/s3/aws4_request"; // todo: variable
2155 $sSignedHeaders = "host";
2156 $sXAMZCredential = urlencode( $fv_fp->_get_option( array('amazon_key', $amazon_key ) ).'/'.$sCredentialScope);
2157
2158 // 1. http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
2159 $sCanonicalRequest = "GET\n";
2160 $sCanonicalRequest .= $url_components['path']."\n";
2161 $sCanonicalRequest .= "X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=$sXAMZCredential&X-Amz-Date=$sXAMZDate&X-Amz-Expires=$time&X-Amz-SignedHeaders=$sSignedHeaders\n";
2162 $sCanonicalRequest .= "host:".$url_components['host']."\n";
2163 $sCanonicalRequest .= "\n$sSignedHeaders\n";
2164 $sCanonicalRequest .= "UNSIGNED-PAYLOAD";
2165
2166 // 2. http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
2167 $sStringToSign = "AWS4-HMAC-SHA256\n";
2168 $sStringToSign .= "$sXAMZDate\n";
2169 $sStringToSign .= "$sCredentialScope\n";
2170 $sStringToSign .= hash('sha256',$sCanonicalRequest);
2171
2172 // 3. http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
2173 $sSignature = hash_hmac('sha256', $sDate, "AWS4".$fv_fp->_get_option( array('amazon_secret', $amazon_key) ), true );
2174 $sSignature = hash_hmac('sha256', $fv_fp->_get_option( array('amazon_region', $amazon_key) ), $sSignature, true ); // todo: variable
2175 $sSignature = hash_hmac('sha256', 's3', $sSignature, true );
2176 $sSignature = hash_hmac('sha256', 'aws4_request', $sSignature, true );
2177 $sSignature = hash_hmac('sha256', $sStringToSign, $sSignature );
2178
2179 // 4. http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html
2180 $resource .= "?X-Amz-Algorithm=AWS4-HMAC-SHA256";
2181 $resource .= "&X-Amz-Credential=$sXAMZCredential";
2182 $resource .= "&X-Amz-Date=$sXAMZDate";
2183 $resource .= "&X-Amz-Expires=$time";
2184 $resource .= "&X-Amz-SignedHeaders=$sSignedHeaders";
2185 $resource .= "&X-Amz-Signature=".$sSignature;
2186
2187 } else {
2188 $expires = time() + $time;
2189
2190 if( strpos( $url_components['path'], $fv_fp->_get_option( array('amazon_bucket', $amazon_key) ) ) === false ) {
2191 $url_components['path'] = '/'.$fv_fp->_get_option( array('amazon_bucket', $amazon_key) ).$url_components['path'];
2192 }
2193
2194 do {
2195 $expires++;
2196 $stringToSign = "GET\n\n\n$expires\n{$url_components['path']}";
2197
2198 $signature = utf8_encode($stringToSign);
2199
2200 $signature = hash_hmac('sha1', $signature, $fv_fp->_get_option( array('amazon_secret', $amazon_key ) ), true);
2201 $signature = base64_encode($signature);
2202
2203 $signature = urlencode($signature);
2204 } while( stripos($signature,'%2B') !== false );
2205
2206 $resource .= '?AWSAccessKeyId='.$fv_fp->_get_option( array('amazon_key', $amazon_key) ).'&Expires='.$expires.'&Signature='.$signature;
2207
2208 }
2209
2210 $media = $resource;
2211
2212 }
2213
2214 return $media;
2215 }
2216
2217 function get_amazon_secure_long( $media ) {
2218 add_filter( 'fv_flowplayer_amazon_expires', '__return_false' );
2219
2220 $signed_media = $this->get_amazon_secure( $media, WEEK_IN_SECONDS );
2221
2222 remove_filter( 'fv_flowplayer_amazon_expires', '__return_false' );
2223
2224 return $signed_media;
2225 }
2226
2227 public static function hms_to_seconds( $tDuration ) {
2228 if ( preg_match('/([\d]{1,2}\:)?[\d]{1,2}\:[\d]{2}/', $tDuration) ) {
2229 $tDuration = preg_replace("/^([\d]{1,2})\:([\d]{2})$/", "00:$1:$2", $tDuration);
2230 sscanf($tDuration, "%d:%d:%d", $hours, $minutes, $seconds);
2231 $tDuration = $hours * 3600 + $minutes * 60 + $seconds;
2232 }
2233 return $tDuration;
2234 }
2235
2236 public static function format_hms( $seconds ) {
2237 if( !is_numeric($seconds) ) return $seconds;
2238
2239 $seconds = round( $seconds );
2240
2241 if( $seconds < 3600 ) {
2242 return gmdate( "i:s", $seconds );
2243 } else {
2244 return gmdate( "H:i:s", $seconds );
2245 }
2246 }
2247
2248
2249 public static function get_duration( $post_id, $video_src, $seconds = false ) {
2250 if( $sVideoMeta = get_post_meta( $post_id, flowplayer::get_video_key($video_src), true ) ) { // todo: should probably work regardles of quality version
2251 if( isset($sVideoMeta['duration']) && $sVideoMeta['duration'] > 0 ) {
2252 if( $seconds ) {
2253 return $sVideoMeta['duration'];
2254 }
2255
2256 return flowplayer::format_hms($sVideoMeta['duration']);
2257 }
2258 }
2259 return false;
2260 }
2261
2262
2263 /*
2264 * Get duration of the longets video in the post
2265 */
2266 public static function get_duration_post( $post_id = false ) {
2267 global $post, $fv_fp;
2268 $post_id = ( $post_id ) ? $post_id : $post->ID;
2269
2270 if( $fv_fp->_get_option('player_model_db_checked') && $fv_fp->_get_option('player_meta_model_db_checked') && $fv_fp->_get_option('video_model_db_checked') && $fv_fp->_get_option('video_meta_model_db_checked') ) {
2271 global $wpdb;
2272 $tDuration = intval( $wpdb->get_var( "SELECT v.duration FROM {$wpdb->prefix}fv_player_playermeta AS pm JOIN {$wpdb->prefix}fv_player_players AS p ON p.id = pm.id_player JOIN {$wpdb->prefix}fv_player_videos AS v ON FIND_IN_SET(v.id, p.videos) > 0 WHERE pm.meta_key = 'post_id' AND pm.meta_value = ".intval($post_id)." ORDER BY v.duration DESC LIMIT 1" ) );
2273
2274 if( $tDuration > 3600 ) {
2275 return gmdate( "H:i:s", $tDuration );
2276 } else if( $tDuration > 0 ) {
2277 return gmdate( "i:s", $tDuration );
2278 }
2279 }
2280
2281 $content = false;
2282 $objPost = get_post($post_id);
2283 if( $aVideos = FV_Player_Checker::get_videos($objPost->ID) ) {
2284 foreach( $aVideos AS $video ) {
2285 $tDuration = flowplayer::get_duration($post_id, $video, true );
2286 if( !$content || $tDuration > $content ) {
2287 $content = $tDuration;
2288 }
2289 }
2290 }
2291
2292 if( $content ) {
2293 $content = flowplayer::format_hms($content);
2294 }
2295
2296 return $content;
2297 }
2298
2299
2300 public static function get_duration_playlist( $caption ) {
2301 if( !$caption ) return $caption;
2302
2303 global $post;
2304 $aArgs = func_get_args();
2305
2306 if( $post && isset($aArgs[1][0]) && is_array($aArgs[1][0]) ) {
2307 $sItemKeys = array_keys($aArgs[1][0]);
2308 if( $sDuration = flowplayer::get_duration( $post->ID, $aArgs[1][0][$sItemKeys[0]] ) ) {
2309 $caption .= '<i class="dur">'.$sDuration.'</i>';
2310 }
2311 }
2312
2313 return $caption;
2314 }
2315
2316
2317 public static function get_duration_video( $content ) {
2318 global $post;
2319 if( !$post ) return $content;
2320
2321 $aArgs = func_get_args();
2322 if( $sDuration = flowplayer::get_duration( $post->ID, $aArgs[1]->aCurArgs['src']) ) {
2323 $content .= '<div class="fvfp_duration">'.$sDuration.'</div>';
2324 }
2325
2326 return $content;
2327 }
2328
2329
2330 public static function get_encoded_url( $sURL ) {
2331
2332 $parsed_url = wp_parse_url( $sURL );
2333 $url_parts_encoded = wp_parse_url( $sURL );
2334
2335 if( !empty($parsed_url['path']) ) {
2336 $parsed_url['path'] = join('/', array_map( 'rawurlencode', array_map('urldecode', explode('/', $url_parts_encoded['path']) ) ) );
2337 $parsed_url['path'] = str_replace( '%2B', '+', $parsed_url['path'] );
2338 }
2339
2340 if( !empty($parsed_url['query']) ) {
2341 $parsed_url['query'] = str_replace( '&amp;', '&', $url_parts_encoded['query'] );
2342 }
2343
2344 // https://www.php.net/manual/en/function.parse-url.php#106731
2345 $scheme = isset( $parsed_url['scheme'] ) ? $parsed_url['scheme'] . '://' : '';
2346 $host = isset( $parsed_url['host'] ) ? $parsed_url['host'] : '';
2347 $port = isset( $parsed_url['port'] ) ? ':' . $parsed_url['port'] : '';
2348 $user = isset( $parsed_url['user'] ) ? $parsed_url['user'] : '';
2349 $pass = isset( $parsed_url['pass'] ) ? ':' . $parsed_url['pass'] : '';
2350 $pass = ( $user || $pass ) ? "$pass@" : '';
2351 $path = isset( $parsed_url['path'] ) ? $parsed_url['path'] : '';
2352 $query = isset( $parsed_url['query'] ) ? '?' . $parsed_url['query'] : '';
2353 $fragment = isset( $parsed_url['fragment'] ) ? '#' . $parsed_url['fragment'] : '';
2354
2355 return "$scheme$user$pass$host$port$path$query$fragment";
2356 }
2357
2358
2359 public static function get_languages() {
2360 // List taken from https://www.localeplanet.com/icu/
2361 $aLangs = array(
2362 'SDH' => 'SDH',
2363 'AA' => 'Afaraf',
2364 'AB' => 'аҧсшәа',
2365 'AF' => 'Afrikaans',
2366 'AGQ' => 'Aghem',
2367 'AK' => 'Akan',
2368 'AM' => 'አማርኛ',
2369 'AR' => 'العربية',
2370 'AS' => '�
2371 সমীয়া',
2372 'ASA' => 'Kipare',
2373 'AST' => 'asturianu',
2374 'AY' => 'aymar aru',
2375 'AZ' => 'azərbaycan',
2376 'BA' => 'башҡорт теле',
2377 'BAS' => 'Ɓàsàa',
2378 'BE' => 'беларуская',
2379 'BEM' => 'Ichibemba',
2380 'BEZ' => 'Hibena',
2381 'BH' => 'भोजपुरी',
2382 'BI' => 'Bislama',
2383 'BG' => 'български',
2384 'BM' => 'bamanakan',
2385 'BN' => 'বাংলা',
2386 'BO' => 'བོད་སྐད་',
2387 'BR' => 'brezhoneg',
2388 'BRX' => 'बड़ो',
2389 'BS' => 'bosanski',
2390 'CA' => 'català',
2391 'CE' => 'но�
2392 чийн',
2393 'CGG' => 'Rukiga',
2394 'CHR' => 'ᏣᎳᎩ',
2395 'CO' => 'Corsu',
2396 'CKB' => 'کوردیی ناوەندی',
2397 'CS' => 'Čeština',
2398 'CY' => 'Cymraeg',
2399 'DA' => 'dansk',
2400 'DAV' => 'Kitaita',
2401 'DE' => 'Deutsch',
2402 'DJE' => 'Zarmaciine',
2403 'DSB' => 'dolnoserbšćina',
2404 'DUA' => 'duálá',
2405 'DYO' => 'joola',
2406 'DZ' => 'རྫོང་ཁ',
2407 'EBU' => 'Kĩembu',
2408 'EE' => 'Eʋegbe',
2409 'EL' => 'Ελληνικά',
2410 'EN' => 'English',
2411 'EO' => 'esperanto',
2412 'ES' => 'español',
2413 'ET' => 'eesti',
2414 'EU' => 'euskara',
2415 'EWO' => 'ewondo',
2416 'FA' => 'فارسی',
2417 'FF' => 'Pulaar',
2418 'FI' => 'suomi',
2419 'FJ' => 'vosa Vakaviti',
2420 'FIL' => 'Filipino',
2421 'FO' => 'føroyskt',
2422 'FR' => 'français',
2423 'FUR' => 'furlan',
2424 'FY' => 'Frysk',
2425 'GA' => 'Gaeilge',
2426 'GD' => 'Gàidhlig',
2427 'GL' => 'galego',
2428 'GN' => 'Avañe\'',
2429 'GSW' => 'Schwiizertüütsch',
2430 'GU' => 'ગુજરાતી',
2431 'GUZ' => 'Ekegusii',
2432 'GV' => 'Gaelg',
2433 'HA' => 'Hausa',
2434 'HAW' => 'ʻŌlelo Hawaiʻi',
2435 'HE' => 'עברית',
2436 'HI' => 'हिन्दी',
2437 'HR' => 'hrvatski',
2438 'HSB' => 'hornjoserbšćina',
2439 'HU' => 'magyar',
2440 'HY' => 'հայերեն',
2441 'IA' => 'Interlingua',
2442 'IE' => 'Interlingue',
2443 'ID' => 'Indonesia',
2444 'IG' => 'Igbo',
2445 'IK' => 'Iñupiatun',
2446 'II' => 'ꆈꌠꉙ',
2447 'IS' => 'íslenska',
2448 'IT' => 'italiano',
2449 'JA' => '日本語',
2450 'JI' => 'אידיש',
2451 'JV' => 'basa Jawa',
2452 'JGO' => 'Ndaꞌa',
2453 'JMC' => 'Kimachame',
2454 'KA' => 'ქართული',
2455 'KAB' => 'Taqbaylit',
2456 'KAM' => 'Kikamba',
2457 'KDE' => 'Chimakonde',
2458 'KEA' => 'kabuverdianu',
2459 'KHQ' => 'Koyra ciini',
2460 'KI' => 'Gikuyu',
2461 'KK' => 'қазақ тілі',
2462 'KKJ' => 'kakɔ',
2463 'KL' => 'kalaallisut',
2464 'KLN' => 'Kalenjin',
2465 'KM' => 'ខ្មែរ',
2466 'KN' => 'ಕನ್ನಡ',
2467 'KO' => '한국어',
2468 'KOK' => 'कोंकणी',
2469 'KS' => 'کٲشُر',
2470 'KSB' => 'Kishambaa',
2471 'KSF' => 'rikpa',
2472 'KSH' => 'Kölsch',
2473 'KW' => 'kernewek',
2474 'KU' => 'كوردی‎',
2475 'KY' => 'кыргызча',
2476 'LA' => 'Latine',
2477 'LAG' => 'Kɨlaangi',
2478 'LB' => 'Lëtzebuergesch',
2479 'LG' => 'Luganda',
2480 'LKT' => 'Lakȟólʼiyapi',
2481 'LN' => 'lingála',
2482 'LO' => 'ລາວ',
2483 'LRC' => 'لۊری شو�
2484 الی',
2485 'LT' => 'lietuvių',
2486 'LU' => 'Tshiluba',
2487 'LUO' => 'Dholuo',
2488 'LUY' => 'Luluhia',
2489 'LV' => 'latviešu',
2490 'MAS' => 'Maa',
2491 'MER' => 'Kĩmĩrũ',
2492 'MFE' => 'kreol morisien',
2493 'MG' => 'Malagasy',
2494 'MGH' => 'Makua',
2495 'MGO' => 'metaʼ',
2496 'MI' => 'te reo Māori',
2497 'MK' => 'македонски',
2498 'ML' => 'മലയാളം',
2499 'MN' => 'монгол',
2500 'MR' => 'मराठी',
2501 'MS' => 'Melayu',
2502 'MT' => 'Malti',
2503 'MUA' => 'MUNDAŊ',
2504 'MY' => 'မြန်မာ',
2505 'MZN' => '�
2506 ازرونی',
2507 'NA' => 'Ekakairũ Naoero',
2508 'NO' => 'Norsk',
2509 'NAQ' => 'Khoekhoegowab',
2510 'NB' => 'norsk bokmål',
2511 'ND' => 'isiNdebele',
2512 'NDS' => 'nds',
2513 'NE' => 'नेपाली',
2514 'NL' => 'Nederlands',
2515 'NMG' => 'nmg',
2516 'NN' => 'nynorsk',
2517 'NNH' => 'Shwóŋò ngiembɔɔn',
2518 'NUS' => 'Thok Nath',
2519 'NYN' => 'Runyankore',
2520 'OC' => 'occitan, lenga d\'òc',
2521 'OM' => 'Oromoo',
2522 'OR' => 'ଓଡ଼ିଆ',
2523 'OS' => 'ирон',
2524 'PA' => 'ਪੰਜਾਬੀ',
2525 'PL' => 'polski',
2526 'PS' => 'پښتو',
2527 'PT' => 'português',
2528 'QU' => 'Runasimi',
2529 'RM' => 'rumantsch',
2530 'RN' => 'Ikirundi',
2531 'RO' => 'română',
2532 'ROF' => 'Kihorombo',
2533 'RU' => 'русский',
2534 'RW' => 'Kinyarwanda',
2535 'RWK' => 'Kiruwa',
2536 'SA' => 'संस्कृतम्',
2537 'SD' => 'सिन्धी, سنڌي، سندھی‎',
2538 'ST' => 'Sesotho',
2539 'SAH' => 'са�
2540 а тыла',
2541 'SAQ' => 'Kisampur',
2542 'SBP' => 'Ishisangu',
2543 'SM' => 'gagana fa\'a Samoa',
2544 'SE' => 'davvisámegiella',
2545 'SEH' => 'sena',
2546 'SES' => 'Koyraboro senni',
2547 'SG' => 'Sängö',
2548 'SHI' => 'ⵜⴰⵛⵍⵃⵉⵜ',
2549 'SI' => 'සිංහල',
2550 'SK' => 'slovenčina',
2551 'SL' => 'slovenščina',
2552 'SMN' => 'anarâškielâ',
2553 'SN' => 'chiShona',
2554 'SS' => 'SiSwati',
2555 'SO' => 'Soomaali',
2556 'SQ' => 'shqip',
2557 'SR' => 'српски',
2558 'SV' => 'svenska',
2559 'SU' => 'Basa Sunda',
2560 'SW' => 'Kiswahili',
2561 'TA' => 'தமிழ்',
2562 'TE' => 'తెలుగు',
2563 'TEO' => 'Kiteso',
2564 'TL' => 'Wikang Tagalog',
2565 'TS' => 'Xitsonga',
2566 'TK' => 'Türkmen, Түркмен',
2567 'TG' => 'тоҷикӣ',
2568 'TH' => 'ไทย',
2569 'TI' => 'ትግርኛ',
2570 'TN' => 'Setswana',
2571 'TO' => 'lea fakatonga',
2572 'TR' => 'Türkçe',
2573 'TT' => 'татар',
2574 'TW' => 'Twi',
2575 'TWQ' => 'Tasawaq senni',
2576 'TZM' => 'Tamaziɣt n laṭlaṣ',
2577 'UG' => 'ئۇيغۇرچە',
2578 'UK' => 'українська',
2579 'UR' => 'اردو',
2580 'UZ' => 'o‘zbek',
2581 'VAI' => 'ꕙꔤ',
2582 'VI' => 'Tiếng Việt',
2583 'VO' => 'Volapük',
2584 'VUN' => 'Kyivunjo',
2585 'WAE' => 'Walser',
2586 'WO' => 'Wolof',
2587 'XOG' => 'Olusoga',
2588 'XH' => 'isiXhosa',
2589 'YAV' => 'nuasue',
2590 'YI' => 'ייִדיש',
2591 'YO' => 'Èdè Yorùbá',
2592 'YUE' => '粵語',
2593 'ZGH' => 'ⵜⴰⵎⴰⵣⵉⵖⵜ',
2594 'ZH' => '中文',
2595 'ZH_HANS' => '中文(简体)',
2596 'ZU' => 'isiZulu'
2597 );
2598
2599 // Uppercase first letter
2600 foreach( $aLangs as $code => $native ) {
2601 if( function_exists('mb_convert_case') ) {
2602 $aLangs[$code] = mb_convert_case($native, MB_CASE_TITLE, "UTF-8");
2603 } else {
2604 $aLangs[$code] = $native;
2605 }
2606 }
2607
2608 ksort($aLangs);
2609
2610 return $aLangs;
2611 }
2612
2613
2614 function get_mime_type($media, $default = 'mp4', $no_video = false) {
2615 $media = trim($media);
2616 $aURL = explode( '?', $media ); // throwing away query argument here
2617 $pathinfo = pathinfo( $aURL[0] );
2618 if( empty($pathinfo['extension']) ) $pathinfo = pathinfo( $media ); // but if no extension remains, keep the query arguments, todo: unit test for https://drive.google.com/uc?export=download&id=0B32098YdDwTAcmJxVl9Kc1piT2s#.mp4
2619
2620 $extension = ( isset($pathinfo['extension']) ) ? $pathinfo['extension'] : false;
2621 $extension = preg_replace( '~[?#].+$~', '', $extension );
2622 $extension = strtolower($extension);
2623
2624 if( !$extension ) {
2625 $output = $default;
2626 } else {
2627 if ($extension == 'm3u8' || $extension == 'm3u') {
2628 $output = 'x-mpegurl';
2629 } else if ($extension == 'mpd') {
2630 $output = 'dash+xml';
2631 } else if ($extension == 'm4v') {
2632 $output = 'mp4';
2633 } else if( $extension == 'mp3' ) {
2634 $output = 'mpeg';
2635 } else if( $extension == 'wav' ) {
2636 $output = 'wav';
2637 } else if( $extension == 'ogg' ) {
2638 $output = 'ogg';
2639 } else if( $extension == 'ogv' ) {
2640 $output = 'ogg';
2641 } else if( $extension == 'mov' ) {
2642 $output = 'mp4';
2643 } else if( $extension == '3gp' ) {
2644 $output = 'mp4';
2645 } else if( $extension == 'mkv' ) {
2646 $output = 'mp4';
2647 } else if( $extension == 'mp3' ) {
2648 $output = 'mpeg';
2649 } else if( !in_array($extension, array('mp4', 'm4v', 'webm', 'ogv', 'ogg', 'wav', '3gp')) ) {
2650 $output = $default;
2651 } else {
2652 $output = $extension;
2653 }
2654 }
2655
2656 if( $output == 'flash' ) {
2657 if( stripos( $media, '(format=m3u8' ) !== false ) { // http://*.streaming.mediaservices.windows.net/*.ism/manifest(format=m3u8-aapl)
2658 $output = 'x-mpegurl';
2659 $extension = 'm3u8';
2660 }
2661 if( stripos( $media, '(format=mpd' ) !== false ) { // http://*.streaming.mediaservices.windows.net/*.ism/manifest(format=mpd-time-csf)
2662 $output = 'dash+xml';
2663 $extension = 'mpd';
2664 }
2665 }
2666
2667 global $fv_fp;
2668 if( $extension == 'mpd' ) {
2669 $fv_fp->load_dash = true;
2670 } else if( $extension == 'm3u8' ) {
2671 $fv_fp->load_hlsjs = true;
2672 }
2673
2674 if( !$no_video ) {
2675 switch($extension) {
2676 case 'dash+xml' :
2677 case 'mpd' :
2678 $output = 'application/'.$output;
2679 break;
2680 case 'x-mpegurl' :
2681 $output = 'application/'.$output;
2682 break;
2683 case 'm3u8' :
2684 $output = 'application/'.$output;
2685 break;
2686 case 'flac' :
2687 case 'mp3' :
2688 case 'ogg' :
2689 case 'wav' :
2690 $output = 'audio/'.$output;
2691 break;
2692 default:
2693 $output = 'video/'.$output;
2694 break;
2695 }
2696 }
2697
2698 $output = apply_filters( 'fv_flowplayer_get_mime_type', $output, $media );
2699
2700 // The custom HTML5 engine to support Ajax loading of video source URL is now part of core, no need to init it in any special way
2701 if ( 'video/fv-mp4' === $output ) {
2702 $output = 'video/mp4';
2703 }
2704
2705 return $output;
2706 }
2707
2708
2709 public static function get_plugin_url() {
2710 if( stripos( __FILE__, '/themes/' ) !== false || stripos( __FILE__, '\\themes\\' ) !== false ) {
2711 return get_template_directory_uri().'/fv-player';
2712 } else {
2713 $plugin_folder = basename(dirname(dirname(__FILE__))); // make fv-wordpress-flowplayer out of {anything}/fv-wordpress-flowplayer/models/flowplayer.php
2714 return plugins_url($plugin_folder);
2715 }
2716 }
2717
2718
2719 public function get_playlist_class($aCaptions) {
2720 $sClass = 'fv-playlist-design-';
2721 if( !empty($this->aCurArgs['listdesign']) ) {
2722 $sClass .= $this->aCurArgs['listdesign'];
2723 } else {
2724 $sClass .= $this->_get_option('playlist-design');
2725 }
2726
2727 // Playlist design doesn't have any use for these two playlist styles:
2728 if( !empty($this->aCurArgs['liststyle']) && in_array($this->aCurArgs['liststyle'], array( 'season', 'polaroid', 'version-one', 'version-two' ) ) ) {
2729 $sClass = '';
2730 }
2731
2732 if( isset($this->aCurArgs['liststyle']) ) {
2733 $list_style = $this->aCurArgs['liststyle'];
2734 if( $list_style == 'slider' ) {
2735 $sClass .= ' fp-playlist-horizontal';
2736 } else if( $list_style == 'text' ) {
2737 $sClass = 'fp-playlist-vertical';
2738 } else {
2739 $sClass .= ' fp-playlist-'.$list_style;
2740 }
2741
2742 if( $list_style == 'text' ) {
2743 $sClass .= ' fp-playlist-only-captions';
2744 } else if( sizeof($aCaptions) > 0 && strlen(implode("",$aCaptions)) > 0 ) {
2745 $sClass .= ' fp-playlist-has-captions';
2746 }
2747 }
2748
2749 if ( get_query_var('fv_player_embed') || get_query_var('fv_player_cms_id') ) {
2750 $sClass .= ' fp-is-embed';
2751 }
2752
2753 if( !empty($this->aCurArgs['skin']) ) {
2754 $sClass .= ' skin-'.$this->aCurArgs['skin'];
2755 } else {
2756 $sClass .= ' skin-'.$this->_get_option('skin');
2757 }
2758
2759 return $sClass;
2760 }
2761
2762
2763 public static function get_core_version() {
2764 global $fv_wp_flowplayer_core_ver;
2765 return $fv_wp_flowplayer_core_ver;
2766 }
2767
2768
2769 function get_server_url() {
2770 $url = is_ssl() ? 'https://' : 'http://';
2771
2772 $url .= sanitize_text_field( $_SERVER['SERVER_NAME'] );
2773
2774 $url = sanitize_url( $url );
2775
2776 if ( ! empty( $_SERVER['SERVER_PORT'] ) && intval( $_SERVER['SERVER_PORT'] ) != 80 && intval( $_SERVER['SERVER_PORT'] ) != 443 ) {
2777 $url .= ':' . intval( $_SERVER['SERVER_PORT'] );
2778 }
2779
2780 $url .= '/';
2781
2782 return $url;
2783 }
2784
2785
2786 public static function get_video_key( $sURL ) {
2787 $sURL = str_replace( '?v=', '-v=', $sURL );
2788 $sURL = preg_replace( '~\?.*$~', '', $sURL );
2789 $sURL = str_replace( array('/','://'), array('-','-'), $sURL );
2790 return '_fv_flowplayer_'.sanitize_title($sURL);
2791 }
2792
2793
2794 public static function get_title_from_src( $src ) {
2795 $name = wp_parse_url( $src, PHP_URL_PATH );
2796 $arr = explode('/', $name);
2797 $name = trim( end($arr) );
2798
2799 if( in_array( $name, array( 'index.m3u8', 'stream.m3u8', 'master.m3u8', 'playlist.m3u8' ) ) ) {
2800 unset($arr[count($arr)-1]);
2801 $name = end($arr);
2802
2803 // Add parent folder too if there's any
2804 if( !empty( $arr ) && count( $arr ) > 2 ) {
2805 unset($arr[count($arr)-1]);
2806 $name = end($arr) . '/' . $name;
2807 }
2808 }
2809
2810 return $name;
2811 }
2812
2813
2814 function get_video_src($media, $aArgs = array() ) {
2815 $aArgs = wp_parse_args( $aArgs, array(
2816 'dynamic' => false, // apply URL signature for CDNs which normally use Ajax
2817 'suppress_filters' => false,
2818 )
2819 );
2820
2821 if( $media ) {
2822 if( !$aArgs['suppress_filters'] ) {
2823 $media = apply_filters( 'fv_flowplayer_video_src', $media, $aArgs );
2824 }
2825 return wp_strip_all_tags(trim($media));
2826 }
2827 return null;
2828 }
2829
2830
2831 function get_video_url($media) {
2832 if( !is_string($media) ) return $media;
2833
2834 if( strpos($media,'rtmp://') !== false ) {
2835 return null;
2836 }
2837 if( strpos($media,'http://') !== 0 && strpos($media,'https://') !== 0 && strpos($media,'//') !== 0 ) {
2838 if ( $media[0] === '/' ) {
2839 $media = substr($media, 1);
2840 }
2841
2842 $media = $this->get_server_url() . $media;
2843 }
2844
2845 $media = apply_filters( 'fv_flowplayer_media', $media, $this );
2846 return $media;
2847 }
2848
2849
2850 public static function is_licensed() {
2851 global $fv_fp;
2852 return preg_match( '!^\$\d+!', $fv_fp->_get_option('key') );
2853 }
2854
2855
2856 public static function is_special_editor() {
2857 return flowplayer::is_optimizepress() || flowplayer::is_themify();
2858 }
2859
2860
2861 public static function is_optimizepress() {
2862 if( ( isset($_GET['page']) && sanitize_key( $_GET['page'] ) == 'optimizepress-page-builder' ) ||
2863 ( isset($_POST['action']) && sanitize_key( $_POST['action'] ) == 'optimizepress-live-editor-parse' )
2864 ) {
2865 return true;
2866 }
2867 return false;
2868 }
2869
2870
2871 public static function is_themify() {
2872 if( isset($_POST['action']) && sanitize_key( $_POST['action'] ) == 'tfb_load_module_partial' ) {
2873 return true;
2874 }
2875 return false;
2876 }
2877
2878
2879 public static function is_wp_rocket_setting( $setting ) {
2880 return function_exists( 'get_rocket_option') && get_rocket_option( $setting );
2881 }
2882
2883
2884 public function is_secure_amazon_s3( $url ) {
2885 return preg_match( '/^.+?s3.*?\.amazonaws\.com\/.+Signature=.+?$/', $url ) || preg_match( '/^.+?\.cloudfront\.net\/.+Signature=.+?$/', $url );
2886 }
2887
2888
2889 public static function json_encode( $input ) {
2890 if( version_compare(phpversion(), '5.3.0', '>') ) {
2891 return wp_json_encode( $input, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP );
2892 } else {
2893 return str_replace( "'", '\u0027', wp_json_encode( $input ) );
2894 }
2895 }
2896
2897
2898 function popup_css( $css ){
2899 $aPopupData = get_option('fv_player_popups');
2900 $sNewCss = '';
2901 if( is_array($aPopupData) ) {
2902 foreach($aPopupData as $key => $val){
2903 if( empty($val['css']) ){
2904 continue;
2905 }
2906 $sNewCss .= '.flowplayer '.stripslashes($val['css'])."\n";
2907 }
2908 }
2909 if( strlen($sNewCss) ){
2910 $css .= "\n/*custom popup css*/\n".$sNewCss."\n/*end custom popup css*/\n";
2911 }
2912 return $css;
2913 }
2914
2915 function custom_css( $css ) {
2916 global $fv_fp;
2917 $aCustomCSS = $fv_fp->_get_option('customCSS');
2918
2919 if( strlen($aCustomCSS) ) {
2920 $css .= "\n/*custom css*/\n".wp_strip_all_tags( stripslashes($aCustomCSS) )."\n/*end custom css*/\n";
2921 }
2922 return $css;
2923 }
2924
2925 /*
2926 * This function changes the /fvp/{number} rewrite endpoint created with fv_player_embed_rewrite_endpoint()
2927 * to accept /fvp{number} or fvp-{number} and also adds rule fo /fvp only (no number)
2928 *
2929 * Example:
2930 * [(.?.+?)/fvp(/(.*))?/?$] => index.php?pagename=$matches[1]&fv_player_embed=$matches[3]
2931 *
2932 * is changed to
2933 *
2934 * [(.?.+?)/fvp((-?.*))?/?$] => index.php?pagename=$matches[1]&fv_player_embed=$matches[3]
2935 *
2936 * and new rule for /fvp without number is added, example:
2937 * [(.?.+?)/fvp/?$] => index.php?pagename=$matches[1]&fv_player_embed=1
2938 */
2939 function fv_player_embed_rewrite_rules_fix( $aRules ) {
2940 $aRulesNew = array();
2941 foreach( $aRules AS $k => $v ) {
2942 if( stripos($k,'/fvp(/') !== false ) {
2943 // 1st rule
2944 $new_k = str_replace( 'fvp(/(.*))?', 'fvp', $k ); // fvp only
2945 $new_v = preg_replace('/fv_player_embed=\$matches\[\d]/', 'fv_player_embed=1', $v); // fv_player_embed=1
2946
2947 $aRulesNew[$new_k] = $new_v;
2948
2949 // 2nd rule
2950 $new_k = str_replace( '/fvp(/(.*))', '/fvp((-?\d+))', $k ); // fvp{number} or fvp-{number}
2951
2952 $aRulesNew[$new_k]= $v;
2953 } else {
2954 $aRulesNew[$k] = $v;
2955 }
2956 }
2957
2958 return $aRulesNew;
2959 }
2960
2961 function fv_player_embed_rewrite_endpoint() {
2962 add_rewrite_endpoint( 'fvp', EP_PERMALINK | EP_PAGES, 'fv_player_embed' );
2963 }
2964
2965 function rewrite_vars( $public_query_vars ) {
2966 $public_query_vars[] = 'fv_player_embed';
2967 return $public_query_vars;
2968 }
2969
2970 function template_embed_buffer(){
2971 if( get_query_var('fv_player_embed') ) {
2972 ob_start();
2973
2974 global $fvseo;
2975 if( isset( $_REQUEST['fv_player_preview_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['fv_player_preview_nonce'] ) ), 'fv_player_preview' ) && isset($_REQUEST['fv_player_preview']) ) {
2976 global $fvseo;
2977 if( isset($fvseo) ) remove_action('wp_footer', array($fvseo, 'script_footer_content'), 999999 );
2978
2979 global $objTracker;
2980 if( isset($objTracker) ) remove_action( 'wp_footer', array( $objTracker, 'OutputFooter' ) );
2981 }
2982 }
2983 }
2984
2985 function template_embed() {
2986 // Generate embed html
2987 if( $embed_id = get_query_var('fv_player_embed') ) {
2988 $content = ob_get_contents();
2989 ob_clean();
2990
2991 if( function_exists('rocket_insert_load_css') ) rocket_insert_load_css();
2992
2993 remove_action( 'wp_footer', array( $this, 'template_embed' ),0 );
2994 //remove_action('wp_head', '_admin_bar_bump_cb');
2995 show_admin_bar(false);
2996 ?>
2997 <style>
2998 body { margin: 0; padding: 0; overflow:hidden; background:white;}
2999 body:before { height: 0px!important;}
3000 html {margin-top: 0px !important; overflow:hidden; }
3001 </style>
3002 </head>
3003 <body class="fv-player-preview">
3004 <?php
3005 if( stripos($content,'<!--fv player end-->') !== false ) {
3006
3007 $bFound = false;
3008 $rewrite = get_option('rewrite_rules');
3009 if( empty($rewrite) ) {
3010 $sLink = 'fv_player_embed='.$embed_id;
3011 } else {
3012 $sPostfix = $embed_id == 1 ? 'fvp' : 'fvp'.$embed_id;
3013 $sLink = user_trailingslashit( trailingslashit( get_permalink() ).$sPostfix );
3014 }
3015
3016 $aPlayers = explode( '<!--fv player end-->', $content );
3017 if( $aPlayers ) {
3018 foreach( $aPlayers AS $k => $v ) {
3019 if( stripos($v,$sLink.'"') !== false ) {
3020 echo substr($v, stripos($v,'<div id="wpfp_') );
3021 $bFound = true;
3022 break;
3023 }
3024 }
3025 }
3026
3027 if( !$bFound && is_numeric($embed_id) && !empty($aPlayers[$embed_id-1]) ) {
3028 echo substr($aPlayers[$embed_id-1], stripos($aPlayers[$embed_id-1],'<div id="wpfp_') );
3029 $bFound = true;
3030 }
3031
3032 if( !$bFound ) {
3033 echo "<p>Player not found, see the full article: <a href='".get_permalink()."' target='_blank'>".get_the_title()."</a>.</p>";
3034 }
3035
3036 }
3037
3038 wp_footer();
3039
3040 ?>
3041 </body>
3042 </html>
3043 <?php
3044 exit();
3045 }
3046 }
3047
3048 function preview_no_lazy_load( $value ) {
3049 if( isset( $_REQUEST['fv_player_preview_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['fv_player_preview_nonce'] ) ), 'fv_player_preview' ) && isset($_REQUEST['fv_player_preview']) ) {
3050 return false;
3051 }
3052 return $value;
3053 }
3054
3055 function process_preferred_video_type( $sources ) {
3056
3057 // Match video URL extensions and put these first
3058 if ( ! empty( $this->aCurArgs['prefer'] ) ) {
3059 $extension = '.' . sanitize_key( $this->aCurArgs['prefer'] );
3060
3061 $new_sources = array();
3062
3063 foreach( $sources as $source_k => $source ) {
3064 if ( stripos( $source['src'], $extension ) !== false ) {
3065 $new_sources[] = $source;
3066 unset( $sources[ $source_k ] );
3067 }
3068 }
3069
3070 $sources = array_merge( $new_sources, $sources );
3071 }
3072
3073 return $sources;
3074 }
3075
3076 function searchwp_pre_post_content( $post ) {
3077 $post->post_content = preg_replace( '~(\[fvplayer(.*?)\])~', '<!--FV Player Search WP Start-->[fvplayer embed="false" $1]<!--FV Player Search WP End-->', $post->post_content );
3078 return $post;
3079 }
3080
3081 function searchwp_post_content( $post ) {
3082 $post->post_content = preg_replace_callback( '~<!--FV Player Search WP Start-->[\s\S]*?<!--FV Player Search WP End-->~', array( $this, 'searchwp_post_content_callback' ), $post->post_content );
3083 return $post;
3084 }
3085
3086 function searchwp_post_content_callback( $match ) {
3087 $html = $match[0];
3088
3089 $html = preg_replace( '~<noscript.*?</noscript>~', '', $html );
3090 $html = preg_replace( '~<script.*?</script>~', '', $html );
3091 $html = preg_replace( '~<svg.*?</svg>~', '', $html );
3092
3093 $allowed_html = array(
3094 // Allowing the 'data-item' attribute for 'a' tags
3095 'a' => array(
3096 'data-item' => true,
3097 ),
3098 // Allow 'data-item' for 'div' tags
3099 'div' => array(
3100 'data-item' => true,
3101 ),
3102 // ... Add other tags as needed
3103 );
3104
3105 $html = wp_kses( $html, $allowed_html );
3106
3107 return $html;
3108 }
3109
3110 // Also used by FV Player extensions
3111 function should_force_load_js() {
3112 return $this->_get_option('js-everywhere') || isset($_GET['brizy-edit-iframe']) || isset($_GET['elementor-preview']) || did_action('fv_player_force_load_assets');
3113 }
3114
3115 function template_preview() {
3116 if( !empty($_GET['fv_player_preview']) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['fv_player_preview_nonce'] ) ), 'fv_player_preview' ) ) {
3117 // Generate preview html
3118 show_admin_bar(false);
3119 ?>
3120 <html>
3121 <head>
3122 <?php wp_head(); ?>
3123 <style>
3124 body { margin: 0; padding: 0; overflow:hidden; background:white;}
3125 body:before { height: 0px!important;}
3126 html {margin-top: 0px !important; overflow:hidden; }
3127 </style>
3128 </head>
3129 <body class="fv-player-preview">
3130 <?php
3131
3132 if( isset( $_REQUEST['fv_player_preview_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['fv_player_preview_nonce'] ) ), 'fv_player_preview' ) && isset($_REQUEST['fv_player_preview']) ) :
3133 $shortcode = base64_decode( sanitize_text_field( $_REQUEST['fv_player_preview'] ) );
3134 $shortcode = apply_filters( 'fv_player_preview_data', $shortcode );
3135
3136 $matches = null;
3137 $width ='';
3138 $height ='';
3139
3140 // width from regular shortcdode data
3141 if ( preg_match('/width="([0-9.,]*)"/', $shortcode, $matches)) {
3142 $width = 'width:'.$matches[1].'px;';
3143 }
3144
3145 // width from DB shortcdode data
3146 if ( !empty($shortcode['fv_wp_flowplayer_field_width'])) {
3147 $width = 'width:'.$shortcode['fv_wp_flowplayer_field_width'].'px;';
3148 }
3149
3150 // height from regular shortcdode data
3151 if( preg_match('/height="([0-9.,]*)"/', $shortcode, $matches)) {
3152 $height = 'min-height:'.$matches[1].'px;';
3153 }
3154
3155 // height from DB shortcdode data
3156 if ( !empty($shortcode['fv_wp_flowplayer_field_height'])) {
3157 $height = 'min-height:'.$shortcode['fv_wp_flowplayer_field_height'].'px;';
3158 }
3159
3160 ?>
3161 <div style="background:white;">
3162 <div id="wrapper" style="background:white; overflow:hidden; <?php echo esc_html( $width . $height ); ?>;">
3163 <?php
3164 // regular shortcode data with source
3165 global $fv_fp;
3166 if ( preg_match('/id="\d+"|src="[^"][^"]*"/i',$shortcode)) {
3167 $aAtts = shortcode_parse_atts($shortcode);
3168 if ( $aAtts && !empty($aAtts['liststyle'] ) && $aAtts['liststyle'] == 'vertical' || $fv_fp->_get_option('liststyle') == 'vertical' ) {
3169 esc_html_e('The preview is too narrow, vertical playlist will shift below the player as it would on mobile.', 'fv-player');
3170 }
3171 echo do_shortcode($shortcode);
3172 } else { ?>
3173 <h1 style="margin: auto;text-align: center; padding: 60px; color: darkgray;">No video.</h1>
3174 <?php
3175 }
3176 ?>
3177 </div>
3178 </div>
3179
3180 <?php
3181
3182 endif;
3183
3184 ?>
3185 <?php
3186 wp_footer();
3187 if( isset($_GET['fv_player_preview']) && !empty($_GET['fv_player_preview']) ) :
3188 ?>
3189 <script>
3190 jQuery(document).ready( function(){
3191 var parent = window.parent.jQuery(window.parent.document);
3192 if( typeof(flowplayer) != "undefined" ) {
3193 parent.trigger('fvp-preview-complete', [jQuery(document).width(),jQuery(document).height()]);
3194
3195 } else {
3196 parent.trigger('fvp-preview-error');
3197 }
3198
3199 });
3200
3201 if (window.top===window.self) {
3202 jQuery('#wrapper').css('margin','25px 50px 0 50px');
3203 }
3204 </script>
3205 <?php endif; ?>
3206 </body>
3207 </html>
3208 <?php
3209
3210 exit;
3211 }
3212 }
3213
3214 function wp_kses_permit_scripts( $tags, $context = false ) {
3215 if( $context != 'post' ) return $tags;
3216
3217 if ( empty($tags['ins']) ) {
3218 $tags['ins'] = array();
3219 }
3220
3221 $tags['ins']['class'] = true;
3222 $tags['ins']['data-zoneid'] = true;
3223
3224 if ( empty($tags['script']) ) {
3225 $tags['script'] = array();
3226 }
3227
3228 $tags['script']['src'] = true;
3229 $tags['script']['type'] = true;
3230 $tags['script']['async'] = true;
3231
3232 return $tags;
3233 }
3234
3235 function wp_kses_permit_settings( $tags, $context = false ) {
3236 if( $context != 'post' ) return $tags;
3237
3238 if ( empty($tags['form']) ) {
3239 $tags['form'] = array();
3240 }
3241
3242 $tags['form']['action'] = true;
3243 $tags['form']['class'] = true;
3244 $tags['form']['id'] = true;
3245 $tags['form']['method'] = true;
3246
3247 if ( empty($tags['iframe']) ) {
3248 $tags['iframe'] = array();
3249 }
3250
3251 $tags['iframe']['class'] = true;
3252 $tags['iframe']['frameborder'] = true;
3253 $tags['iframe']['data-*'] = true;
3254 $tags['iframe']['height'] = true;
3255 $tags['iframe']['id'] = true;
3256 $tags['iframe']['src'] = true;
3257 $tags['iframe']['style'] = true;
3258 $tags['iframe']['width'] = true;
3259
3260 if ( empty($tags['input']) ) {
3261 $tags['input'] = array();
3262 }
3263
3264 $tags['input']['class'] = true;
3265 $tags['input']['id'] = true;
3266 $tags['input']['name'] = true;
3267 $tags['input']['onclick'] = true;
3268 $tags['input']['placeholder'] = true;
3269 $tags['input']['type'] = true;
3270 $tags['input']['value'] = true;
3271
3272 return $tags;
3273 }
3274 }
3275
3276 function fv_wp_flowplayer_save_post( $post_id ) {
3277 if( $parent_id = wp_is_post_revision($post_id) ) {
3278 $post_id = $parent_id;
3279 }
3280
3281 global $post;
3282 $post_id = ( isset($post->ID) ) ? $post->ID : $post_id;
3283
3284 global $fv_fp, $post, $FV_Player_Checker;
3285 if( !$FV_Player_Checker->is_cron && $FV_Player_Checker->queue_check($post_id) ) {
3286 //return;
3287 }
3288
3289 $saved_post = get_post($post_id);
3290 if ( ! $saved_post ) {
3291 return;
3292 }
3293
3294 $videos = FV_Player_Checker::get_videos($saved_post->ID);
3295
3296 $iDone = 0;
3297 if( is_array($videos) && count($videos) > 0 ) {
3298 $tStart = microtime(true);
3299 foreach( $videos AS $video ) {
3300 if( microtime(true) - $tStart > apply_filters( 'fv_flowplayer_checker_save_post_time', 5 ) ) {
3301 FV_Player_Checker::queue_add($post_id);
3302 break;
3303 }
3304
3305 if( isset($post->ID) && !get_post_meta( $post->ID, flowplayer::get_video_key($video), true ) ) {
3306
3307 if ( $FV_Player_Checker->check_mimetype( array( $video ), array( 'meta_action' => 'check_time' ) ) ) {
3308 $iDone++;
3309
3310 } else {
3311 FV_Player_Checker::queue_add($post_id);
3312 }
3313
3314 } else {
3315 $iDone++;
3316 }
3317
3318 }
3319 }
3320
3321 if( !$videos || $iDone == count($videos) ) {
3322 FV_Player_Checker::queue_remove($post_id);
3323 }
3324 }
3325