PluginProbe
FV Player 8 / 8.1
FV Player 8 v8.1
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 / controller / frontend.php

frontend.php in FV Player 8 8.1, at controller/frontend.php

1,349 lines 51.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /* FV Player - HTML5 video player
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 3 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 add_action('wp_footer','flowplayer_prepare_scripts',9);
24 add_action('wp_footer','flowplayer_display_scripts',100);
25 add_action('widget_text','do_shortcode');
26
27 add_filter( 'run_ngg_resource_manager', '__return_false' );
28
29
30 function fv_flowplayer_remove_bad_scripts() {
31 global $wp_scripts;
32 if( isset($wp_scripts->registered['flowplayer']) && isset($wp_scripts->registered['flowplayer']->src) && stripos($wp_scripts->registered['flowplayer']->src, 'fv-player') === false ) {
33 wp_deregister_script( 'flowplayer' );
34 }
35 }
36 add_action( 'wp_print_scripts', 'fv_flowplayer_remove_bad_scripts', 100 );
37
38 add_filter( 'run_ngg_resource_manager', '__return_false' ); // Nextgen Gallery compatibility fix
39
40 function fv_flowplayer_ap_action_init(){
41 // Localization
42 load_plugin_textdomain('fv-player', false, dirname(dirname(plugin_basename(__FILE__))) . "/languages");
43 }
44 add_action('init', 'fv_flowplayer_ap_action_init');
45
46 function fv_flowplayer_get_js_translations() {
47
48 $aStrings = array(
49 0 => '',
50 1 => __('Video loading aborted', 'fv-player' ),
51 2 => __('Network error', 'fv-player' ),
52 3 => __('Video not properly encoded', 'fv-player' ),
53 4 => __('Video file not found', 'fv-player' ),
54 5 => __('Unsupported video', 'fv-player' ),
55 6 => __('Skin not found', 'fv-player' ),
56 7 => __('SWF file not found', 'fv-player' ),
57 8 => __('Subtitles not found', 'fv-player' ),
58 10 => __('Unsupported video format.', 'fv-player' ),
59 11 => __('Click to watch the video', 'fv-player' ),
60 12 => __('[This post contains video, click to play]', 'fv-player' ),
61 'video_expired' => __('<h2>Video file expired.<br />Please reload the page and play it again.</h2>', 'fv-player' ),
62 'unsupported_format' => __('<h2>Unsupported video format.<br />Please use a Flash compatible device.</h2>', 'fv-player' ),
63 'mobile_browser_detected_1' => __('Mobile browser detected, serving low bandwidth video.', 'fv-player' ),
64 'mobile_browser_detected_2' => __('Click here for full quality', 'fv-player' ),
65 'live_stream_failed' => __('<h2>Live stream load failed.</h2><h3>Please try again later, perhaps the stream is currently offline.</h3>', 'fv-player' ),
66 'live_stream_failed_2' => __('<h2>Live stream load failed.</h2><h3>Please try again later, perhaps the stream is currently offline.</h3>', 'fv-player' ),
67 'what_is_wrong' => __('Please tell us what is wrong :', 'fv-player' ),
68 'full_sentence' => __('Please give us more information (a full sentence) so we can help you better', 'fv-player' ),
69 'error_JSON' =>__('Admin: Error parsing JSON', 'fv-player' ),
70 'no_support_IE9' =>__('Admin: Video checker doesn\'t support IE 9.', 'fv-player' ),
71 'check_failed' =>__('Admin: Check failed.', 'fv-player' ),
72 'playlist_current' =>__('Now Playing', 'fv-player' ),
73 'playlist_item_no' =>__('Item %d.', 'fv-player' ),
74 'playlist_play_all' =>__('Play All', 'fv-player' ),
75 'playlist_play_all_button' =>__('All', 'fv-player' ),
76 'playlist_replay_all' =>__('Replay Playlist', 'fv-player' ),
77 'playlist_replay_video' =>__('Repeat Track', 'fv-player' ),
78 'playlist_shuffle' =>__('Shuffle Playlist', 'fv-player' ),
79 'video_issues' =>__('Video Issues', 'fv-player' ),
80 'video_reload' =>__('Video loading has stalled, click to reload', 'fv-player' ),
81 'link_copied' =>__('Video Link Copied to Clipboard', 'fv-player' ),
82 'live_stream_starting'=>__('<h2>Live stream scheduled</h2><p>Starting in <span>%d</span>.</p>', 'fv-player' ),
83 'live_stream_retry'=>__( '<h2>We are sorry, currently no live stream available.</h2><p>Retrying in <span>%d</span> ...</p>', 'fv-player' ),
84 'live_stream_continue'=>__( '<h2>It appears the stream went down.</h2><p>Retrying in <span>%d</span> ...</p>', 'fv-player' ),
85 'embed_copied' =>__('Embed Code Copied to Clipboard', 'fv-player' ),
86 'error_copy_clipboard' => __('Error copying text into clipboard!', 'fv-player' ),
87 'subtitles_disabled' =>__('Subtitles disabled', 'fv-player' ),
88 'subtitles_switched' =>__('Subtitles switched to ', 'fv-player' ),
89 'warning_iphone_subs' => __('This video has subtitles, that are not supported on your device.', 'fv-player' ),
90 'warning_unstable_android' => __('You are using an old Android device. If you experience issues with the video please use <a href="https://play.google.com/store/apps/details?id=org.mozilla.firefox">Firefox</a>.', 'fv-player' ),
91 'warning_samsungbrowser' => __('You are using the Samsung Browser which is an older and buggy version of Google Chrome. If you experience issues with the video please use <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> or other modern browser.', 'fv-player' ),
92 'warning_old_safari' => __('You are using an old Safari browser. If you experience issues with the video please use <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> or other modern browser.', 'fv-player' ),
93 'warning_old_chrome' => __('You are using an old Chrome browser. Please make sure you use the latest version.', 'fv-player' ),
94 'warning_old_firefox' => __('You are using an old Firefox browser. Please make sure you use the latest version.', 'fv-player' ),
95 'warning_old_ie' => __('You are using a deprecated browser. If you experience issues with the video please use <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> or other modern browser.', 'fv-player' ),
96 'quality' => __('Quality', 'fv-player' ),
97 'closed_captions' => __('Closed Captions', 'fv-player' ),
98 'no_subtitles' => __('No subtitles', 'fv-player' ),
99 'speed' => __('Speed', 'fv-player' ),
100 'duration_1_day' => __( "%s day" ),
101 'duration_n_days' => _n( '%s day', '%s days', 5 ),
102 'duration_1_hour' => __( "%s hour" ),
103 'duration_n_hours' => _n( '%s hour', '%s hours', 5 ),
104 'duration_1_minute' => __( "%s min" ),
105 'duration_n_minutes' => _n( '%s min', '%s mins', 5 ),
106 'duration_1_second' => __( "%s second" ),
107 'duration_n_seconds' => _n( '%s second', '%s seconds', 5 ),
108 'and' => sprintf( __( '%1$s and %2$s' ), '', '' ),
109 'chrome_extension_disable_html5_autoplay' => __('It appears you are using the Disable HTML5 Autoplay Chrome extension, disable it to play videos', 'fv-player' ),
110 'audio_button' => __('AUD', 'fv-player' ),
111 'audio_menu' => __('Audio', 'fv-player' ),
112 'iphone_swipe_up_location_bar' => __('To enjoy fullscreen swipe up to hide location bar.', 'fv-player' ),
113 'invalid_youtube' => __('Invalid Youtube video ID.', 'fv-player'),
114 'redirection' => __( "Admin note:\n\nThis player is set to redirect to a URL at the end of the video:\n\n%url%\n\nWould you like to be redirected?\n\nThis note only shows to logged in Administrators and Editors for security reasons, other users are redirected without any popup or confirmation.", 'fv-player' ),
115 'video_loaded' => __('Video loaded, click to play.', 'fv-player'),
116 'msg_no_skipping' => __('Skipping is not allowed.', 'fv-player' ),
117 'msg_watch_video' => __('Please watch the video carefully.', 'fv-player' ),
118 );
119
120 return $aStrings;
121 }
122
123 /**
124 * Replaces the flowplayer tags in post content by players and fills the $GLOBALS['fv_fp_scripts'] array.
125 *
126 * @param string Content to be parsed
127 * @return string Modified content string
128 */
129 function flowplayer_content( $content ) {
130 global $fv_fp;
131
132 $content_matches = array();
133 preg_match_all('/\[(flowplayer|fvplayer)\ [^\]]+\]/i', $content, $content_matches);
134
135 // process all found tags
136 foreach ($content_matches[0] as $tag) {
137 $ntag = str_replace("\'",'&#039;',$tag);
138 //search for URL
139 preg_match("/src='([^']*?)'/i",$ntag,$tmp);
140 if( $tmp[1] == NULL ) {
141 preg_match_all("/src=([^,\s\]]*)/i",$ntag,$tmp);
142 $media = $tmp[1][0];
143 }
144 else
145 $media = $tmp[1];
146
147 //strip the additional /videos/ from the beginning if present
148 preg_match('/(.*)\/videos\/(.*)/',$media,$matches);
149 if ($matches[0] == NULL)
150 $media = $media;
151 else if ($matches[1] == NULL) {
152 $media = $matches[2];
153 }
154 else {
155 $media = $matches[2];
156 }
157
158 unset($arguments['src']);
159 unset($arguments['src1']);
160 unset($arguments['src2']);
161 unset($arguments['width']);
162 unset($arguments['height']);
163 unset($arguments['autoplay']);
164 unset($arguments['splash']);
165 unset($arguments['splashend']);
166 unset($arguments['popup']);
167 unset($arguments['controlbar']);
168 unset($arguments['redirect']);
169 unset($arguments['loop']);
170
171 //width and heigth
172 preg_match("/width=(\d*)/i",$ntag,$width);
173 preg_match("/height=(\d*)/i",$ntag,$height);
174 if( $width[1] != NULL)
175 $arguments['width'] = $width[1];
176 if( $height[1] != NULL)
177 $arguments['height'] = $height[1];
178
179 //search for redirect
180 preg_match("/redirect='([^']*?)'/i",$ntag,$tmp);
181 if ($tmp[1])
182 $arguments['redirect'] = $tmp[1];
183
184 //search for autoplay
185 preg_match("/[\s]+autoplay([\s]|])+/i",$ntag,$tmp);
186 if (isset($tmp[0])){
187 $arguments['autoplay'] = true;
188 }
189 else {
190 preg_match("/autoplay='([A-Za-z]*)'/i",$ntag,$tmp);
191 if ( $tmp[1] == NULL )
192 preg_match("/autoplay=([A-Za-z]*)/i",$ntag,$tmp);
193 if (isset($tmp[1]))
194 $arguments['autoplay'] = $tmp[1];
195 }
196
197 //search for popup in quotes
198 preg_match("/popup='([^']*?)'/i",$ntag,$tmp);
199 if ($tmp[1])
200 $arguments['popup'] = $tmp[1];
201
202 //search for loop
203 preg_match("/[\s]+loop([\s]|])+/i",$ntag,$tmp);
204 if (isset($tmp[0])){
205 $arguments['loop'] = true;
206 }
207 else {
208 preg_match("/loop='([A-Za-z]*)'/i",$ntag,$tmp);
209 if ( $tmp[1] == NULL )
210 preg_match("/loop=([A-Za-z]*)/i",$ntag,$tmp);
211 if (isset($tmp[1]))
212 $arguments['loop'] = $tmp[1];
213 }
214
215 // search for splash image
216 preg_match("/splash='([^']*?)'/i",$ntag,$tmp); //quotes version
217 if( $tmp[1] == NULL ) {
218 preg_match_all("/splash=([^,\s\]]*)/i",$ntag,$tmp); //non quotes version
219 preg_match('/(.*)\/videos\/(.*)/i',$tmp[1][0],$matches);
220 if ($matches[0] == NULL)
221 $arguments['splash'] = $tmp[1][0];
222 else if ($matches[1] == NULL) {
223 $arguments['splash'] = $matches[2];//$tmp[1][0];
224 }
225 else {
226 $arguments['splash'] = $matches[2];
227 }
228 }
229 else {
230 preg_match('/(.*)\/videos\/(.*)/',$tmp[1],$matches);
231 if ($matches[0] == NULL)
232 $arguments['splash'] = $tmp[1];
233 elseif ($matches[1] == NULL)
234 $arguments['splash'] = $matches[2];
235 else
236 $arguments['splash'] = $matches[2];//$tmp[1];
237 }
238
239 // search for src1
240 preg_match("/src1='([^']*?)'/i",$ntag,$tmp); //quotes version
241 if( $tmp[1] == NULL ) {
242 preg_match_all("/src1=([^,\s\]]*)/i",$ntag,$tmp); //non quotes version
243 preg_match('/(.*)\/videos\/(.*)/i',$tmp[1][0],$matches);
244 if ($matches[0] == NULL)
245 $arguments['src1'] = $tmp[1][0];
246 else if ($matches[1] == NULL) {
247 $arguments['src1'] = $matches[2];//$tmp[1][0];
248 }
249 else {
250 $arguments['src1'] = $matches[2];
251 }
252 }
253 else {
254 preg_match('/(.*)\/videos\/(.*)/',$tmp[1],$matches);
255 if ($matches[0] == NULL)
256 $arguments['src1'] = $tmp[1];
257 elseif ($matches[1] == NULL)
258 $arguments['src1'] = $matches[2];
259 else
260 $arguments['src1'] = $matches[2];//$tmp[1];
261 }
262
263 // search for src1
264 preg_match("/src2='([^']*?)'/i",$ntag,$tmp); //quotes version
265 if( $tmp[1] == NULL ) {
266 preg_match_all("/src2=([^,\s\]]*)/i",$ntag,$tmp); //non quotes version
267 preg_match('/(.*)\/videos\/(.*)/i',$tmp[1][0],$matches);
268 if ($matches[0] == NULL)
269 $arguments['src2'] = $tmp[1][0];
270 else if ($matches[1] == NULL) {
271 $arguments['src2'] = $matches[2];//$tmp[1][0];
272 }
273 else {
274 $arguments['src2'] = $matches[2];
275 }
276 }
277 else {
278 preg_match('/(.*)\/videos\/(.*)/',$tmp[1],$matches);
279 if ($matches[0] == NULL)
280 $arguments['src2'] = $tmp[1];
281 elseif ($matches[1] == NULL)
282 $arguments['src2'] = $matches[2];
283 else
284 $arguments['src2'] = $matches[2];//$tmp[1];
285 }
286
287 //search for splashend
288 preg_match("/[\s]+splashend([\s]|])+/i",$ntag,$tmp);
289 if (isset($tmp[0])){
290 $arguments['splashend'] = true;
291 }
292 else {
293 preg_match("/splashend='([A-Za-z]*)'/i",$ntag,$tmp);
294 if ( $tmp[1] == NULL )
295 preg_match("/splashend=([A-Za-z]*)/i",$ntag,$tmp);
296 if (isset($tmp[1]))
297 $arguments['splashend'] = $tmp[1];
298 }
299
300 //search for controlbar
301 preg_match("/[\s]+controlbar([\s]|])+/i",$ntag,$tmp);
302 if (isset($tmp[0])){
303 $arguments['controlbar'] = true;
304 }
305 else {
306 preg_match("/controlbar='([A-Za-z]*)'/i",$ntag,$tmp);
307 if ( $tmp[1] == NULL )
308 preg_match("/controlbar=([A-Za-z]*)/i",$ntag,$tmp);
309 if (isset($tmp[1]))
310 $arguments['controlbar'] = $tmp[1];
311 }
312
313 if (trim($media) != '') {
314 // build new player
315 $new_player = $fv_fp->build_min_player($media,$arguments);
316 $content = str_replace($tag, $new_player['html'],$content);
317 if (!empty($new_player['script'])) {
318 $GLOBALS['fv_fp_scripts'] = $new_player['script'];
319 }
320 }
321 }
322 return $content;
323 }
324
325 function flowplayer_prepare_scripts() {
326 global $fv_fp, $fv_wp_flowplayer_ver, $fv_wp_flowplayer_core_ver;
327
328 // don't load script in Optimize Press 2 preview
329 if( flowplayer::is_special_editor() ) {
330 return;
331 }
332
333 if(
334 isset($GLOBALS['fv_fp_scripts']) ||
335 $fv_fp->should_force_load_js() ||
336 isset( $_GET['fv_wp_flowplayer_check_template'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['fv_wp_flowplayer_check_template'] ) ), 'fv_wp_flowplayer_check_template' )
337 ){
338
339 $aDependencies = array('jquery');
340 if( $fv_fp->should_force_load_js() || $fv_fp->load_tabs ) {
341 wp_enqueue_script('jquery-ui-tabs', false, array('jquery','jquery-ui-core'), $fv_wp_flowplayer_ver, true);
342 $aDependencies[] = 'jquery-ui-tabs';
343 }
344
345 if( !$fv_fp->bCSSLoaded ) $fv_fp->css_enqueue(true);
346
347 $sLogo = $fv_fp->_get_option('logo') ? $fv_fp->_get_option('logo') : '';
348
349 // Load base Freedom Video Player library
350 $path = '/freedom-video-player/freedomplayer.min.js';
351 if( file_exists(dirname(__FILE__).'/../freedom-video-player/freedomplayer.js') ) {
352 $path = '/freedom-video-player/freedomplayer.js';
353 }
354
355 $version = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? filemtime( dirname(__FILE__).'/../'.$path ) : $fv_wp_flowplayer_core_ver;
356
357 wp_enqueue_script( 'flowplayer', flowplayer::get_plugin_url().$path, $aDependencies, $version, true );
358 $aDependencies[] = 'flowplayer';
359
360 // Load modules
361 if( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) {
362 $path = '/freedom-video-player/modules/fv-player.js';
363 wp_enqueue_script( 'fv-player', flowplayer::get_plugin_url().$path, $aDependencies, filemtime( dirname(__FILE__).'/../'.$path ), true );
364 $aDependencies[] = 'fv-player';
365
366 foreach( glob( dirname(dirname(__FILE__)).'/freedom-video-player/modules/*.module.js') as $filename ) {
367 $path = '/freedom-video-player/modules/'.basename($filename);
368 wp_enqueue_script( 'fv-player-'.basename($filename), flowplayer::get_plugin_url().$path, $aDependencies, filemtime( dirname(__FILE__).'/../'.$path ), true);
369 }
370
371 } else {
372 wp_enqueue_script( 'fv-player', flowplayer::get_plugin_url().'/freedom-video-player/fv-player.min.js', $aDependencies, $fv_wp_flowplayer_ver, true );
373
374 }
375
376 if( current_user_can('manage_options') && !$fv_fp->_get_option('disable_videochecker') && ( $fv_fp->_get_option('video_checker_agreement') || $fv_fp->_get_option('key_automatic') ) ) {
377 wp_enqueue_script( 'fv-player-video-checker', flowplayer::get_plugin_url().'/js/video-checker.js', array('flowplayer'), $fv_wp_flowplayer_ver, true );
378 $aConf['video_checker'] = true;
379 }
380
381 if( $fv_fp->_get_option('ui_speed_increment') == 0.25){
382 $aConf['speeds'] = array( 0.25,0.5,0.75,1,1.25,1.5,1.75,2 );
383 }elseif( $fv_fp->_get_option('ui_speed_increment') == 0.1){
384 $aConf['speeds'] = array( 0.25,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2 );
385 }elseif( $fv_fp->_get_option('ui_speed_increment') == 0.5){
386 $aConf['speeds'] = array( 0.5,1,1.5,2 );
387 }
388
389 $aConf['video_hash_links'] = empty($fv_fp->aCurArgs['linking']) ? $fv_fp->_get_option( 'ui_video_links' ) : $fv_fp->aCurArgs['linking'] === 'true';
390
391 if( apply_filters( 'fv_flowplayer_safety_resize', true) ) {
392 $aConf['safety_resize'] = true;
393 }
394 if( $fv_fp->_get_option('cbox_compatibility') ) {
395 $aConf['cbox_compatibility'] = true;
396 }
397 if( current_user_can('manage_options') && !$fv_fp->_get_option('disable_videochecker') ) {
398 $aConf['video_checker_site'] = home_url();
399 }
400
401 if( $sLogo ) $aConf['logo'] = $sLogo;
402 if ( $fv_fp->_get_option( 'logo_over_video' ) ) $aConf['logo_over_video'] = true;
403
404 // Used to restore volume, removed in JS if volume stored in browser localStorage
405 $aConf['volume'] = floatval( $fv_fp->_get_option('volume') );
406 if( $aConf['volume'] > 1 ) {
407 $aConf['volume'] = 1;
408 }
409
410 $aConf['default_volume'] = $aConf['volume'];
411
412 if( $val = $fv_fp->_get_option('mobile_native_fullscreen') ) $aConf['mobile_native_fullscreen'] = $val;
413 if( $val = $fv_fp->_get_option('mobile_force_fullscreen') ) $aConf['mobile_force_fullscreen'] = $val;
414 if( $val = $fv_fp->_get_option('mobile_alternative_fullscreen') ) $aConf['mobile_alternative_fullscreen'] = $val;
415 $aConf['mobile_landscape_fullscreen'] = true;
416
417 if ( $fv_fp->_get_option('video_position_save_enable') ) {
418 $aConf['video_position_save_enable'] = $fv_fp->_get_option('video_position_save_enable');
419 }
420
421 if( is_user_logged_in() ) $aConf['is_logged_in'] = true;
422
423 if ( current_user_can( 'edit_posts' ) ) {
424 $aConf['is_logged_in_editor'] = true;
425 }
426
427 $aConf['sticky_video'] = $fv_fp->_get_option('sticky_video');
428 $aConf['sticky_place'] = $fv_fp->_get_option('sticky_place');
429 $aConf['sticky_min_width'] = intval( apply_filters( 'fv_player_sticky_desktop_min_width', 1020 ) );
430
431 global $post;
432 if( $post && isset($post->ID) && $post->ID > 0 ) {
433 if( get_post_meta($post->ID, 'fv_player_mobile_native_fullscreen', true) ) $aConf['mobile_native_fullscreen'] = true;
434 if( get_post_meta($post->ID, 'fv_player_mobile_force_fullscreen', true) ) $aConf['mobile_force_fullscreen'] = true;
435 }
436
437 if( $fv_fp->should_force_load_js() || $fv_fp->load_hlsjs ) {
438 wp_enqueue_script( 'flowplayer-hlsjs', flowplayer::get_plugin_url().'/freedom-video-player/hls.min.js', array('flowplayer'), '1.6.9', true );
439 }
440 $aConf['script_hls_js'] = flowplayer::get_plugin_url().'/freedom-video-player/hls.min.js?ver=1.6.9';
441
442 $dashjs_version = '3.2.2-mod';
443
444 $fv_player_dashjs = 'fv-player-dashjs.min.js';
445 if( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) $fv_player_dashjs = 'fv-player-dashjs.dev.js';
446
447 if( $fv_fp->should_force_load_js() || $fv_fp->load_dash ) {
448 wp_enqueue_script( 'dashjs', flowplayer::get_plugin_url().'/freedom-video-player/dash.mediaplayer.min.js', array('flowplayer'), $dashjs_version, true );
449 wp_enqueue_script( 'fv-player-dash', flowplayer::get_plugin_url().'/freedom-video-player/'.$fv_player_dashjs, array('dashjs'), $fv_wp_flowplayer_ver, true );
450 }
451
452 // Used by FV Player Pro in case Dash.js was not loaded for the page
453 $aConf['script_dash_js'] = flowplayer::get_plugin_url().'/freedom-video-player/dash.mediaplayer.min.js?ver='.$dashjs_version;
454 $aConf['script_dash_js_engine'] = flowplayer::get_plugin_url().'/freedom-video-player/'.$fv_player_dashjs.'?ver='.$fv_wp_flowplayer_ver;
455
456 if( $fv_fp->should_force_load_js() || FV_Player_YouTube()->bYoutube || did_action('fv_player_extensions_admin_load_assets') ) {
457 $youtube_js = 'fv-player-youtube.min.js';
458 $youtube_ver = $fv_wp_flowplayer_ver;
459
460 if( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) {
461 $youtube_js = 'fv-player-youtube.dev.js';
462 $youtube_ver = filemtime( dirname(__FILE__).'/../freedom-video-player/'.$youtube_js );
463 }
464
465 wp_enqueue_script( 'fv-player-youtube', flowplayer::get_plugin_url().'/freedom-video-player/' . $youtube_js , array('flowplayer'), $youtube_ver, true );
466 }
467
468 if( $fv_fp->_get_option('googleanalytics') ) {
469 $aConf['fvanalytics'] = $fv_fp->_get_option('googleanalytics');
470 }
471
472 if( $fv_fp->_get_option('matomo_domain') && $fv_fp->_get_option('matomo_site_id') ) {
473 // take the domain name from Matomo Domain setting in case somebody entered full URL
474 $matomo_domain = $fv_fp->_get_option('matomo_domain');
475 $parsed = wp_parse_url($matomo_domain);
476 if( $parsed && !empty($parsed['host']) ) {
477 $matomo_domain = $parsed['host'];
478 if( !empty($parsed['path']) ) {
479 $matomo_domain .= '/'.$parsed['path'];
480 }
481 }
482 $aConf['matomo_domain'] = $matomo_domain;
483 $aConf['matomo_site_id'] = $fv_fp->_get_option('matomo_site_id');
484 }
485
486 if( $fv_fp->_get_option('ui_airplay') ) {
487 $aConf['airplay'] = true;
488 }
489
490 if ( $fv_fp->_get_option('debug_log') ) {
491 $aConf['debug_log'] = true;
492 }
493
494 $aConf['chromecast'] = false; // tell core Freedom Video Player and FV Player Pro <= 7.4.43.727 to not load Chromecast
495 if( $fv_fp->_get_option('chromecast') ) {
496 $aConf['chromecast'] = array(
497 'applicationId' => '908E271B'
498 );
499 }
500
501 if( $fv_fp->_get_option('hd_streaming') ) {
502 $aConf['hd_streaming'] = true;
503 }
504
505 if( $fv_fp->_get_option('multiple_playback') ) {
506 $aConf['multiple_playback'] = true;
507 }
508
509 if( $fv_fp->_get_option('disable_localstorage') ) {
510 $aConf['disable_localstorage'] = true;
511 }
512
513 if( $fv_fp->_get_option('autoplay_preload') && $fv_fp->_get_option('autoplay_preload') != 'false' ) {
514 $aConf['autoplay_preload'] = $fv_fp->_get_option('autoplay_preload');
515 }
516
517 if( $fv_fp->_get_option('youtube_browser_chrome') ) {
518 $aConf['youtube_browser_chrome'] = $fv_fp->_get_option('youtube_browser_chrome');
519 }
520
521 $aConf['hlsjs'] = array(
522 'startLevel' => -1,
523 'fragLoadingMaxRetry' => 3,
524 'levelLoadingMaxRetry' => 3,
525 'capLevelToPlayerSize' => true,
526 'use_for_safari' => class_exists( 'FV_Player_DRM' ),
527 );
528
529 // The above HLS.js config doesn't work well on Chrome and Firefox, so we detect that in JS and use this config for it instead. Todo: make this a per-video thing
530 if( class_exists('FV_Player_Pro_DaCast') ) {
531 $aConf['dacast_hlsjs'] = array(
532 'autoLevelEnabled' => false // disable ABR. If you set startLevel or capLevelToPlayerSize it will be enabled again. So this way everybody on desktop gets top quality and they have to switch to lower each time.
533 );
534 }
535
536 if( is_admin() ) $aConf['wpadmin'] = true;
537
538 // Is it the wp-admin -> FV Player -> Settings screen?
539 if ( did_action( 'admin_head-fv-player_page_fvplayer' ) ) {
540 $aConf['skin_preview'] = true;
541 }
542
543 $aConf['msg'] = array(
544 'click_to_unmute' => __('Click to unmute', 'fv-player' ),
545 );
546
547 $aConf = apply_filters( 'fv_flowplayer_conf', $aConf );
548
549 $aLocalize = array(
550 'ajaxurl' => site_url() . '/wp-admin/admin-ajax.php',
551 'nonce' => wp_create_nonce( 'fv_player_frontend' ),
552 'email_signup_nonce' => wp_create_nonce( 'fv_player_email_signup' ),
553 'video_position_save_nonce' => wp_create_nonce( 'fv_player_video_position_save' ),
554 );
555
556 if ( is_user_logged_in() ) {
557 $aLocalize['is_user_logged_in'] = true;
558 $aLocalize['audio_name'] = get_user_meta( get_current_user_id(), 'fv_player_audio_name', true );
559 $aLocalize['audio_lang'] = get_user_meta( get_current_user_id(), 'fv_player_audio_lang', true );
560 }
561
562 wp_localize_script( 'flowplayer', 'fv_flowplayer_conf', $aConf );
563 if( current_user_can('manage_options') ) {
564 $aLocalize['admin_input'] = true;
565 $aLocalize['admin_js_test'] = true;
566 }
567
568 if( current_user_can('edit_posts') ) {
569 $aLocalize['user_edit'] = true;
570 }
571
572 wp_localize_script( 'flowplayer', 'fv_player', $aLocalize );
573
574 wp_localize_script( 'flowplayer', 'fv_flowplayer_translations', fv_flowplayer_get_js_translations());
575 wp_localize_script( 'flowplayer', 'fv_flowplayer_playlists', array() ); // has to be defined for FV Player Pro 0.6.20 and such
576
577 if( isset($GLOBALS['fv_fp_scripts']) && count($GLOBALS['fv_fp_scripts']) > 0 ) {
578 foreach( $GLOBALS['fv_fp_scripts'] AS $sKey => $aScripts ) {
579 wp_localize_script( 'flowplayer', $sKey.'_array', $aScripts );
580 }
581 }
582
583 }
584
585 FV_Player_lightbox()->maybe_load();
586 }
587
588 /**
589 * Prints flowplayer javascript content to the bottom of the page.
590 */
591 function flowplayer_display_scripts() {
592 if( flowplayer::is_special_editor() ) {
593 return;
594 }
595
596 if( is_user_logged_in() || isset($_GET['fv_wp_flowplayer_check_template']) ) {
597 echo "\n<!--fv-flowplayer-footer-->\n\n";
598 }
599 }
600
601 /**
602 * This is the template tag. Use the standard Flowplayer shortcodes
603 */
604 function flowplayer($shortcode) {
605 echo apply_filters('the_content',$shortcode);
606 }
607
608
609 /*
610 Make sure our div won't be wrapped in any P tag and that html attributes don't break the shortcode
611 */
612 function fv_flowplayer_the_content( $c ) {
613 if( flowplayer::is_special_editor() ) {
614 return $c;
615 }
616
617 $c = preg_replace( '!<p[^>]*?>(\[(?:fvplayer|flowplayer).*?[^\\\]\])</p>!', "\n".'$1'."\n", $c );
618 $c = preg_replace_callback( '!\[(?:fvplayer|flowplayer).*?[^\\\]\]!', 'fv_flowplayer_shortfcode_fix_attrs', $c );
619 return $c;
620 }
621 add_filter( 'the_content', 'fv_flowplayer_the_content', 0 );
622
623
624 function fv_flowplayer_shortfcode_fix_attrs( $aMatch ) {
625 $aMatch[0] = preg_replace_callback( '!(?:ad|popup)="(.*?[^\\\])"!', 'fv_flowplayer_shortfcode_fix_attr', $aMatch[0] );
626 return $aMatch[0];
627 }
628
629
630 function fv_flowplayer_shortfcode_fix_attr( $aMatch ) {
631 $aMatch[0] = str_replace( $aMatch[1], '<!--fv_flowplayer_base64_encoded-->'.base64_encode($aMatch[1]), $aMatch[0] );
632 return $aMatch[0];
633 }
634
635
636 /*
637 Handle attachment pages which contain videos
638 */
639 function fv_flowplayer_attachment_page_video( $c ) {
640 global $post;
641 if( stripos($post->post_mime_type, 'video/') !== 0 && stripos($post->post_mime_type, 'audio/') !== 0 ) {
642 return $c;
643 }
644
645 if( !$src = wp_get_attachment_url($post->ID) ) {
646 return $c;
647 }
648
649 $meta = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
650 $size = (isset($meta['width']) && isset($meta['height']) && intval($meta['width'])>0 && intval($meta['height'])>0 ) ? ' width="'.intval($meta['width']).'" height="'.intval($meta['height']).'"' : false;
651
652 $shortcode = '[fvplayer src="'.$src.'"'.$size.']';
653
654 $c = preg_replace( '~<p class=.attachment.[\s\S]*?</p>~', $shortcode, $c );
655 $c = preg_replace( '~<div[^>]*?class="[^"]*?wp-video[^"]*?"[^>]*?>[\s\S]*?<video.*?</video></div>~', $shortcode, $c );
656
657 return $c;
658 }
659 add_filter( 'prepend_attachment', 'fv_flowplayer_attachment_page_video' );
660
661
662 function fv_player_title( $title ) {
663 global $post, $authordata;
664 $sAuthorInfo = ( $authordata ) ? sprintf( '<a href="%1$s" title="%2$s" rel="author">%3$s</a>', esc_url( get_author_posts_url( $authordata->ID, $authordata->user_nicename ) ), esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ), get_the_author() ) : false;
665 $title = str_replace(
666 array(
667 '%post_title%',
668 '%post_date%',
669 '%post_author%',
670 '%post_author_name%'
671 ),
672 array(
673 get_the_title(),
674 get_the_date(),
675 $sAuthorInfo,
676 get_the_author()
677 ),
678 $title );
679 return $title;
680 }
681 add_filter( 'fv_player_title', 'fv_player_title' );
682
683
684 add_filter( 'comment_text', 'fv_player_comment_text', 0 );
685 add_filter( 'bp_get_activity_content_body', 'fv_player_comment_text', 6 );
686 add_filter( 'bbp_get_topic_content', 'fv_player_comment_text', 0 );
687 add_filter( 'bbp_get_reply_content', 'fv_player_comment_text', 0 );
688
689 function fv_player_comment_text( $comment_text ) {
690 if( is_admin() ) return $comment_text;
691
692 global $fv_fp;
693 if( isset($fv_fp->conf['parse_comments']) && $fv_fp->conf['parse_comments'] == 'true' ) {
694 add_filter('comment_text', 'do_shortcode');
695 add_filter('bbp_get_topic_content', 'do_shortcode', 11);
696 add_filter('bbp_get_reply_content', 'do_shortcode', 11);
697
698 if( stripos($comment_text,'youtube.com') !== false || stripos($comment_text,'youtu.be') !== false ) {
699 $pattern = '#(?:<iframe[^>]*?src=[\'"])?((?:https?://|//)?' # Optional URL scheme. Either http, or https, or protocol-relative.
700 . '(?:www\.|m\.)?' # Optional www or m subdomain.
701 . '(?:' # Group host alternatives:
702 . 'youtu\.be/' # Either youtu.be,
703 . '|youtube\.com/' # or youtube.com
704 . '(?:' # Group path alternatives:
705 . 'embed/' # Either /embed/,
706 . '|v/' # or /v/,
707 . '|watch\?v=' # or /watch?v=,
708 . '|watch\?.+&v=' # or /watch?other_param&v=
709 . ')' # End path alternatives.
710 . ')' # End host alternatives.
711 . '([\w-]{11})' # 11 characters (Length of Youtube video ids).
712 . '(?![\w-]))(?:.*?</iframe>)?#'; # Rejects if overlong id.
713 $comment_text = preg_replace( $pattern, '[fvplayer src="$1"]', $comment_text );
714 }
715
716 if( stripos($comment_text,'vimeo.com') !== false ) {
717 $pattern = '#(?:https?://)?(?:www.)?(?:player.)?vimeo.com/(?:[/a-z]*/)*([0-9]{6,11})[?]?.*#';
718 $comment_text = preg_replace( $pattern, '[fvplayer src="https://vimeo.com/$1"]', $comment_text );
719 }
720 }
721
722 return $comment_text;
723 }
724
725 add_action( 'fv_player_extensions_admin_load_assets', 'fv_player_footer_svg_playlist' );
726
727 function fv_player_footer_svg_playlist() {
728 if( file_exists(dirname( __FILE__ ) . '/../css/fvp-icon-sprite.svg') ) {
729 include_once(dirname( __FILE__ ) . '/../css/fvp-icon-sprite.svg');
730 }
731 }
732
733 add_action( 'fv_player_extensions_admin_load_assets', 'fv_player_footer_svg_rewind' );
734
735 function fv_player_footer_svg_rewind() {
736 ?>
737 <svg style="position: absolute; width: 0; height: 0; overflow: hidden;" class="fvp-icon" xmlns="https://www.w3.org/2000/svg">
738 <g id="fvp-rewind">
739 <path d="M22.7 10.9c0 1.7-0.4 3.3-1.1 4.8 -0.7 1.5-1.8 2.8-3.2 3.8 -0.4 0.3-1.3-0.9-0.9-1.2 1.2-0.9 2.1-2 2.7-3.3 0.7-1.3 1-2.7 1-4.1 0-2.6-0.9-4.7-2.7-6.5 -1.8-1.8-4-2.7-6.5-2.7 -2.5 0-4.7 0.9-6.5 2.7 -1.8 1.8-2.7 4-2.7 6.5 0 2.4 0.8 4.5 2.5 6.3 1.7 1.8 3.7 2.7 6.1 2.9l-1.2-2c-0.2-0.3 0.9-1 1.1-0.7l2.3 3.7c0.2 0.3 0 0.6-0.2 0.7L9.5 23.8c-0.3 0.2-0.9-0.9-0.5-1.2l2.1-1.1c-2.7-0.2-5-1.4-6.9-3.4 -1.9-2-2.8-4.5-2.8-7.2 0-3 1.1-5.5 3.1-7.6C6.5 1.2 9 0.2 12 0.2c3 0 5.5 1.1 7.6 3.1C21.7 5.4 22.7 7.9 22.7 10.9z" /><path d="M8.1 15.1c-0.1 0-0.1 0-0.1-0.1V8C8 7.7 7.8 7.9 7.7 7.9L6.8 8.3C6.8 8.4 6.7 8.3 6.7 8.2L6.3 7.3C6.2 7.2 6.3 7.1 6.4 7.1l2.7-1.2c0.1 0 0.4 0 0.4 0.3v8.8c0 0.1 0 0.1-0.1 0.1H8.1z" /><path d="M17.7 10.6c0 2.9-1.3 4.7-3.5 4.7 -2.2 0-3.5-1.8-3.5-4.7s1.3-4.7 3.5-4.7C16.4 5.9 17.7 7.7 17.7 10.6zM12.3 10.6c0 2.1 0.7 3.4 2 3.4 1.3 0 2-1.2 2-3.4 0-2.1-0.7-3.4-2-3.4C13 7.2 12.3 8.5 12.3 10.6z" />
740 </g>
741 </svg>
742 <svg style="position: absolute; width: 0; height: 0; overflow: hidden;" class="fvp-icon" xmlns="https://www.w3.org/2000/svg">
743 <g id="fvp-forward">
744 <path d="M22.7 10.9c0 1.7-0.4 3.3-1.1 4.8 -0.7 1.5-1.8 2.8-3.2 3.8 -0.4 0.3-1.3-0.9-0.9-1.2 1.2-0.9 2.1-2 2.7-3.3 0.7-1.3 1-2.7 1-4.1 0-2.6-0.9-4.7-2.7-6.5 -1.8-1.8-4-2.7-6.5-2.7 -2.5 0-4.7 0.9-6.5 2.7 -1.8 1.8-2.7 4-2.7 6.5 0 2.4 0.8 4.5 2.5 6.3 1.7 1.8 3.7 2.7 6.1 2.9l-1.2-2c-0.2-0.3 0.9-1 1.1-0.7l2.3 3.7c0.2 0.3 0 0.6-0.2 0.7L9.5 23.8c-0.3 0.2-0.9-0.9-0.5-1.2l2.1-1.1c-2.7-0.2-5-1.4-6.9-3.4 -1.9-2-2.8-4.5-2.8-7.2 0-3 1.1-5.5 3.1-7.6C6.5 1.2 9 0.2 12 0.2c3 0 5.5 1.1 7.6 3.1C21.7 5.4 22.7 7.9 22.7 10.9z" transform="scale(-1,1) translate(-24,0)" /><path d="M8.1 15.1c-0.1 0-0.1 0-0.1-0.1V8C8 7.7 7.8 7.9 7.7 7.9L6.8 8.3C6.8 8.4 6.7 8.3 6.7 8.2L6.3 7.3C6.2 7.2 6.3 7.1 6.4 7.1l2.7-1.2c0.1 0 0.4 0 0.4 0.3v8.8c0 0.1 0 0.1-0.1 0.1H8.1z" /><path d="M17.7 10.6c0 2.9-1.3 4.7-3.5 4.7 -2.2 0-3.5-1.8-3.5-4.7s1.3-4.7 3.5-4.7C16.4 5.9 17.7 7.7 17.7 10.6zM12.3 10.6c0 2.1 0.7 3.4 2 3.4 1.3 0 2-1.2 2-3.4 0-2.1-0.7-3.4-2-3.4C13 7.2 12.3 8.5 12.3 10.6z" />
745 </g>
746 </svg>
747 <?php
748 }
749
750 add_action( 'wp_footer', 'fv_player_load_svg_buttons_everywhere' );
751
752 function fv_player_load_svg_buttons_everywhere() {
753 global $fv_fp;
754 if( !$fv_fp->should_force_load_js() ) {
755 return;
756 }
757
758 foreach( array(
759 'no_picture',
760 'repeat',
761 'rewind'
762 ) AS $type ) {
763 if( $type == 'rewind' ) {
764 add_action( 'wp_footer', 'fv_player_footer_svg_rewind', 101 );
765 } else if( $type == 'repeat' || $type == 'no_picture' ) {
766 add_action( 'wp_footer', 'fv_player_footer_svg_playlist', 101 );
767 }
768 }
769
770 if( function_exists('FV_Player_Pro') && method_exists( 'FV_Player_Pro', 'svg_chapters') ) {
771 add_action( 'wp_footer', array( FV_Player_Pro(), 'svg_chapters'), 101 );
772 }
773 }
774
775 add_filter( 'script_loader_tag', 'fv_player_js_loader_mark_scripts', PHP_INT_MAX, 2 );
776
777 /**
778 * Disables scroll auotplay
779 *
780 * @return void
781 */
782 function fv_player_disable_scroll_autoplay() {
783 add_filter('fv_flowplayer_conf', 'fv_player_disable_scroll_autoplay');
784 }
785
786 /**
787 * Removes scroll autoplay from conf
788 *
789 * @param array $conf
790 *
791 * @return array $conf
792 */
793 function fv_player_disable_scroll_autoplay_conf($conf) {
794 unset($conf['autoplay_preload']);
795 return $conf;
796 }
797
798 /**
799 * Alters all the script tags related to FV Player, with excetption of the base FV Player library.
800 * The reason is that it's a dependency of most of the modules so then each module would have to be
801 * adjusted to be able to load without it.
802 *
803 * Fancybox lightbox library with additional code is also excluded.
804 *
805 * @param string $tag The original script tag.
806 * @param string $handle The WordPress script handle
807 *
808 * @global object $fv_fp The FV Player plugin instance
809 *
810 * @return string The adjusted script tag
811 */
812 function fv_player_js_loader_mark_scripts( $tag, $handle ) {
813 global $fv_fp;
814 if( is_admin() || isset($_GET['fv_player_loader_skip']) || $fv_fp->_get_option('js-everywhere') || !$fv_fp->_get_option('js-optimize') || flowplayer::is_wp_rocket_setting( 'delay_js' ) || did_action( 'fv_player_skip_js_optimize' ) ) {
815 return $tag;
816 }
817
818 if(
819 // script ID must start with one of following
820 (
821 stripos($handle,'flowplayer-') === 0 || // process HLS.js and Dash.js, but not the base FV Player library, that one must be present instantly
822 stripos($handle,'fv-player') === 0 ||
823 stripos($handle,'fv_player') === 0 ||
824 'dashjs' === $handle
825
826 // script handle must not be one of
827 ) && !in_array( $handle, array(
828 'fv_player_lightbox', // without this it would be impossible to open the lightbox without hovering the page before it, so it's really a problem on mobile
829 'fv-player-s3-uploader',
830 'fv-player-s3-uploader-base',
831 ), true )
832 ) {
833 $tag = str_replace( ' src=', ' data-fv-player-loader-src=', $tag );
834 add_action( 'wp_print_footer_scripts', 'fv_player_js_loader_load', PHP_INT_MAX );
835 }
836 return $tag;
837 }
838
839 /*
840 * Outpput FV Player JS Loader into footer, hooked in in fv_player_js_loader_mark_scripts()
841 */
842 function fv_player_js_loader_load() {
843 require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
844 require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
845 $filesystem = new WP_Filesystem_Direct( new StdClass() );
846
847 $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? 'dev' : 'min';
848
849 $js = $filesystem->get_contents( dirname(__FILE__).'/../freedom-video-player/fv-player-loader.'.$suffix.'.js' );
850
851 if( !defined('SCRIPT_DEBUG') || !SCRIPT_DEBUG ) {
852 // remove /* comments */
853 $js = preg_replace( '~/\*[\s\S]*?\*/~m', '', $js );
854 // remove whitespace
855 $js = preg_replace( '~\s+~m', ' ', $js );
856 }
857
858 echo '<script data-length="'.strlen($js).'">'.$js.'</script>';
859 }
860
861 /**
862 * @param string $min The minimal version to check - like 7.4.44.727
863 *
864 * @return bool True if the version is at least $min
865 */
866 function fv_player_extension_version_is_min( $min, $extension = 'pro' ) {
867 $version = false;
868 if( $extension == 'pro' ) {
869 global $FV_Player_Pro;
870 if( isset($FV_Player_Pro) && !empty($FV_Player_Pro->version) ) {
871 $version = $FV_Player_Pro->version;
872 }
873
874 } else if( $extension == 'vast' ) {
875 global $FV_Player_VAST;
876 if( isset($FV_Player_VAST) && !empty($FV_Player_VAST->version) ) {
877 $version = $FV_Player_VAST->version;
878 }
879
880 } else if( $extension == 'alternative-sources' ) {
881 global $FV_Player_Alternative_Sources;
882 if( isset($FV_Player_Alternative_Sources) && !empty($FV_Player_Alternative_Sources->version) ) {
883 $version = $FV_Player_Alternative_Sources->version;
884 }
885
886 } else if( $extension == 'ppv' ) {
887 global $FV_Player_PayPerView;
888 if( isset($FV_Player_PayPerView) && !empty($FV_Player_PayPerView->version) ) {
889 $version = $FV_Player_PayPerView->version;
890 }
891
892 } else if( $extension == 'ppv-woocommerce' ) {
893 global $FV_Player_PayPerView_WooCommerce;
894 if( isset($FV_Player_PayPerView_WooCommerce) && !empty($FV_Player_PayPerView_WooCommerce->version) ) {
895 $version = $FV_Player_PayPerView_WooCommerce->version;
896 }
897
898 }
899
900 $version = str_replace('.beta','',$version);
901
902 return version_compare($version,$min ) != -1;
903 }
904
905
906 /*
907 * WP Rocket Used CSS exclusion
908 * Since many FV Player features are only visible once the video starts this optimization doesn't work
909 */
910 add_filter( 'pre_get_rocket_option_remove_unused_css_safelist', 'fv_player_wp_rocket_used_css' );
911
912 function fv_player_wp_rocket_used_css( $safelist ) {
913 // Without this our additions would show on WP Rocket settings page
914 if ( did_action( 'admin_head-settings_page_wprocket' ) ) {
915 return $safelist;
916 }
917
918 $safelist[] = '/wp-content/fv-player-custom/style-(.*)';
919 $safelist[] = '/wp-content/plugins/fv-wordpress-flowplayer(.*)';
920 $safelist[] = '/wp-content/plugins/fv-player(.*)';
921 return $safelist;
922 }
923
924
925 /*
926 * SiteGround Security "Lock and Protect System Folders" exclusion
927 *
928 * The plugins normally blocks direct PHP calls in wp-content folder, we allow track.php requests for FV Player tracking this way
929 * Unfortunately it uses simple rule like <Files track.php> so we cannot include the folder name.
930 */
931 add_filter( 'sgs_whitelist_wp_content' , 'fv_player_sgs_whitelist_wp_content' );
932
933 function fv_player_sgs_whitelist_wp_content( $exclusions ) {
934 global $fv_fp;
935
936 $exclusions[] = 's3-ajax.php';
937
938 if( $fv_fp->_get_option('video_stats_enable') ) {
939 $exclusions[] = 'track.php';
940 }
941
942 if ( class_exists( 'FV_Player_Coconut' ) ) {
943 $exclusions[] = 'coconut-ajax.php';
944 }
945
946 if ( class_exists( 'FV_Player_Pro' ) ) {
947 $exclusions[] = 'stream-loader.php';
948 }
949
950 return $exclusions;
951 }
952
953
954 /*
955 * SiteGround Optimizer unfortunately does not process the scripts enqueued after wp_head has finished.
956 * So then "Defer Render-blocking JavaScript" does not defer FV Player but it defect jQuery.
957 * So we have to make sure jQuery is not defered as FV Player scripts depend on it.
958 * There are no issues when using "Combine JavaScript Files"
959 */
960 add_filter( 'sgo_js_async_exclude', 'fv_player_sgo_js_async_exclude' );
961
962 function fv_player_sgo_js_async_exclude( $excluded_scripts ) {
963 $excluded_scripts[] = 'jquery-core';
964 return $excluded_scripts;
965 }
966
967 /*
968 * Some themes do not remove shortcodes when showing excerpts.
969 * So we remove [fvplayer...] as in excerpt it would only show "Please enable JavaScript" kind of message.
970 */
971
972 // Learnify, this filter seems to run for excerpts only, see learnify_show_post_content()
973 add_filter( 'learnify_filter_post_content', 'fv_player_remove_for_excerpt' );
974
975 function fv_player_remove_for_excerpt( $post_content ) {
976 if( is_archive() ) {
977 $post_content = preg_replace( '~\[fvplayer.*?\]~', '', $post_content );
978 }
979 return $post_content;
980 }
981
982
983 /*
984 * @param array $args {
985 * @param int $count Number of items to get
986 * @param bool $full_details Should it return full details about the video progress?
987 * @param string $include Get only "unfinished" or "finished" videos.
988 * @param string $post_type Post type where the video is embed
989 * @param int $user_id User ID to operate on, defaults to logged in user.
990 * }
991 *
992 * @return array Array of post IDs
993 */
994 function fv_player_get_user_watched_post_ids( $args = array() ) {
995 $args = wp_parse_args( $args, array(
996 'count' => 20,
997 'include' => 'all',
998 'post_type' => 'any',
999 'user_id' => get_current_user_id()
1000 ) );
1001
1002 $args['full_details'] = true;
1003
1004 $video_ids = fv_player_get_user_watched_video_ids( $args );
1005 if( count($video_ids) == 0 ) {
1006 return array();
1007 }
1008
1009 $post_ids = array();
1010 foreach( $video_ids AS $data ) {
1011 if( !empty($data['post_id']) ) {
1012 $post_ids[] = $data['post_id'];
1013 }
1014 }
1015
1016 return $post_ids;
1017 }
1018
1019
1020 /*
1021 * @param array $args {
1022 * @param int $count Number of items to get
1023 * @param bool $full_details Should it return full details about the video progress?
1024 * @param string $include Get only "unfinished" or "finished" videos.
1025 * @param string $post_type Post type where the video is embed
1026 * @param int $user_id User ID to operate on, defaults to logged in user.
1027 * }
1028 *
1029 * @return array Array of video IDs, or array of video progress details
1030 */
1031 function fv_player_get_user_watched_video_ids( $args = array() ) {
1032 $args = wp_parse_args( $args, array(
1033 'count' => 20,
1034 'full_details' => false,
1035 'include' => 'all',
1036 'post_type' => 'any',
1037 'user_id' => get_current_user_id()
1038 ) );
1039
1040 $output = array();
1041
1042 global $wpdb;
1043
1044 static $user_meta;
1045 if( !isset($user_meta) ) {
1046 $user_meta = array();
1047 }
1048 if( !isset($user_meta[ $args['user_id'] ]) ) {
1049 $user_meta[ $args['user_id'] ] = $wpdb->get_results(
1050 $wpdb->prepare(
1051 "SELECT meta_key, meta_value FROM $wpdb->usermeta WHERE user_id = %d AND ( meta_key LIKE %s OR meta_key LIKE %s OR meta_key LIKE %s ) ORDER BY umeta_id DESC",
1052 $args['user_id'],
1053 $wpdb->esc_like( 'fv_wp_flowplayer_position_' ) . '%',
1054 $wpdb->esc_like( 'fv_wp_flowplayer_top_position_' ) . '%',
1055 $wpdb->esc_like( 'fv_wp_flowplayer_saw_' ) . '%'
1056 )
1057 );
1058 }
1059
1060 if( $user_meta[ $args['user_id'] ] ) {
1061 $metas = $user_meta[ $args['user_id'] ];
1062
1063 $output = array();
1064
1065 foreach( $metas AS $meta ) {
1066 if( stripos( $meta->meta_key, 'fv_wp_flowplayer_top_position_') === 0 ) {
1067 $video_id = str_replace( 'fv_wp_flowplayer_top_position_', '', $meta->meta_key );
1068 if( !is_numeric($video_id) ) continue;
1069
1070 $output[$video_id] = array(
1071 'type' => 'unfinished',
1072 'message' => 'Watched until '.flowplayer::format_hms($meta->meta_value),
1073 'time' => $meta->meta_value
1074 );
1075
1076 } else if( stripos( $meta->meta_key, 'fv_wp_flowplayer_position_') === 0 ) {
1077 $video_id = str_replace( 'fv_wp_flowplayer_position_', '', $meta->meta_key );
1078 if( !is_numeric($video_id) ) continue;
1079
1080 if( empty($output[$video_id]) ) {
1081 $output[$video_id] = array(
1082 'type' => 'unfinished',
1083 'message' => 'Watched until '.flowplayer::format_hms($meta->meta_value),
1084 'time' => $meta->meta_value
1085 );
1086 }
1087
1088 }
1089
1090 // No "else if" as we want the full video watch to take priority over the stored position
1091 if( stripos( $meta->meta_key, 'fv_wp_flowplayer_saw_') === 0 ) {
1092 $video_id = str_replace( 'fv_wp_flowplayer_saw_', '', $meta->meta_key );
1093 if( !is_numeric($video_id) ) continue;
1094
1095 $output[$video_id] = array(
1096 'type' => 'finished',
1097 'message' => 'Saw whole video'
1098 );
1099 }
1100 }
1101 }
1102
1103 // Filter unfinished or finished videos
1104 if( $args['include'] != 'all' ) {
1105 foreach( $output AS $video_id => $details ) {
1106 if( $args['include'] != $details['type'] ) {
1107 unset( $output[$video_id]);
1108 }
1109 }
1110 }
1111
1112 // Add player_id and post_id for the videos
1113 // Remove items which do not belong to a player and published post
1114 if( count($output) ) {
1115 $post_type_where = $args['post_type'] != 'any' ? 'post_type = %s AND ': '';
1116 $video_ids = implode( ',', array_map( 'intval', array_keys( $output ) ) );
1117
1118 $videos2players2posts = $wpdb->get_results( $wpdb->prepare( "
1119 SELECT pl.id AS player_id, v.id AS video_id, pm.meta_value AS post_id FROM
1120 {$wpdb->prefix}fv_player_players AS pl
1121 JOIN {$wpdb->prefix}fv_player_playermeta AS pm
1122 ON pl.id = pm.id_player
1123 JOIN {$wpdb->prefix}fv_player_videos AS v
1124 ON FIND_IN_SET(v.id, pl.videos)
1125 JOIN {$wpdb->posts} AS p
1126 ON p.ID = pm.meta_value
1127 WHERE
1128 pm.meta_key = 'post_id' AND
1129 p.post_status = 'publish' AND
1130 $post_type_where
1131 v.id IN ( {$video_ids} )", $args['post_type'] ) );
1132
1133 foreach( $output AS $video_id => $details ) {
1134 $found = false;
1135 foreach( $videos2players2posts AS $more_details ) {
1136
1137 if( $more_details->video_id == $video_id ) {
1138 $found = true;
1139 $output[$video_id]['player_id'] = $more_details->player_id;
1140 $output[$video_id]['post_id'] = $more_details->post_id;
1141 break;
1142 }
1143 }
1144
1145 if( !$found ) {
1146 unset($output[$video_id]);
1147 }
1148 }
1149 }
1150
1151 if( !$args['full_details'] ) {
1152 $output = array_keys( $output );
1153 }
1154
1155 return $output;
1156 }
1157
1158
1159 add_shortcode( 'fvplayer_editor', 'fvplayer_editor' );
1160
1161 /**
1162 * @param array $args {
1163 * @type string $field jQuery field selector of the field with the shortcode
1164 * @type string $hide Comma separated list of fields to hide
1165 * @type string $library Comma separated list of libraries to show in Media Library
1166 * @type string $tabs Use "none" to only show Playlist and Videos tabs and nothing else, like Options, Actions or Subtitles
1167 * }
1168 *
1169 * @return string HTML code.
1170 */
1171 function fvplayer_editor( $args ) {
1172 include_once( ABSPATH.'/wp-admin/includes/plugin.php' );
1173 include_once( __DIR__.'/editor.php' );
1174
1175 if( version_compare(phpversion(),'5.5.0') != -1 ) {
1176 include_once( __DIR__ . '/../models/media-browser.php');
1177 }
1178
1179 if ( function_exists( 'FV_Player_Pro' ) && method_exists ( 'FV_Player_Pro', 'include_vimeo_media_browser' ) ) {
1180 FV_Player_Pro()->include_vimeo_media_browser( true );
1181 }
1182
1183 do_action( 'fvplayer_editor_load' );
1184
1185 wp_enqueue_media();
1186
1187 $args['frontend'] = true;
1188
1189 fv_player_shortcode_editor_scripts_enqueue( $args );
1190
1191 ob_start();
1192 fv_wp_flowplayer_edit_form_after_editor();
1193 ?>
1194 <script>
1195 var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
1196
1197 document.addEventListener( 'DOMContentLoaded', function() {
1198 jQuery(function() {
1199
1200 // Wait until FV Player Editor $doc.ready() finishes
1201 setTimeout( function() {
1202 fv_player_editor.editor_open();
1203 });
1204 });
1205 });
1206 </script>
1207 <style>
1208 #fv-player-editor-modal {
1209 display: block !important;
1210 position: relative !important;
1211 top: auto !important;
1212 left: unset !important;
1213 right: unset !important;
1214 bottom: unset !important;
1215 z-index: unset !important;
1216 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
1217 }
1218 #fv-player-editor-modal h2 {
1219 letter-spacing: normal;
1220 }
1221 #fv-player-editor-modal #fv-player-shortcode-editor {
1222 position: static !important;
1223 }
1224 #fv-player-editor-modal-close {
1225 display: none !important;
1226 }
1227 #fv-player-shortcode-editor-preview {
1228 margin-top: 16px;
1229 }
1230 .fv-player-tab {
1231 overflow-y: unset !important;
1232 }
1233 /* Left-align for the inputs */
1234 #fv-player-shortcode-editor #fv-player-shortcode-editor-preview-no .components-base-control__field {
1235 justify-content: unset;
1236 }
1237 /* Hide the intro text */
1238 #fv-player-shortcode-editor-preview-no > p {
1239 display: none;
1240 }
1241 /* Somehow the vertical scrolling would appear when one video was inserted */
1242 #fv-player-shortcode-editor #fv-player-shortcode-editor-left {
1243 overflow-x: unset;
1244 }
1245
1246 /* Core WordPress Admin Button styling */
1247 #fv-player-editor-modal .button, #fv-player-editor-modal .button-primary, #fv-player-editor-modal .button-secondary {
1248 box-shadow: unset;
1249 display: inline-block;
1250 text-decoration: none;
1251 font-size: 13px;
1252 font-weight: normal;
1253 letter-spacing: normal;
1254 line-height: 2.15384615;
1255 min-height: 30px;
1256 margin: 0;
1257 margin-top: 0 !important;
1258 padding: 0 10px;
1259 cursor: pointer;
1260 border-width: 1px;
1261 border-style: solid;
1262 -webkit-appearance: none;
1263 border-radius: 3px;
1264 white-space: nowrap;
1265 box-sizing: border-box;
1266 text-shadow: unset;
1267 text-transform: none;
1268 width: auto !important;
1269 }
1270 #fv-player-editor-modal .button.hover, #fv-player-editor-modal .button:hover, #fv-player-editor-modal .button-secondary:hover {
1271 background: #f0f0f1;
1272 border-color: #0a4b78;
1273 color: #0a4b78;
1274 }
1275 #fv-player-editor-modal .button, #fv-player-editor-modal .button-secondary {
1276 color: #2271b1;
1277 border-color: #2271b1;
1278 background: #f6f7f7;
1279 vertical-align: top;
1280 }
1281 #fv-player-editor-modal .button-primary {
1282 background: #2271b1;
1283 border-color: #2271b1;
1284 color: #fff;
1285 text-decoration: none;
1286 text-shadow: none;
1287 }
1288 #fv-player-editor-modal .button-primary.hover, #fv-player-editor-modal .button-primary:hover, #fv-player-editor-modal .button-primary.focus, #fv-player-editor-modal .button-primary:focus {
1289 background: #135e96;
1290 border-color: #135e96;
1291 color: #fff;
1292 }
1293
1294 /* Core WordPress Media Library styles to fix */
1295 .media-modal .media-router button.media-menu-item {
1296 color: #3c434a;
1297 text-transform: none;
1298 }
1299 </style>
1300 <?php
1301 return ob_get_clean();
1302 }
1303
1304 /**
1305 * The nonce normally only work up to 24 hours, but it might just be 12 hours.
1306 *
1307 * We set the nonce life to 7 days to make sure caching plugins don't break the video tracking etc.
1308 *
1309 * So far we were able to use 42 hours old nonce without any issues. When the nonce was 4 days and 19 hours old
1310 * it would already fail. So my guess is that this way we can be sure that the nonce is valid for 3.5 days,
1311 * but it might be up to 7 days.
1312 */
1313 add_filter( 'nonce_life', 'fv_player_frontend_nonce_life', PHP_INT_MAX, 2 );
1314
1315 /**
1316 * @param int $seconds
1317 * @param string|false $action This has one been added in WordPress 6.1 unfortunately
1318 *
1319 * @return int Longer nonce TTL if it's used by FV Player
1320 */
1321 function fv_player_frontend_nonce_life( $seconds, $action = false ) {
1322 if (
1323 in_array(
1324 $action,
1325 array(
1326 'fv_player_email_signup',
1327 'fv_player_track',
1328 'fv_player_video_position_save',
1329 )
1330 )
1331 ) {
1332 $seconds = 7 * DAY_IN_SECONDS;
1333 }
1334 return $seconds;
1335 }
1336
1337 add_action( 'wp_ajax_fv_player_save_audio_settings', 'fv_player_save_audio_settings' );
1338
1339 function fv_player_save_audio_settings() {
1340 if (
1341 empty( $_POST['nonce'] ) ||
1342 ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'fv_player_frontend' )
1343 ) {
1344 wp_send_json_error( 'Invalid nonce' );
1345 }
1346
1347 update_user_meta( get_current_user_id(), 'fv_player_audio_name', sanitize_text_field( $_POST['name'] ) );
1348 update_user_meta( get_current_user_id(), 'fv_player_audio_lang', sanitize_text_field( $_POST['lang'] ) );
1349 }