PluginProbe
FV Player 8 / trunk
FV Player 8 vtrunk
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 trunk, at models/fv-player.php

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