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

shortcodes.php in FV Player 8 8.0.21, at controller/shortcodes.php

651 lines 21.0 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 require_once dirname( __FILE__ ) . '/../models/fv-player.php';
24 if (!class_exists('flowplayer_frontend'))
25 require_once dirname( __FILE__ ) . '/../models/fv-player-frontend.php';
26
27 add_shortcode('flowplayer','flowplayer_content_handle');
28
29 add_shortcode('fvplayer','flowplayer_content_handle');
30
31 add_shortcode('fv_time','fv_player_time');
32
33 function flowplayer_content_handle( $atts, $content = null, $tag = false ) {
34 global $fv_fp;
35 if( !$fv_fp ) return false;
36
37 if( $fv_fp->_get_option('parse_commas') && strcmp($tag,'flowplayer') == 0 ) {
38
39 if( !isset( $atts['src'] ) ) {
40 foreach( $atts AS $key => $att ) {
41 if( stripos( $att, 'src=' ) !== FALSE ) {
42 if( stripos( $att, ',' ) === FALSE ) { // if the broken attribute is not using ','
43 $atts['src'] = preg_replace( '/^\s*?src=[\'"](.*)[\'"].*?$/', '$1', $att );
44 } else {
45 $atts['src'] = preg_replace( '/^\s*?src=[\'"](.*)[\'"],\s*?$/', '$1', $att );
46 }
47 $i = $key+1;
48 unset( $atts[$key] ); // = ''; // let's remove it, so it won't confuse the rest of workaaround
49 }
50 }
51 }
52
53 if( !isset( $atts['splash'] ) ) {
54 foreach( $atts AS $key => $att ) {
55 if( stripos( $att, 'splash=' ) !== FALSE ) {
56 $atts['splash'] = preg_replace( '/^\s*?splash=[\'"](.*)[\'"],\s*?$/', '$1', $att );
57 unset( $atts[$key] ); // = ''; // let's remove it, so it won't confuse the rest of workaround
58 }
59 }
60 }
61
62 // the popup should really be a content of the shortcode, not an attribute
63 // this part will fix the popup if there is any single quote in it.
64 if( !isset( $atts['popup'] ) ) {
65 $popup = array();
66 $is_popup = false;
67 foreach( $atts AS $key => $att ) {
68 if( !is_numeric( $key ) ) continue;
69 if( ( stripos( $att, 'popup=' ) !== FALSE || $is_popup ) && stripos( $att, 'src=' ) === FALSE && stripos( $att, 'splash=' ) === FALSE && stripos( $att, 'ad=' ) === FALSE) {
70 $popup[] = $att;
71 $is_popup = true;
72 unset( $atts[$key] ); // = ''; // let's remove it, so it won't confuse the rest of workaround
73 }
74 }
75 $popup = implode( ' ', $popup );
76 $atts['popup'] = preg_replace( '/^\s*?popup=[\'"](.*)[\'"]\s*?$/mi', '$1', $popup );
77 }
78
79 // same for ad code
80 if( !isset( $atts['ad'] ) ) {
81 $ad = array();
82 $is_ad = false;
83 foreach( $atts AS $key => $att ) {
84 if( !is_numeric( $key ) ) continue;
85 if( ( stripos( $att, 'ad=' ) !== FALSE || $is_ad ) && stripos( $att, 'src=' ) === FALSE && stripos( $att, 'splash=' ) === FALSE && stripos( $att, 'popup=' ) === FALSE) {
86 $ad[] = $att;
87 $is_ad = true;
88 unset( $atts[$key] ); // = ''; // let's remove it, so it won't confuse the rest of workaround
89 }
90 }
91 $ad = implode( ' ', $ad );
92 $atts['ad'] = preg_replace( '/^\s*?ad=[\'"](.*)[\'"]\s*?$/mi', '$1', $ad );
93 }
94
95 }
96
97 $atts = wp_parse_args( $atts, array(
98 'admin_warning' => '',
99 'align' => '',
100 'autoplay' => '',
101 'caption' => '',
102 'caption_html' => '',
103 'controlbar' => '',
104 'embed' => '',
105 'end_popup_preview' => '',
106 'engine' => '',
107 'height' => '',
108 'mobile' => '',
109 'linking' => '',
110 'liststyle' => '',
111 'live' => '',
112 'logo' => '',
113 'loop' => '',
114 'overlay' => '',
115 'overlay_width' => '',
116 'overlay_height' => '',
117 'overlay_skip' => '',
118 'play_button' => '',
119 'playlist' => '',
120 'playlist_advance' => '',
121 'playlist_hide' => '',
122 'popup' => '',
123 'post' => '',
124 'redirect' => '',
125 'rtmp' => '',
126 'rtmp_path' => '',
127 'share' => '',
128 'skin' => '',
129 'speed' => '',
130 'splash' => '',
131 'splash_text' => '',
132 'splashend' => '',
133 'src' => '',
134 'src1' => '',
135 'src2' => '',
136 'sticky' => '',
137 'subtitles' => '',
138 'title' => '',
139 'width' => '',
140 ) );
141
142 if( $fv_fp->_get_option('parse_commas') && strcmp($tag,'flowplayer') == 0 ) {
143 foreach( $atts AS $k => $v ) {
144 if( in_array($k, array('admin_warning','caption','caption_html','playlist','popup','share') ) ) {
145 $arguments[$k] = $v;
146 } else {
147 $arguments[$k] = preg_replace('/\,/', '', $v);
148 }
149 }
150
151 } else {
152 $arguments = $atts;
153 }
154
155 if( ( !isset($arguments['src']) || strlen(trim($arguments['src'])) == 0 ) && isset($arguments['mobile']) && strlen(trim($arguments['mobile'])) ) {
156 $arguments['src'] = $arguments['mobile'];
157 unset($arguments['mobile']);
158 }
159
160 $arguments = apply_filters( 'fv_flowplayer_shortcode', $arguments, $fv_fp, $atts );
161
162 if( $arguments['post'] == 'this' ) {
163 $arguments['post'] = get_the_ID();
164 }
165
166 // accepts:
167 // 1) [fvplayer id="198"] - a DB-based shortcode in the form
168 // 2) [fvplayer src="198" playlist="198;199;200"] - a front-end user's playlist shortcode that is programatically passed to this method
169 if( (!empty($arguments['id']) && intval($arguments['id']) > 0) || (!empty($arguments['src']) && is_numeric($arguments['src']) && intval($arguments['src']) > 0) ) {
170 $new_player = $fv_fp->build_min_player(false, $arguments);
171 if (!empty($new_player['script'])) {
172 $GLOBALS['fv_fp_scripts'] = $new_player['script'];
173 }
174
175 if ( $new_player ) {
176 return $new_player['html'];
177 } else {
178 return '';
179 }
180
181 } else if( intval($arguments['post']) > 0 ) {
182 $objVideoQuery = new WP_Query( array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_parent' => intval($post), 'post_mime_type' => 'video' ) );
183 if( $objVideoQuery->have_posts() ) {
184 $sHTML = '';
185 while( $objVideoQuery->have_posts() ) {
186 $objVideoQuery->the_post();
187 $aArgs = $arguments;
188 $aArgs['src'] = wp_get_attachment_url(get_the_ID());
189 if( $aSplash = wp_get_attachment_image_src( get_post_thumbnail_id(get_the_ID()), 'large' ) ) {
190 $aArgs['splash'] = $aSplash[0];
191 }
192 if( strlen($aArgs['lightbox']) ) {
193 $aArgs['lightbox'] .= ';'.html_entity_decode(get_the_title());
194 }
195 if( strlen($aArgs['title']) ) {
196 $aArgs['title'] = apply_filters( 'fv_player_title', $aArgs['title'], false );
197 }
198
199 $new_player = $fv_fp->build_min_player( $aArgs['src'],$aArgs );
200 if ( $new_player ) {
201 $sHTML .= $new_player['html'];
202 }
203 }
204
205 return $sHTML;
206 }
207
208 } else if( $arguments['src'] != '' || ( ( ( strlen($fv_fp->conf['rtmp']) && $fv_fp->conf['rtmp'] != 'false' ) || strlen($arguments['rtmp'])) && strlen($arguments['rtmp_path']) ) ) {
209 // build new player
210 $new_player = $fv_fp->build_min_player($arguments['src'],$arguments);
211 if (!empty($new_player['script'])) {
212 $GLOBALS['fv_fp_scripts'] = $new_player['script'];
213 }
214
215 if ( $new_player ) {
216 return $new_player['html'];
217 } else {
218 return '';
219 }
220
221 }
222 return false;
223 }
224
225
226
227
228 add_filter( 'the_content', 'fv_flowplayer_optimizepress', 1 );
229
230 function fv_flowplayer_optimizepress( $post_content ) {
231
232 if( stripos( $post_content, '[video_player type="url"' ) === false ) {
233 return $post_content;
234 }
235
236 $post_content = preg_replace_callback( '~\[video_player.*?\].*?\[/video_player\]~', 'fv_flowplayer_optimizepress_bridge', $post_content );
237 return $post_content;
238 }
239
240 function fv_flowplayer_optimizepress_bridge( $input ) {
241 $video = $input[0];
242
243 $atts = shortcode_parse_atts($video);
244
245 $default = array(
246 'type' => 'embed', // na
247 'hide_controls' => 'N', // todo
248 'auto_play' => 'N', // ok
249 'auto_buffer' => 'N', // todo
250 'width' => 511, // ok
251 'height' => 288, // ok
252 'margin_top' => 0, // todo
253 'margin_bottom' => 20, // todo
254 'border_size' => 0, // todo
255 'border_color' => '#fff', // todo
256 'placeholder' => '', // ok
257 'align' => 'center', // ok
258 'youtube_url' => '', // na
259 'youtube_auto_play' => 'N', // na
260 'youtube_hide_controls' => 'N', // na
261 'youtube_remove_logo' => 'N', // na
262 'youtube_show_title_bar' => 'N', // na
263 'youtube_force_hd' => '', // na
264 'url1' => '', // ok
265 'url2' => '', // ok
266 );
267 $vars = shortcode_atts($default, $atts);
268
269 $shortcode = '[fvplayer';
270
271 $content = preg_replace( '~\[video_player.*?\](.*?)\[/video_player\]~', '$1', $video );
272 $content = base64_decode($content);
273 if(preg_match('|(https?://[^<"]+)|im',$content,$matches)){
274 $shortcode .= ' src="'.$matches[1].'"';
275 }
276 $url1 = base64_decode($atts['url1']);
277 if(preg_match('|(https?://[^<"]+)|im',$url1,$matches)){
278 $shortcode .= ' src1="'.$matches[1].'"';
279 }
280 $url2 = base64_decode($atts['url2']);
281 if(preg_match('|(https?://[^<"]+)|im',$url2,$matches)){
282 $shortcode .= ' src2="'.$matches[1].'"';
283 }
284
285 if( $vars['placeholder'] ) {
286 $shortcode .= ' splash="'.$vars['placeholder'].'"';
287 }
288
289 if( $vars['auto_play'] == 'Y' ) {
290 $shortcode .= ' autoplay="true"';
291 }
292
293
294 $shortcode .= ' width="'.$vars['width'].'"';
295 $shortcode .= ' height="'.$vars['height'].'"';
296 $shortcode .= ' align="'.$vars['align'].'"';
297
298 if( current_user_can('manage_options') &&
299 (
300 ( isset($vars['margin-top']) && $vars['margin-top'] > 0 ) ||
301 ( isset($vars['margin-bottom']) && $vars['margin-bottom'] > 0 && $vars['margin-bottom'] != 20 ) ||
302 ( isset($vars['hide_controls']) && $vars['hide_controls'] == 'Y' ) ||
303 ( isset($vars['auto_buffer']) && $vars['auto_buffer'] == 'Y' ) ||
304 ( isset($vars['border_size']) && $vars['border_size'] > 0 ) ||
305 isset($vars['border_color'])
306 )
307 ) {
308 $shortcode .= ' admin_warning="Admin note: Some of the OptimizePress styling parameters are not supported by FV Player. Please visit the <a href=\''.admin_url('admin.php?page=fvplayer').'\'>settings</a> and set your global appearance preferences there."';
309 }
310
311 $shortcode .= ']';
312
313 return $shortcode;
314 }
315
316
317 function fv_player_time( $args = array() ) {
318 global $post, $fv_fp;
319
320 if( !empty($args['id']) ) {
321 $player = new FV_Player_Db_Player($args['id']);
322 if( $player->getIsValid() ) {
323 foreach( $player->getVideos() AS $video ) {
324 if( $duration = $video->getDuration() ) {
325 return flowplayer::format_hms( $duration );
326 }
327 }
328 }
329 }
330
331 if( $post->ID > 0 && isset($fv_fp->aCurArgs['src']) ) {
332 return flowplayer::get_duration( $post->ID, $fv_fp->aCurArgs['src'] );
333 } else {
334 return flowplayer::get_duration_post();
335 }
336 }
337
338
339 function fv_player_handle_vimeo_links( $html, $closing = '<!-- link converted by FV Player -->' ) {
340 $html = preg_replace( '~<iframe[^>]*?vimeo\.com/video/(\d+)[^>]*?(\?h=[a-z0-9]+)?[^>]*?></iframe>~', '[fvplayer src="http://vimeo.com/$1$2"]' . $closing, $html );
341 return $html;
342 }
343
344 function fv_player_handle_youtube_links( $html, $closing = '<!-- link converted by FV Player -->' ) {
345 $html = preg_replace( '~<iframe[^>]*?youtube(?:-nocookie)?\.com/(?:embed|v)/(.*?)[\'"&#\?][^>]*?></iframe>~', '[fvplayer src="http://youtube.com/watch?v=$1"]' . $closing, $html );
346 return $html;
347 }
348
349 function fv_player_handle_video_tags( $html, $closing = '<!-- link converted by FV Player -->' ) {
350 $html = preg_replace( '~<figure class="wp-block-video"><video[^>]*?src\s*=\s*"(.+?)"[^>]*?></video></figure>~', '<figure class="wp-block-video">[fvplayer src="$1"]' . $closing . '</figure>' , $html);
351 return $html;
352 }
353
354 function fv_flowplayer_shortcode_video( $output ) {
355 $aArgs = func_get_args();
356 $atts = $aArgs[1];
357
358 $bridge_atts = array();
359 if( isset($atts['src']) ) {
360 $bridge_atts['src'] = $atts['src'];
361 }
362
363 $count = 0;
364 foreach( array('mp4','webm','ogv','mov','flv','wmv','m4v','mp3') AS $key => $value ) {
365 if( !empty($atts[$value]) ) {
366 $src = 'src'.(( $count > 0 ) ? $count : '');
367 $bridge_atts[$src] = $atts[$value];
368 $count++;
369 }
370 }
371
372 if( isset($atts['poster']) ) {
373 $bridge_atts['splash'] = $atts['poster'];
374 }
375
376 if( isset($atts['loop']) && $atts['loop'] == 'on' ) {
377 $bridge_atts['loop'] = 'true';
378 } else if( isset($atts['loop']) && $atts['loop'] == 'off' ) {
379 $bridge_atts['loop'] = 'false';
380 }
381
382 if( isset($atts['autoplay']) && $atts['autoplay'] == 'on' ) {
383 $bridge_atts['autoplay'] = 'true';
384 } else if( isset($atts['loop']) && $atts['loop'] == 'off' ) {
385 $bridge_atts['autoplay'] = 'false';
386 }
387
388 if( isset($atts['width']) ) {
389 $bridge_atts['width'] = $atts['width'];
390 }
391 if( isset($atts['height']) ) {
392 $bridge_atts['height'] = $atts['height'];
393 }
394
395 if( count($bridge_atts) == 0 ) {
396 return "<!--FV Player video shortcode integration - no attributes recognized-->";
397 }
398 return flowplayer_content_handle( $bridge_atts, false, 'video' );
399 }
400
401 function fv_flowplayer_shortcode_playlist( $output ) {
402 $aArgs = func_get_args();
403 $atts = $aArgs[1];
404
405 // copy from wp-includes/media.php wp_playlist_shortcode()
406 global $post;
407 if ( ! empty( $attr['ids'] ) ) {
408 // 'ids' is explicitly ordered, unless you specify otherwise.
409 if ( empty( $attr['orderby'] ) ) {
410 $attr['orderby'] = 'post__in';
411 }
412 $attr['include'] = $attr['ids'];
413 }
414
415 $atts = shortcode_atts( array(
416 'type' => 'audio',
417 'order' => 'ASC',
418 'orderby' => 'menu_order ID',
419 'id' => $post ? $post->ID : 0,
420 'include' => '',
421 'exclude' => '',
422 'style' => 'light',
423 'tracklist' => true,
424 'tracknumbers' => true,
425 'images' => true,
426 'artists' => true
427 ), $atts, 'playlist' );
428
429 $args = array(
430 'post_status' => 'inherit',
431 'post_type' => 'attachment',
432 'post_mime_type' => $atts['type'],
433 'order' => $atts['order'],
434 'orderby' => $atts['orderby']
435 );
436
437 if( !empty($atts['include']) ) {
438 $args['include'] = $atts['include'];
439 $_attachments = get_posts( $args );
440 if( !count($_attachments) ) {
441 return false;
442 }
443
444 $attachments = array();
445 foreach( $_attachments as $key => $val ) {
446 $attachments[$val->ID] = $_attachments[$key];
447 }
448 } else {
449 return false;
450 }
451
452 $bridge_atts = array();
453 $aPlaylistItems = array();
454 $aPlaylistImages = array();
455 $aPlaylistCaptions = array();
456 $aPlaylistDurations = array();
457 $i = 0;
458 foreach ( $attachments as $attachment ) {
459 $i++;
460
461 $url = wp_get_attachment_url( $attachment->ID );
462 if( $i == 1 ) {
463 $bridge_atts['src'] = $url;
464 } else {
465 $aPlaylistItems[] = $url;
466 }
467
468 $thumb_id = get_post_thumbnail_id( $attachment->ID );
469 $src = false;
470 if( !empty( $thumb_id ) ) {
471 list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'thumbnail' );
472 }
473 if( $i == 1 ) {
474 $bridge_atts['splash'] = $src;
475 } else {
476 $aPlaylistImages[] = $src;
477 }
478
479 $aPlaylistCaptions[] = str_replace( array('"',';'), '', flowplayer::esc_caption($attachment->post_title) );
480
481 $meta = wp_get_attachment_metadata( $attachment->ID );
482 if( !empty($meta) ) {
483 if( !empty($meta['length']) ) {
484 $aPlaylistDurations[] = $meta['length'];
485 }
486 }
487
488 }
489
490
491 $bridge_atts['playlist'] = '';
492 foreach( $aPlaylistItems AS $key => $src ) {
493 $bridge_atts['playlist'] .= $src;
494 if( $aPlaylistImages[$key] ) {
495 $bridge_atts['playlist'] .= ','.$aPlaylistImages[$key];
496 }
497 $bridge_atts['playlist'] .= ';';
498 }
499 $bridge_atts['playlist'] = trim($bridge_atts['playlist'],';');
500 if( count($aPlaylistCaptions) > 1 || $atts['tracklist'] ) $bridge_atts['caption'] = implode(';',$aPlaylistCaptions);
501 $bridge_atts['durations'] = implode(';',$aPlaylistDurations);
502
503 if( $atts['tracklist'] ) {
504 $bridge_atts['listshow'] = true;
505 }
506
507 if( isset($atts['width']) ) {
508 $bridge_atts['width'] = $atts['width'];
509 }
510 if( isset($atts['height']) ) {
511 $bridge_atts['height'] = $atts['height'];
512 }
513
514 if( count($bridge_atts) == 0 ) {
515 return "<!--FV Flowplayer video shortcode integration - no attributes recognized-->";
516 }
517
518 if( !empty($atts['type']) && $atts['type'] == 'audio' ) {
519 $bridge_atts['liststyle'] = 'horizontal';
520 }
521
522 return flowplayer_content_handle( $bridge_atts, false, 'video' );
523 }
524
525 global $fv_fp;
526 if( ( empty($_POST['action']) || sanitize_key( $_POST['action'] ) != 'parse-media-shortcode' ) && ( empty($_GET['action']) || sanitize_key( $_GET['action'] ) != 'edit' ) && !empty($fv_fp->conf['integrations']['wp_core_video']) && $fv_fp->conf['integrations']['wp_core_video'] == 'true' ) {
527 add_filter( 'wp_video_shortcode_override', 'fv_flowplayer_shortcode_video', 10, 4 );
528 add_filter( 'wp_audio_shortcode_override', 'fv_flowplayer_shortcode_video', 10, 4 );
529 add_filter( 'post_playlist', 'fv_flowplayer_shortcode_playlist', 10, 2 );
530 add_filter( 'the_content', 'fv_player_handle_youtube_links' );
531 add_filter( 'the_content', 'fv_player_handle_vimeo_links' );
532 add_filter( 'embed_oembed_html', 'fv_player_handle_vimeo_links' );
533 add_filter( 'embed_oembed_html', 'fv_player_handle_youtube_links' );
534 add_filter( 'the_content', 'fv_player_handle_video_tags' );
535
536 /**
537 * Fix excerpts if video links are converted to FV Player.
538 *
539 * If FV Player is inserted using shortcode, then it's removed by core WordPress
540 * strip_shortcodes() before the excerpt is created in wp_trim_excerpt().
541 *
542 * However if we use the "Handle WordPress audio/video" setting
543 * integrations[]'wp_core_video'] the video is just a link and it does not get stripped.
544 *
545 * That way FV Player puts in the HTML code which is then removed, while keeping its text
546 * content and this shows as excerpt:
547 *
548 * "Please enable JavaScriptplay-sharp-fill 01:53 LinkEmbedCopy and paste this HTML code into your webpage to embed."
549 */
550 add_filter( 'wp_trim_words', 'fv_player_fix_wp_trim_words', 100, 4 );
551
552 function fv_player_fix_wp_trim_words( $text, $num_words, $more, $original_text ) {
553
554 if ( stripos( $original_text, '<!-- link converted by FV Player -->' ) !== false ) {
555 remove_filter( 'wp_trim_words', 'fv_player_fix_wp_trim_words', 100, 4 );
556
557 // Since the player HTML code ends with just </div> we look for the HTML comment to be able to detect where it ends.
558 $original_text = preg_replace( '~<div id="wpfp[\s\S]*?<!-- link converted by FV Player -->~', '', $original_text );
559
560 $text = wp_trim_words( $original_text, $num_words, $more );
561
562 add_filter( 'wp_trim_words', 'fv_player_fix_wp_trim_words', 100, 4 );
563 }
564
565 return $text;
566 }
567 }
568
569
570 add_filter( 'fv_flowplayer_shortcode', 'fv_flowplayer_shortcode_fix_fancy_quotes' );
571
572 function fv_flowplayer_shortcode_fix_fancy_quotes( $aArgs ) {
573
574 foreach( $aArgs AS $k => $v ) {
575 $v = preg_replace( "~^(\xe2\x80\x9c|\xe2\x80\x9d|\xe2\x80\xb3)~","", $v);
576 $v = preg_replace( "~(\xe2\x80\x9c|\xe2\x80\x9d|\xe2\x80\xb3)$~","", $v);
577
578 $aArgs[$k] = $v;
579 }
580
581 return $aArgs;
582 }
583
584
585 add_shortcode( 'fvplayer_watched', 'fvplayer_watched' );
586
587 function fvplayer_watched( $args = array() ) {
588 $args = wp_parse_args( $args, array(
589 'count' => 20,
590 'include' => 'all',
591 'post_type' => 'any',
592 'user_id' => get_current_user_id()
593 ) );
594
595 $args['full_details'] = true;
596
597 $videos = fv_player_get_user_watched_video_ids( $args );
598 if( count($videos) == 0 ) {
599 return "<p>No watched videos.</p>";
600 }
601
602 $video_ids = array_filter( array_keys($videos), 'is_numeric' );
603
604 $video_ids = array_map( 'absint', $video_ids );
605 $placeholder = implode( ', ', array_fill( 0, count( $video_ids ), '%d' ) );
606
607 global $wpdb;
608 $videos2durations = $wpdb->get_results(
609 $wpdb->prepare(
610 // $placeholders is a string of %d created above
611 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
612 "SELECT v.id AS video_id, vm.meta_value AS duration FROM {$wpdb->prefix}fv_player_videos AS v JOIN {$wpdb->prefix}fv_player_videometa AS vm ON v.id = vm.id_video WHERE v.id IN ({$placeholder}) AND vm.meta_key = 'duration'",
613 $video_ids
614 )
615 );
616
617 $html = "<ul>\n";
618 foreach( $videos AS $video_id => $data ) {
619
620 global $FV_Player_Db;
621 $objVideo = new FV_Player_Db_Video( $video_id, array(), $FV_Player_Db );
622 if( $objVideo->getTitle() ) {
623 $line = $objVideo->getTitle();
624 } else {
625 $line = $objVideo->getTitleFromSrc();
626 }
627
628 $post = get_post( $data['post_id'] );
629 if( $post ) {
630 $line .= " in <a href='".get_permalink($post)."'>".$post->post_title."</a>";
631 }
632
633 if( !empty($data['time']) ) {
634
635 foreach( $videos2durations AS $details ) {
636 if( $details->video_id == $video_id ) {
637 // In some strange cases the duration might not be set right
638 if( $data['time'] <= intval($details->duration) ) {
639 $line .= ' (<abbr title="'.esc_attr($data['message']).'">'.round( 100 * $data['time'] / intval($details->duration) ).'%</abbr>)';
640 }
641 }
642 }
643 }
644
645 $html .= "<li>".$line."</li>\n";
646 }
647 $html .= "</ul>\n";
648
649 return $html;
650 }
651