· 8 years ago · Jun 14, 2018, 10:14 AM
1<?php
2/*
3Plugin Name: VideoWhisper Live Streaming
4Plugin URI: https://videowhisper.com/?p=WordPress+Live+Streaming
5Description: <strong>Live Streaming / Broadcast Live Video</strong> solution powers a turnkey live streaming channels site including web based webcam broadcasting app and player with chat, support for external apps, 24/7 RTSP ip cameras, video playlist scheduler, video archiving & vod, HLS delivery for mobile, membership and access control, pay per view channels and tips for broadcasters.
6Version: 4.67.16
7Author: VideoWhisper.com
8Author URI: https://videowhisper.com/
9Contributors: videowhisper, VideoWhisper.com, BroadcastLiveVideo.com
10*/
11
12if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
13
14if (!class_exists("VWliveStreaming"))
15{
16 class VWliveStreaming {
17
18 function VWliveStreaming() { //constructor
19
20 }
21
22 static function install() {
23 // do not generate any output here
24
25 VWliveStreaming::channel_post();
26 flush_rewrite_rules();
27 }
28
29 function settings_link($links) {
30 $settings_link = '<a href="admin.php?page=live-streaming">'.__("Settings").'</a>';
31 array_unshift($links, $settings_link);
32 return $links;
33 }
34
35 function init()
36 {
37 //setup post
38 VWliveStreaming::channel_post();
39
40 //prevent wp from adding <p> that breaks JS
41 remove_filter ('the_content', 'wpautop');
42
43 //move wpautop filter to BEFORE shortcode is processed
44 add_filter( 'the_content', 'wpautop' , 1);
45
46 //then clean AFTER shortcode
47 add_filter( 'the_content', 'shortcode_unautop', 100 );
48
49 }
50
51
52 function plugins_loaded()
53 {
54 $plugin = plugin_basename(__FILE__);
55 add_filter("plugin_action_links_$plugin", array('VWliveStreaming','settings_link') );
56
57
58 //widget
59 wp_register_sidebar_widget('liveStreamingWidget','VideoWhisper Streaming', array('VWliveStreaming', 'widget') );
60
61 //channel page
62 add_filter('the_title', array('VWliveStreaming','the_title'));
63 add_filter('the_content', array('VWliveStreaming','channel_page'));
64 add_filter('query_vars', array('VWliveStreaming','query_vars'));
65 add_filter('pre_get_posts', array('VWliveStreaming','pre_get_posts'));
66
67 //admin channels
68 add_filter('manage_channel_posts_columns', array( 'VWliveStreaming', 'columns_head_channel') , 10);
69 add_filter( 'manage_edit-channel_sortable_columns', array('VWliveStreaming', 'columns_register_sortable') );
70 add_action('manage_channel_posts_custom_column', array( 'VWliveStreaming', 'columns_content_channel') , 10, 2);
71 add_filter( 'request', array('VWliveStreaming', 'duration_column_orderby') );
72
73 //shortcodes
74 add_shortcode('videowhisper_livesnapshots', array( 'VWliveStreaming', 'shortcode_livesnapshots'));
75 add_shortcode('videowhisper_broadcast', array( 'VWliveStreaming', 'shortcode_broadcast'));
76 add_shortcode('videowhisper_external', array( 'VWliveStreaming', 'shortcode_external'));
77 add_shortcode('videowhisper_watch', array( 'VWliveStreaming', 'shortcode_watch'));
78 add_shortcode('videowhisper_video', array( 'VWliveStreaming', 'shortcode_video'));
79 add_shortcode('videowhisper_hls', array( 'VWliveStreaming', 'shortcode_hls'));
80 add_shortcode('videowhisper_channel_manage',array( 'VWliveStreaming', 'shortcode_manage'));
81 add_shortcode('videowhisper_channels',array( 'VWliveStreaming', 'shortcode_channels'));
82
83
84 add_action( 'before_delete_post', array( $this,'before_delete_post') );
85
86 //ajax
87
88 add_action( 'wp_ajax_vwls_playlist', array('VWliveStreaming','vwls_playlist') );
89 add_action( 'wp_ajax_nopriv_vwls_playlist', array('VWliveStreaming','vwls_playlist'));
90
91 add_action( 'wp_ajax_vwls_trans', array('VWliveStreaming','vwls_trans') );
92 add_action( 'wp_ajax_nopriv_vwls_trans', array('VWliveStreaming','vwls_trans'));
93
94 add_action( 'wp_ajax_vwls_broadcast', array('VWliveStreaming','vwls_broadcast'));
95
96 add_action( 'wp_ajax_vwls', array('VWliveStreaming','vwls_calls'));
97 add_action( 'wp_ajax_nopriv_vwls', array('VWliveStreaming','vwls_calls'));
98
99 add_action( 'wp_ajax_vwls_channels', array('VWliveStreaming','vwls_channels'));
100 add_action( 'wp_ajax_nopriv_vwls_channels', array('VWliveStreaming','vwls_channels'));
101
102 //jquery for ajax
103 add_action( 'wp_enqueue_scripts', array('VWliveStreaming','wp_enqueue_scripts') );
104
105 //update page if not exists or deleted
106 $page_id = get_option("vwls_page_manage");
107 $page_id2 = get_option("vwls_page_channels");
108
109 if (!$page_id || $page_id == "-1" || !$page_id2 || $page_id2 == "-1") add_action('wp_loaded', array('VWliveStreaming','updatePages'));
110
111 //check db and update if necessary
112 $vw_db_version = "1.2";
113
114 global $wpdb;
115 $table_name = $wpdb->prefix . "vw_sessions";
116 $table_name2 = $wpdb->prefix . "vw_lwsessions";
117 $table_name3 = $wpdb->prefix . "vw_lsrooms";
118
119
120 $installed_ver = get_option( "vwls_db_version" );
121
122 if( $installed_ver != $vw_db_version )
123 {
124
125 //echo "---$installed_ver != $vw_db_version---";
126
127 $wpdb->flush();
128
129 $sql = "DROP TABLE IF EXISTS `$table_name`;
130 CREATE TABLE `$table_name` (
131 `id` int(11) NOT NULL auto_increment,
132 `session` varchar(64) NOT NULL,
133 `username` varchar(64) NOT NULL,
134 `room` varchar(64) NOT NULL,
135 `message` text NOT NULL,
136 `sdate` int(11) NOT NULL,
137 `edate` int(11) NOT NULL,
138 `status` tinyint(4) NOT NULL,
139 `type` tinyint(4) NOT NULL,
140 PRIMARY KEY (`id`),
141 KEY `status` (`status`),
142 KEY `type` (`type`),
143 KEY `room` (`room`)
144 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Video Whisper: Broadcaster Sessions - 2009@videowhisper.com' AUTO_INCREMENT=1 ;
145
146 DROP TABLE IF EXISTS `$table_name2`;
147 CREATE TABLE `$table_name2` (
148 `id` int(11) NOT NULL auto_increment,
149 `session` varchar(64) NOT NULL,
150 `username` varchar(64) NOT NULL,
151 `room` varchar(64) NOT NULL,
152 `message` text NOT NULL,
153 `sdate` int(11) NOT NULL,
154 `edate` int(11) NOT NULL,
155 `status` tinyint(4) NOT NULL,
156 `type` tinyint(4) NOT NULL,
157 PRIMARY KEY (`id`),
158 KEY `status` (`status`),
159 KEY `type` (`type`),
160 KEY `room` (`room`)
161 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Video Whisper: Subscriber Sessions - 2009@videowhisper.com' AUTO_INCREMENT=1 ;
162
163 DROP TABLE IF EXISTS `$table_name3`;
164 CREATE TABLE `$table_name3` (
165 `id` int(11) NOT NULL auto_increment,
166 `name` varchar(64) NOT NULL,
167 `owner` int(11) NOT NULL,
168 `sdate` int(11) NOT NULL,
169 `edate` int(11) NOT NULL,
170 `btime` int(11) NOT NULL,
171 `wtime` int(11) NOT NULL,
172 `rdate` int(11) NOT NULL,
173 `status` tinyint(4) NOT NULL,
174 `type` tinyint(4) NOT NULL,
175 `options` TEXT,
176 PRIMARY KEY (`id`),
177 KEY `name` (`name`),
178 KEY `status` (`status`),
179 KEY `type` (`type`),
180 KEY `owner` (`owner`)
181 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Video Whisper: Rooms - 2014@videowhisper.com' AUTO_INCREMENT=1 ;
182 ";
183
184 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
185 dbDelta($sql);
186
187 if (!$installed_ver) add_option("vwls_db_version", $vw_db_version);
188 else update_option( "vwls_db_version", $vw_db_version );
189
190 $wpdb->flush();
191 }
192
193
194 }
195 /*
196 function delTree($dir) {
197 $files = array_diff(scandir($dir), array('.','..'));
198 foreach ($files as $file) {
199 (is_dir("$dir/$file")) ? VWliveStreaming::delTree("$dir/$file") : unlink("$dir/$file");
200 }
201 return rmdir($dir);
202 }
203*/
204
205 function before_delete_post($postID)
206 {
207 $options = get_option('VWliveStreamingOptions');
208 if (get_post_type( $postID ) != $options['custom_post']) return;
209
210 $post = get_post( $postID );
211
212
213 //delete from room table
214 $room = sanitize_file_name($post->post_title);
215
216 global $wpdb;
217 $table_name3 = $wpdb->prefix . "vw_lsrooms";
218 $sql = "DELETE FROM $table_name3 where name='$room'";
219
220 $wpdb->query($sql);
221
222
223
224
225 }
226
227
228 function updatePages()
229 {
230
231 $options = get_option('VWliveStreamingOptions');
232
233 if ($options['disablePage']=='0' || $options['disablePageC']=='0')
234 {
235 //create a menu to add pages
236 $menu_name = 'VideoWhisper';
237 $menu_exists = wp_get_nav_menu_object( $menu_name );
238
239 if (!$menu_exists) $menu_id = wp_create_nav_menu($menu_name);
240 else $menu_id = $menu_exists->term_id;
241 }
242
243
244
245 //if not disabled create
246 if ($options['disablePage']=='0')
247 {
248 global $user_ID;
249 $page = array();
250 $page['post_type'] = 'page';
251 $page['post_content'] = '[videowhisper_channel_manage]';
252 $page['post_parent'] = 0;
253 $page['post_author'] = $user_ID;
254 $page['post_status'] = 'publish';
255 $page['post_title'] = 'Broadcast Live';
256 $page['comment_status'] = 'closed';
257
258 $page_id = get_option("vwls_page_manage");
259 if ($page_id>0) $page['ID'] = $page_id;
260
261 $pageid = wp_insert_post ($page);
262 update_option( "vwls_page_manage", $pageid);
263
264 $link = get_permalink( $pageid);
265
266 if ($menu_id) wp_update_nav_menu_item($menu_id, 0, array(
267 'menu-item-title' => 'Broadcast Live',
268 'menu-item-url' => $link,
269 'menu-item-status' => 'publish'));
270
271 }
272
273 if ($options['disablePageC']=='0')
274 {
275 global $user_ID;
276 $page = array();
277 $page['post_type'] = 'page';
278 $page['post_content'] = '[videowhisper_channels]';
279 $page['post_parent'] = 0;
280 $page['post_author'] = $user_ID;
281 $page['post_status'] = 'publish';
282 $page['post_title'] = 'Channels';
283 $page['comment_status'] = 'closed';
284
285 $page_id = get_option("vwls_page_channels");
286 if ($page_id>0) $page['ID'] = $page_id;
287
288 $pageid = wp_insert_post ($page);
289 update_option( "vwls_page_channels", $pageid);
290
291 $link = get_permalink( $pageid);
292
293 if ($menu_id) wp_update_nav_menu_item($menu_id, 0, array(
294 'menu-item-title' => 'Channels',
295 'menu-item-url' => $link,
296 'menu-item-status' => 'publish'));
297 }
298
299 }
300
301 function deletePages()
302 {
303 $options = get_option('VWliveStreamingOptions');
304
305 if ($options['disablePage'])
306 {
307 $page_id = get_option("vwls_page_manage");
308 if ($page_id > 0)
309 {
310 wp_delete_post($page_id);
311 update_option( "vwls_page_manage", -1);
312 }
313 }
314
315 if ($options['disablePageC'])
316 {
317 $page_id = get_option("vwls_page_channels");
318 if ($page_id > 0)
319 {
320 wp_delete_post($page_id);
321 update_option( "vwls_page_channels", -1);
322 }
323 }
324
325 }
326
327 function login_headerurl($url) {
328
329 return get_bloginfo( "url" ) . "/";
330 }
331
332 function login_enqueue_scripts() {
333
334 $options = get_option('VWliveStreamingOptions');
335
336 if ($options['loginLogo'])
337 {
338?>
339 <style type="text/css">
340 #login h1 a, .login h1 a {
341 background-image: url(<?php echo $options['loginLogo']; ?>);
342 background-size: 320px 54px;
343 width: 320px;
344 height: 54px;
345 }
346 </style>
347 <?php
348 }
349 /* else
350 {
351?>
352 <style type="text/css">
353 #login h1 a, .login h1 a {
354 background-image: url(<?php echo get_stylesheet_directory_uri(); ?>/images/site-login-logo.png);
355 padding-bottom: 30px;
356 }
357 </style>
358 <?php
359
360 }*/
361
362 }
363
364
365
366 //! set fc
367
368 //string contains any term for list (ie. banning)
369 function containsAny($name, $list)
370 {
371 $items = explode(',', $list);
372 foreach ($items as $item) if (stristr($name, trim($item))) return $item;
373
374 return 0;
375 }
376
377
378 //if any key matches any listing
379 function inList($keys, $data)
380 {
381 if (!$keys) return 0;
382 if (!$data) return 0;
383 if (strtolower(trim($data)) == 'all') return 1;
384 if (strtolower(trim($data)) == 'none') return 0;
385
386 $list=explode(",", strtolower(trim($data)));
387 if (in_array('all', $list)) return 1;
388
389 foreach ($keys as $key)
390 foreach ($list as $listing)
391 if ( strtolower(trim($key)) == trim($listing) ) return 1;
392
393 return 0;
394 }
395
396 //! room fc
397 function roomURL($room)
398 {
399
400 $options = get_option('VWliveStreamingOptions');
401
402 if ($options['channelUrl'] == 'post')
403 {
404 global $wpdb;
405
406 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . sanitize_file_name($room) . "' and post_type='channel' LIMIT 0,1" );
407
408 if ($postID) return get_post_permalink($postID);
409 }
410
411 if ($options['channelUrl'] == 'full') return site_url('/fullchannel/' . urlencode($room));
412
413 return plugin_dir_url(__FILE__) . 'ls/channel.php?n=' . urlencode(sanitize_file_name($room));
414
415 }
416
417 function count_user_posts_by_type( $userid, $post_type = 'channel' )
418 {
419 global $wpdb;
420 $where = get_posts_by_author_sql( $post_type, true, $userid );
421 $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
422 return apply_filters( 'get_usernumposts', $count, $userid );
423 }
424
425
426 //! Channel Validation
427
428 function channelInvalid( $channel, $broadcast =false)
429 {
430 //check if online channel is invalid for any reason
431
432 if (!function_exists('fm'))
433 {
434
435 function fm($t, $item = null)
436 {
437 $img = '';
438
439 if ($item)
440 {
441 $options = get_option('VWliveStreamingOptions');
442 $dir = $options['uploadsPath']. "/_thumbs";
443 $age = VWliveStreaming::format_age(time() - $item->edate);
444 $thumbFilename = "$dir/" . $item->name . ".jpg";
445
446 $noCache = '';
447 if ($age=='LIVE') $noCache='?'.((time()/10)%100);
448
449 if (file_exists($thumbFilename)) $img = '<IMG ALIGN="RIGHT" src="' . VWliveStreaming::path2url($thumbFilename) . $noCache .'" width="' . $options['thumbWidth'] . 'px" height="' . $options['thumbHeight'] . 'px"><br style="clear:both">';
450 }
451
452 //format message
453 return '<div class="w-actionbox color_alternate">'. $t . $img . '</div><br>';
454 }
455 }
456
457 $channel = sanitize_file_name($channel);
458 if (!$channel) return fm('Ðет имени канала!');
459
460 global $wpdb;
461 $table_name3 = $wpdb->prefix . "vw_lsrooms";
462
463 $sql = "SELECT * FROM $table_name3 where name='$channel'";
464 $channelR = $wpdb->get_row($sql);
465
466 if (!$channelR) if ($broadcast) return; //first broadcast
467 else return fm('Пользователь в данный момент Offline.', $channelR);
468
469 $options = get_option('VWliveStreamingOptions');
470
471 if ($channelR->type >=2) //premium
472 {
473 $poptions = VWliveStreaming::channelOptions($channelR->type, $options);
474
475 $maximumBroadcastTime = 60 * $poptions['pBroadcastTime'];
476 $maximumWatchTime = 60 * $poptions['pWatchTime'];
477
478 $canWatch = $poptions['canWatchPremium'];
479 $watchList = $poptions['watchListPremium'];
480 }
481 else
482 {
483 $maximumBroadcastTime = 60 * $options['broadcastTime'];
484 $maximumWatchTime = 60 * $options['watchTime'];
485
486 $canWatch = $options['canWatch'];
487 $watchList = $options['watchList'];
488 }
489
490 if (!$broadcast)
491 {
492 if ($maximumWatchTime) if ($channelR->wtime >= $maximumWatchTime) return fm('Превышено Ð²Ñ€ÐµÐ¼Ñ Ð¿Ñ€Ð¾Ñмотра канала!', $channelR);
493
494 }
495 else if ($maximumBroadcastTime) if ($channelR->btime >= $maximumBroadcastTime) return fm('Превышено Ð²Ñ€ÐµÐ¼Ñ Ð²ÐµÑ‰Ð°Ð½Ð¸Ñ ÐºÐ°Ð½Ð°Ð»Ð°!');
496
497
498 //user access validation
499
500 $current_user = wp_get_current_user();
501
502
503 if ($current_user->ID != 0) //logged in
504 {
505 //access keys
506 $userkeys = $current_user->roles;
507 $userkeys[] = $current_user->ID;
508 $userkeys[] = $current_user->user_email;
509 $userkeys[] = $current_user->user_login;
510 }
511 else $userkeys[] = 'Guest';
512
513 //global access settings
514 switch ($canWatch)
515 {
516 case "members":
517 if (!$current_user->ID) return fm('Только вы видите Ñту Ñтраницу!');
518 break;
519
520 case "list";
521 if (!$current_user->ID || !VWliveStreaming::inList($userkeys, $watchList))
522 return fm('ДоÑтуп, ограниченный ÑпиÑком доÑтупа!');
523 break;
524 }
525
526
527
528 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $channel . "' and post_type='channel' LIMIT 0,1" );
529
530 if ($postID) //post validations
531 {
532 //accessPassword
533 if (post_password_required($postID)) return fm('ДоÑтуп, ограниченный паролем!');
534
535 // channel access list
536 $accessList = get_post_meta($postID, 'vw_accessList', true);
537 if ($accessList) if (!VWliveStreaming::inList($userkeys, $accessList)) return fm('ДоÑтуп, ограниченный ÑпиÑком доÑтупа к каналу!');
538 //playlist active or ip camera
539 $playlistActive = get_post_meta( $postID, 'vw_playlistActive', true );
540 $ipCamera = get_post_meta( $postID, 'vw_ipCamera', true );
541 }
542
543 if (!$broadcast) if (!VWliveStreaming::userPaidAccess($current_user->ID, $postID)) return fm('ДоÑтуп ограничен: необходимо приобреÑти доÑтуп к каналу!');
544
545
546 if (!$broadcast) if (!$options['alwaysWatch']) if (!$playlistActive && !$ipCamera)
547 if (time() - $channelR->edate > 45)
548 {
549 $age = VWliveStreaming::format_age(time() - $channelR->edate);
550
551 $htmlCode ='Канал в данный момент оффлайн. ';
552
553 $eventCode = VWliveStreaming::eventInfo($postID);
554
555 if ($eventCode)
556 $eventCode = 'Обновите Ñтраницу при Ñтарте транÑлÑции!' . $eventCode;
557 else $eventCode .= ' Попробуйте позже.Ð’Ñ€ÐµÐ¼Ñ Ð¾Ñ„Ñ„Ð»Ð°Ð¹Ð½Ð°: ' . $age;
558
559 return fm($htmlCode . $eventCode, $channelR );
560 }
561
562 //valid then
563 return ;
564
565 }
566
567 //! Shortcodes
568
569
570 function getCurrentURL()
571 {
572 /*
573 $currentURL = (@$_SERVER["HTTPS"] == "on") ? "https://" : "http://";
574 $currentURL .= $_SERVER["SERVER_NAME"];
575
576 if($_SERVER["SERVER_PORT"] != "80" && $_SERVER["SERVER_PORT"] != "443")
577 {
578 $currentURL .= ":".$_SERVER["SERVER_PORT"];
579 }
580
581 $uri_parts = explode('?', $_SERVER['REQUEST_URI'], 2);
582
583 $currentURL .= $uri_parts[0];
584
585 return $currentURL;
586 */
587 global $wp;
588 return home_url(add_query_arg(array(),$wp->request));
589 }
590
591 function shortcode_manage()
592 {
593 //can user create room?
594 $options = get_option('VWliveStreamingOptions');
595
596 $maxChannels = $options['maxChannels'];
597
598 $canBroadcast = $options['canBroadcast'];
599 $broadcastList = $options['broadcastList'];
600 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
601
602 $loggedin=0;
603
604 $current_user = wp_get_current_user();
605
606 if ($current_user->$userName) $username = $current_user->$userName;
607
608 //access keys
609 $userkeys = $current_user->roles;
610 $userkeys[] = $current_user->user_login;
611 $userkeys[] = $current_user->ID;
612 $userkeys[] = $current_user->user_email;
613
614 switch ($canBroadcast)
615 {
616 case "members":
617 if ($username) $loggedin=1;
618 else $htmlCode .= "<a href=\"/\">ПожалуйÑта, войдите Ñначала или зарегиÑтрируйте аккаунт, еÑли у Ð²Ð°Ñ ÐµÐ³Ð¾ нет!</a>";
619 break;
620 case "list";
621 if ($username)
622 if (VWliveStreaming::inList($userkeys, $broadcastList)) $loggedin=1;
623 else $htmlCode .= "<a href=\"/\">$username, вам отказано в доÑтупе.</a>";
624 else $htmlCode .= "<a href=\"/\">ПожалуйÑта, войдите Ñначала или зарегиÑтрируйте аккаунт, еÑли у Ð²Ð°Ñ ÐµÐ³Ð¾ нет!</a>";
625 break;
626 }
627
628 if (!$loggedin)
629 {
630 $htmlCode .='<p>Ðта Ñтраница позволÑет Ñоздавать и управлÑть каналами Ð²ÐµÑ‰Ð°Ð½Ð¸Ñ Ð´Ð»Ñ Ð·Ð°Ñ€ÐµÐ³Ð¸Ñтрированных пользователей.</p>';
631 return $htmlCode;
632 }
633
634 $this_page = VWliveStreaming::getCurrentURL();
635 $channels_count = VWliveStreaming::count_user_posts_by_type($current_user->ID, 'channel');
636
637 //! save channel
638 $postID = $_POST['editPost']; //-1 for new
639
640 if ($postID) //create or update
641 {
642
643 $name = sanitize_file_name($_POST['newname']);
644
645 global $wpdb;
646 $existID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE `ID` <> $postID AND `post_title` = '$name' AND `post_type`='".$options['custom_post']."' LIMIT 0,1" ); //same name, diff than postID
647
648
649 if ($postID <= 0 && $channels_count >= $maxChannels)
650 $htmlCode .= "<div class='error'>Лимит доÑтупных каналов Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ автора: ". $options['maxChannels']."</div>";
651 elseif ($existID) $htmlCode .= "<div class='error'>Ðевозможно Ñоздать канал: Канал Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем '".$name."' уже Ñоздан. ПожалуйÑта укажите другое имÑ!</div>";
652 else
653 {
654 //$name = preg_replace("/[^\s\w]+/", '', $name);
655
656 if ($_POST['ipCamera']) if (!strstr($name,'.stream')) $name .= '.stream';
657
658 $comments = sanitize_file_name($_POST['newcomments']);
659
660 //accessPassword
661 $accessPassword ='';
662 if (VWliveStreaming::inList($userkeys, $options['accessPassword']))
663 {
664 $accessPassword = sanitize_text_field($_POST['accessPassword']);
665 }
666
667
668 $post = array(
669 'post_content' => sanitize_text_field($_POST['description']),
670 'post_name' => $name,
671 'post_title' => $name,
672 'post_author' => $current_user->ID,
673 'post_type' => $options['custom_post'],
674 'post_status' => 'publish',
675 'comment_status' => $comments,
676 'post_password' => $accessPassword
677 );
678
679 $category = (int) $_POST['newcategory'];
680
681 if ($postID>0)
682 {
683 $channel = get_post( $postID );
684 if ($channel->post_author == $current_user->ID) $post['ID'] = $postID; //update
685 else return "<div class='error'>Ðе удалоÑÑŒ!</div>";
686 $htmlCode .= "<div class='update'>Канал $name обновлен!</div>";
687 }
688 else $htmlCode .= "<div class='update'>Канал $name Ñоздан!</div>";
689
690 $postID = wp_insert_post($post);
691 if ($postID) wp_set_post_categories($postID, array($category));
692
693 $channels_count = VWliveStreaming::count_user_posts_by_type($current_user->ID, 'channel');
694
695
696
697 //uploadPicture
698 if (VWliveStreaming::inList($userkeys, $options['uploadPicture']))
699 {
700
701 if ($filename = $_FILES['uploadPicture']['tmp_name'])
702 {
703
704 $ext = strtolower(pathinfo($_FILES['uploadPicture']['name'], PATHINFO_EXTENSION));
705 $allowed = array('jpg','jpeg','png','gif');
706 if (!in_array($ext,$allowed)) return 'Файл не поддерживаетÑÑ!';
707
708 list($width, $height) = getimagesize($filename);
709
710 if ($width && $height)
711 {
712
713 //delete previous image(s)
714 VWliveStreaming::delete_associated_media($postID, true);
715
716 //$htmlCode .= 'Generating thumb... ';
717 $thumbWidth = $options['thumbWidth'];
718 $thumbHeight = $options['thumbHeight'];
719
720 $src = imagecreatefromstring(file_get_contents($filename));
721 $tmp = imagecreatetruecolor($thumbWidth, $thumbHeight);
722
723 $dir = $options['uploadsPath']. "/_pictures";
724 if (!file_exists($dir)) mkdir($dir);
725
726 $room_name = sanitize_file_name($channel->post_title);
727 $thumbFilename = "$dir/$room_name.jpg";
728 imagecopyresampled($tmp, $src, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $width, $height);
729 imagejpeg($tmp, $thumbFilename, 95);
730
731 //detect tiny images without info
732 if (filesize($thumbFilename)>5000) $picType = 1;
733 else $picType = 2;
734
735 //update post meta
736 if ($postID)
737 {
738 update_post_meta($postID, 'hasPicture', $picType);
739 update_post_meta($postID, 'hasSnapshot', 1); //so it gets listed
740 update_post_meta($postID, 'edate', time() - 60);
741 }
742
743 //$htmlCode .= ' Updating picture... ' . $thumbFilename;
744
745 //update post image
746 if (!function_exists('wp_generate_attachment_metadata')) require ( ABSPATH . 'wp-admin/includes/image.php' );
747
748 $wp_filetype = wp_check_filetype(basename($thumbFilename), null );
749
750 $attachment = array(
751 'guid' => $thumbFilename,
752 'post_mime_type' => $wp_filetype['type'],
753 'post_title' => $room_name,
754 'post_content' => '',
755 'post_status' => 'inherit'
756 );
757
758 $attach_id = wp_insert_attachment( $attachment, $thumbFilename, $postID );
759 set_post_thumbnail($postID, $attach_id);
760
761
762
763
764 //update post imaga data
765 $attach_data = wp_generate_attachment_metadata( $attach_id, $thumbFilename );
766 wp_update_attachment_metadata( $attach_id, $attach_data );
767
768
769 }
770 }
771
772 $showImage = sanitize_file_name($_POST['showImage']);
773 update_post_meta($postID, 'showImage', $showImage);
774
775 }
776
777 if (VWliveStreaming::inList($userkeys, $options['eventDetails']))
778 {
779 update_post_meta($postID, 'eventTitle', sanitize_text_field($_POST['eventTitle']));
780 update_post_meta($postID, 'eventStart', sanitize_text_field($_POST['eventStart']));
781 update_post_meta($postID, 'eventEnd', sanitize_text_field($_POST['eventEnd']));
782 update_post_meta($postID, 'eventStartTime', sanitize_text_field($_POST['eventStartTime']));
783 update_post_meta($postID, 'eventEndTime', sanitize_text_field($_POST['eventEndTime']));
784 update_post_meta($postID, 'eventDescription', sanitize_text_field($_POST['eventDescription']));
785 }
786
787 //disable sidebar for themes that support this
788 update_post_meta($postID, 'disableSidebar', true);
789
790 //transcode
791 if (VWliveStreaming::inList($userkeys, $options['transcode']))
792 update_post_meta($postID, 'vw_transcode', '1');
793 else update_post_meta($postID, 'vw_transcode', '0');
794
795
796 //logoHide
797 if (VWliveStreaming::inList($userkeys, $options['logoHide']))
798 update_post_meta($postID, 'vw_logo', 'hide');
799 else update_post_meta($postID, 'vw_logo', 'global');
800
801 //logoCustom
802 if (VWliveStreaming::inList($userkeys, $options['logoCustom']))
803 {
804 $logoImage = sanitize_text_field($_POST['logoImage']);
805 update_post_meta($postID, 'vw_logoImage', $logoImage);
806
807 $logoLink = sanitize_text_field($_POST['logoLink']);
808 update_post_meta($postID, 'vw_logoLink', $logoLink);
809
810 update_post_meta($postID, 'vw_logo', 'custom');
811 }
812
813 //adsHide
814 if (VWliveStreaming::inList($userkeys, $options['adsHide']))
815 update_post_meta($postID, 'vw_ads', 'hide');
816 else update_post_meta($postID, 'vw_ads', 'global');
817
818
819 //adsCustom
820 if (VWliveStreaming::inList($userkeys, $options['adsCustom']))
821 {
822 $logoImage = sanitize_text_field($_POST['adsServer']);
823 update_post_meta($postID, 'vw_adsServer', $logoImage);
824
825 update_post_meta($postID, 'vw_ads', 'custom');
826 }
827
828 //ipCameras
829 if (VWliveStreaming::inList($userkeys, $options['ipCameras']))
830 {
831 if (file_exists($options['streamsPath']))
832 {
833 $ipCamera = sanitize_text_field($_POST['ipCamera']);
834
835
836 if ($ipCamera)
837 {
838 list($firstWord) = explode(':', $ipCamera);
839 if (!in_array($firstWord, array('rtsp','udp','rtmp','rtmps','wowz','wowzs', 'http', 'https')))
840 {
841 $htmlCode .= "<BR>Формат указан неверно ($firstWord). ИÑпользуйте протоколы: rtsp://, udp://, rtmp://, rtmps://, wowz://, wowzs://, http://, https:// .";
842 $ipCamera = '';
843
844 }
845 }
846
847 if ($ipCamera) if (!strstr($name,'.stream'))
848 {
849 $htmlCode .= "<BR>Channel name must end in .stream when re-streaming!";
850 $ipCamera = '';
851 }
852
853 $file = $options['streamsPath'] . '/' . $name;
854
855 if ($ipCamera)
856 {
857
858 $myfile = fopen($file, "w");
859 if ($myfile)
860 {
861 fwrite($myfile, $ipCamera);
862 fclose($myfile);
863 $htmlCode .= '<BR>Stream file created/updated:<br>' . $name . ' = ' . $ipCamera;
864 }
865 else
866 {
867 $htmlCode .= '<BR>Could not write file: '. $file;
868 $ipCamera = '';
869 }
870
871 }
872 else
873 {
874 if (file_exists($file))
875 {
876 unlink($file);
877 $htmlCode .= '<BR>Stream file removed: '. $file;
878 }
879 }
880
881 update_post_meta($postID, 'vw_ipCamera', $ipCamera);
882 }
883 else
884 {
885 $htmlCode .= '<BR>Stream file could not be setup. Streams folder not found: '. $options['streamsPath'];
886 }
887 }
888 else update_post_meta($postID, 'vw_ipCamera', '');
889
890 //schedulePlaylists
891 if (!$options['playlists'] || !VWliveStreaming::inList($userkeys, $options['schedulePlaylists']))
892 update_post_meta($postID, 'vw_playlistActive', '');
893
894
895 //permission lists: access, chat, write, participants, private
896 foreach (array('access','chat','write','participants','privateChat') as $field)
897 if (VWliveStreaming::inList($userkeys, $options[$field .'List']))
898 {
899 $value = sanitize_text_field($_POST[$field . 'List']);
900 update_post_meta($postID, 'vw_'.$field.'List', $value);
901 }
902
903
904 //accessPrice
905 if (VWliveStreaming::inList($userkeys, $options['accessPrice']))
906 {
907 $accessPrice = round($_POST['accessPrice'],2);
908 update_post_meta($postID, 'vw_accessPrice', $accessPrice);
909
910 $mCa = array(
911 'status' => 'enabled',
912 'price' => $accessPrice,
913 'button_label' => 'Buy Access Now', // default button label
914 'expire' => 0 // default no expire
915 );
916
917 if ($options['mycred'] && $accessPrice) update_post_meta($postID, 'myCRED_sell_content', $mCa);
918 else delete_post_meta($postID, 'myCRED_sell_content');
919
920 }
921
922 }
923
924 }
925
926 //! Playlist Edit
927 if ( (int) $editPlaylist = $_GET['editPlaylist'])
928 {
929
930 $channel = get_post( $editPlaylist );
931 if (!$channel)
932 {
933 return "Канал не найден!";
934 }
935
936 if ($channel->post_author != $current_user->ID)
937 {
938 return "ДоÑтуп ограничен!";
939 }
940
941 $stream = sanitize_file_name($channel->post_title);
942
943 wp_enqueue_script( 'jquery');
944 wp_enqueue_script( 'jquery-ui-core');
945 wp_enqueue_script( 'jquery-ui-widget');
946 wp_enqueue_script( 'jquery-ui-dialog');
947
948 //wp_enqueue_script( 'jquery-ui-datepicker');
949
950
951
952 //css
953 wp_enqueue_style( 'jtable-green', plugin_dir_url( __FILE__ ) . '/scripts/jtable/themes/lightcolor/green/jtable.min.css');
954
955 wp_enqueue_style( 'jtable-flick', plugin_dir_url( __FILE__ ) . '/scripts/jtable/themes/flick/jquery-ui.min.css');
956
957 //js
958 wp_enqueue_script( 'jquery-ui-jtable', plugin_dir_url( __FILE__ ) . '/scripts/jtable/jquery.jtable.min.js', array('jquery-ui-core', 'jquery-ui-widget', 'jquery-ui-dialog'));
959
960 // wp_enqueue_script( 'jtable', plugin_dir_url( __FILE__ ) . '/scripts/jtable/jquery.jtable.js', array('jquery-ui-core', 'jquery-ui-widget', 'jquery-ui-dialog'));
961
962 $ajaxurl = admin_url() . 'admin-ajax.php?action=vwls_playlist&channel=' . $editPlaylist;
963
964
965 $htmlCode .= '<h3>Playlist Scheduler: ' .$channel->post_title.'</h3>';
966
967 $currentDate = date('Y-m-j h:i:s');
968
969 if ($_POST['updatePlaylist'])
970 {
971 update_post_meta( $editPlaylist, 'vw_playlistActive', $playlistActive = (int) $_POST['playlistActive']);
972 VWliveStreaming::updatePlaylist($stream, $playlistActive);
973 update_post_meta( $editPlaylist, 'vw_playlistUpdated', time());
974 }
975
976 //playlistActive
977 $value = get_post_meta( $editPlaylist, 'vw_playlistActive', true );
978
979 $activeCode .= '<select id="playlistActive" name="playlistActive">';
980 $activeCode .= '<option value="0" ' . (!$value ? 'selected' : '') . '>Inactive</option>';
981 $activeCode .= '<option value="1" ' . ($value ? 'selected' : '') . '>Active</option>';
982 $activeCode .= '</select>';
983
984 $value = get_post_meta( $editPlaylist, 'vw_playlistUpdated', true );
985 $playlistUpdated = date('Y-m-j h:i:s', (int) $value);
986
987 $value = get_post_meta( $editPlaylist, 'vw_playlistLoaded', true );
988 $playlistLoaded = date('Y-m-j h:i:s', (int) $value);
989
990
991 $playlistPage = add_query_arg(array('editPlaylist'=>$editPlaylist), $this_page);
992
993 $videosImg = plugin_dir_url( __FILE__ ) . 'scripts/jtable/themes/lightcolor/edit.png';
994
995 $channelURL = get_permalink($channel->ID);
996
997 //! jTable
998 $htmlCode .= <<<HTMLCODE
999<form method="post" action="$playlistPage" name="adminForm" class="w-actionbox">
1000Playlist Status: $activeCode
1001<input class="videowhisperButtonLS g-btn type_primary" type="submit" name="button" id="button" value="Update" />
1002<input type="hidden" name="updatePlaylist" id="updatePlaylist" value="$editPlaylist" />
1003<BR>After editing playlist contents, update it to apply changes. Last Updated: $playlistUpdated
1004<BR>Playlist is loaded with web application (on access) and reloaded if necessary when users access <a href='$channelURL'>watch interface</a> (last time reloaded: $playlistLoaded).
1005</form>
1006<BR>
1007First create a Schedule (Add new record), then Edit Videos (Add new record under Videos):
1008 <div id="PlaylistTableContainer" style="width: 600px;"></div>
1009 <script type="text/javascript">
1010
1011 jQuery(document).ready(function () {
1012
1013 //Prepare jTable
1014 jQuery('#PlaylistTableContainer').jtable({
1015 title: 'Playlist Contents for Channel',
1016 defaultSorting: 'Order ASC',
1017 toolbar: {hoverAnimation: false},
1018 actions: {
1019 listAction: '$ajaxurl&task=list',
1020 createAction: '$ajaxurl&task=create',
1021 updateAction: '$ajaxurl&task=update',
1022 deleteAction: '$ajaxurl&task=delete'
1023 },
1024 fields: {
1025 Id: {
1026 key: true,
1027 create: false,
1028 edit: false,
1029 list: false,
1030 },
1031 //CHILD TABLE DEFINITION
1032 Videos: {
1033 title: 'Videos',
1034 sorting: false,
1035 edit: false,
1036 create: false,
1037 display: function (playlist) {
1038 //Create an image that will be used to open child table
1039 var vButton = jQuery('<IMG src="$videosImg" /><I>Edit Videos</I>');
1040 //Open child table when user clicks the image
1041 vButton.click(function () {
1042 jQuery('#PlaylistTableContainer').jtable('openChildTable',
1043 vButton.closest('tr'),
1044 {
1045 title: 'Videos for Schedule ' + playlist.record.Scheduled,
1046 actions: {
1047 listAction: '$ajaxurl&task=videolist&item=' + playlist.record.Id,
1048 deleteAction: '$ajaxurl&task=videoremove&item=' + playlist.record.Id,
1049 updateAction: '$ajaxurl&task=videoupdate',
1050 createAction: '$ajaxurl&task=videoadd'
1051 },
1052 fields: {
1053 ItemId: {
1054 type: 'hidden',
1055 defaultValue: playlist.record.Id
1056 },
1057 Id: {
1058 key: true,
1059 create: false,
1060 edit: false,
1061 list: false
1062 },
1063 Video: {
1064 title: 'Video',
1065 options: '$ajaxurl&task=source',
1066 sorting: false
1067 },
1068 Start: {
1069 title: 'Start',
1070 defaultValue: '0',
1071 },
1072 Length: {
1073 title: 'Length',
1074 defaultValue: '-1',
1075 },
1076 Order: {
1077 title: 'Order',
1078 defaultValue: '0',
1079 },
1080 }
1081 }, function (data) { //opened handler
1082 data.childTable.jtable('load');
1083 });
1084 });
1085 //Return image to show on the person row
1086 return vButton;
1087 }
1088
1089 },
1090 Scheduled: {
1091 title: 'Scheduled',
1092 defaultValue: '$currentDate',
1093 sorting: false
1094 },
1095 Repeat: {
1096 title: 'Repeat',
1097 type: 'checkbox',
1098 defaultValue: '0',
1099 values: { '0' : 'Disabled', '1' : 'Enabled' },
1100 sorting: false
1101 },
1102 Order: {
1103 title: 'Order',
1104 defaultValue: '0',
1105 }
1106 }
1107 });
1108
1109 //Load item list from server
1110 jQuery('#PlaylistTableContainer').jtable('load');
1111 });
1112 </script>
1113 <STYLE>
1114 .ui-front
1115 {
1116 z-index: 1000;
1117 }
1118 </STYLE>
1119
1120HTMLCODE;
1121
1122 $htmlCode .= '<BR>Schedule playlist items as: Year-Month-Day Hours:Minutes:Seconds. In example, current server time: ' . date('Y-m-j h:i:s');
1123 if (date_default_timezone_get()) {
1124 $htmlCode .= '<BR>If the schedule time is in the past, each video is loaded in order and immediately replaces the previous video for the stream. Repeat will cause that videos to repeat in loop. Scheduling must be based on server timezone: ' . date_default_timezone_get() . '<br />';
1125 }
1126 }
1127
1128 //! list channels
1129 if (!$_GET['editChannel'] && !$_GET['editPlaylist'])
1130 {
1131
1132 $args = array(
1133 'author' => $current_user->ID,
1134 'orderby' => 'post_date',
1135 'order' => 'DESC',
1136 'post_type' => 'channel',
1137 );
1138
1139 $channels = get_posts( $args );
1140
1141
1142 $htmlCode .= apply_filters("vw_ls_manage_channels_head", '');
1143 $htmlCode .= "<h3>Мои каналы ($channels_count/$maxChannels)</h3>";
1144
1145 if ($channels_count <$maxChannels)
1146 $htmlCode .= '<a href="'. add_query_arg( 'editChannel', -1, $this_page).'" class="videowhisperButtonLS g-btn type_yellow"> + Создать новый канал</a>';
1147
1148 if (count($channels))
1149 {
1150 global $wpdb;
1151 $table_name3 = $wpdb->prefix . "vw_lsrooms";
1152
1153 require_once( ABSPATH . 'wp-admin/includes/image.php' );
1154
1155 $htmlCode .= '<table>';
1156
1157 foreach ($channels as $channel)
1158 {
1159 $postID = $channel->ID;
1160
1161 $stream = sanitize_file_name(get_the_title($postID));
1162
1163 //update room
1164 //setup/update channel, premium & time reset
1165
1166 $room = $stream;
1167 $ztime = time();
1168
1169 $poptions = VWliveStreaming::premiumOptions($userkeys, $options);
1170
1171 if ($poptions) //premium room
1172 {
1173 $rtype = 1 + $poptions['level'];
1174 $maximumBroadcastTime = 60 * $poptions['pBroadcastTime'];
1175 $maximumWatchTime = 60 * $poptions['pWatchTime'];
1176
1177 // $camBandwidth=$options['pCamBandwidth'];
1178 // $camMaxBandwidth=$options['pCamMaxBandwidth'];
1179 // if (!$options['pLogo']) $options['overLogo']=$options['overLink']='';
1180
1181 }else
1182 {
1183 $rtype=1;
1184 //$camBandwidth=$options['camBandwidth'];
1185 //$camMaxBandwidth=$options['camMaxBandwidth'];
1186
1187 $maximumBroadcastTime = 60 * $options['broadcastTime'];
1188 $maximumWatchTime = 60 * $options['watchTime'];
1189 }
1190
1191
1192 $sql = "SELECT * FROM $table_name3 where owner='$username' and name='$room'";
1193 $channelR = $wpdb->get_row($sql);
1194
1195 if (!$channelR)
1196 $sql="INSERT INTO `$table_name3` ( `owner`, `name`, `sdate`, `edate`, `rdate`,`status`, `type`) VALUES ('$username', '$room', $ztime, $ztime, $ztime, 0, $rtype)";
1197 elseif ($options['timeReset'] && $channelR->rdate < $ztime - $options['timeReset']*24*3600) //time to reset in days
1198 $sql="UPDATE `$table_name3` set type=$rtype, rdate=$ztime, wtime=0, btime=0 where owner='$username' and name='$room'";
1199 else
1200 $sql="UPDATE `$table_name3` set type=$rtype where owner='$username' and name='$room'";
1201
1202 $wpdb->query($sql);
1203
1204 //update thumb
1205 $dir = $options['uploadsPath']. "/_snapshots";
1206 $thumbFilename = "$dir/$stream.jpg";
1207
1208 //ip camera or playlist : update snapshot
1209 if (get_post_meta( $postID, 'vw_ipCamera', true ) || get_post_meta( $postID, 'vw_playlistActive', true ))
1210 {
1211 VWliveStreaming::streamSnapshot($stream, true);
1212 //$htmlCode .= 'Updating IP Cam Snapshot: ' . $stream;
1213 }
1214
1215
1216
1217
1218 //only if snapshot exists but missing post thumb (not uploaded or generated previously)
1219 if ( file_exists($thumbFilename) && !get_post_thumbnail_id( $postID ))
1220 {
1221 if ( !get_post_thumbnail_id( $postID ) ) //insert
1222 {
1223 $wp_filetype = wp_check_filetype(basename($thumbFilename), null );
1224
1225 $attachment = array(
1226 'guid' => $thumbFilename,
1227 'post_mime_type' => $wp_filetype['type'],
1228 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $thumbFilename, ".jpg" ) ),
1229 'post_content' => '',
1230 'post_status' => 'inherit'
1231 );
1232
1233 $attach_id = wp_insert_attachment( $attachment, $thumbFilename, $postID );
1234 set_post_thumbnail($postID, $attach_id);
1235 }
1236 else //update
1237 {
1238 $attach_id = get_post_thumbnail_id($postID );
1239 $thumbFilename = get_attached_file($attach_id);
1240 }
1241
1242 //cleanup any relics
1243 if ($postID && $attach_id) VWliveStreaming::delete_associated_media($postID, false, $attach_id);
1244
1245 //update
1246 $attach_data = wp_generate_attachment_metadata( $attach_id, $thumbFilename );
1247 wp_update_attachment_metadata( $attach_id, $attach_data );
1248 }
1249
1250
1251 //snapshot
1252 $dir = $options['uploadsPath']. "/_snapshots";
1253 $thumbFilename = "$dir/$stream.jpg";
1254
1255 $showImage=get_post_meta( $postID, 'showImage', true );
1256
1257 if (!file_exists($thumbFilename) || $showImage =='all') //show thumb instead
1258 {
1259 $attach_id = get_post_thumbnail_id($postID );
1260 if ($attach_id) $thumbFilename = get_attached_file($attach_id);
1261 }
1262
1263 $noCache = '';
1264 if ($age=='LIVE') $noCache='?'.((time()/10)%100);
1265 if (file_exists($thumbFilename)) $thumbCode = '<IMG src="' . VWliveStreaming::path2url($thumbFilename) . $noCache .'" width="' . $options['thumbWidth'] . 'px" height="' . $options['thumbHeight'] . 'px">';
1266 else $thumbCode = '<IMG SRC="' . plugin_dir_url(__FILE__). 'screenshot-3.jpg" width="' . $options['thumbWidth'] . 'px" height="' . $options['thumbHeight'] . 'px">';
1267
1268 //channel url
1269 $url = get_permalink($postID);
1270
1271
1272 $htmlCode .= '<tr><td><a href="' . $url . '"><h4>' . $channel->post_title . '</h4>' . $thumbCode . '</a>';
1273
1274
1275 //Features Info
1276
1277
1278 //transcode quick update (if settigns changed for role)
1279 $vw_transcode = get_post_meta( $postID, 'vw_transcode', true );
1280 if (VWliveStreaming::inList($userkeys, $options['transcode'])) $new_vw_transcode = 1;
1281 else $new_vw_transcode =0;
1282 if ($vw_transcode != $new_vw_transcode) update_post_meta($postID, 'vw_transcode', $new_vw_transcode);
1283
1284
1285
1286 if ($channelR)
1287 $htmlCode .= '<br> ТранÑлÑциÑ: ' . VWliveStreaming::format_time($channelR->btime) . ' / ' . VWliveStreaming::format_time($maximumBroadcastTime) . '<br> ПроÑмотрено: ' . VWliveStreaming::format_time($channelR->wtime) . ' / ' . VWliveStreaming::format_time($maximumWatchTime);
1288
1289 $htmlCode .= '<br> Тип: ' . ($channelR->type>1?'Премиум '. ($channelR->type-1):'ÐžÐ±Ñ‹Ñ‡Ð½Ð°Ñ '. $channelR->type);
1290
1291
1292 if ($options['transcoding']) $htmlCode .= '<br> Кодирование: ' . ($vw_transcode?'Вкл.':'Выкл.');
1293
1294
1295
1296
1297 if (get_post_meta( $postID, 'vw_ipCamera', true )) $htmlCode .= '<br>IP Camera';
1298 if (get_post_meta( $postID, 'vw_playlistActive', true )) $htmlCode .= '<br>Playlist Scheduled';
1299
1300
1301 foreach (array('access','chat','write','participants','privateChat') as $field)
1302 if ($value = get_post_meta($postID, 'vw_'.$field.'List', true))
1303 $htmlCode .= '<br>' . ucwords($field) . ': ' . $value;
1304
1305
1306
1307 $htmlCode .= '</td>';
1308 $htmlCode .= '<td width="210px">';
1309
1310
1311
1312
1313
1314 $htmlCode .= '<BR> <a class="videowhisperButtonLS g-btn type_yellow" href="' . add_query_arg( 'editChannel', $channel->ID, $this_page) . '">ÐаÑтройки</a>';
1315
1316 if ($options['playlists'])
1317 if (VWliveStreaming::inList($userkeys, $options['schedulePlaylists']))
1318 $htmlCode .= '<BR> <a class="videowhisperButtonLS g-btn type_yellow" href="' . add_query_arg( 'editPlaylist', $channel->ID, $this_page) . '">ВоÑпроизведениÑ</a>';
1319
1320 $htmlCode .= '</td></tr>';
1321 //filter under channel
1322 $htmlCode .= '<tr><td colspan=2>' . apply_filters("vw_ls_manage_channel", '', $channel->ID) . '</td></tr>';
1323
1324 }
1325 $htmlCode .= '</table>';
1326
1327 $htmlCode .= '<small>Только админиÑтратор может удалÑть каналы.</small>';
1328
1329 }
1330 else
1331 $htmlCode .= "<div class='warning'>У Ð²Ð°Ñ Ð½ÐµÑ‚ доÑтупных каналов!</div>";
1332
1333 $htmlCode .= apply_filters("vw_ls_manage_channels_foot", '');
1334 }
1335
1336 //! Edit Channel Form
1337
1338 $editPost = (int) $_GET['editChannel'];
1339
1340
1341 //setup
1342 $editPost = (int) $_GET['editChannel'];
1343
1344 if ($editPost)
1345 {
1346 $newCat = -1;
1347
1348 if ($editPost > 0)
1349 {
1350 $channel = get_post( $editPost );
1351 if ($channel->post_author != $current_user->ID) return "<div class='error'>Ðет доÑтупа!</div>";
1352
1353 $newDescription = $channel->post_content;
1354 $newName = $channel->post_title;
1355 $newComments = $channel->comment_status;
1356
1357 $cats = wp_get_post_categories( $editPost);
1358 if (count($cats)) $newCat = array_pop($cats);
1359 }
1360
1361 if ($editPost<1)
1362 {
1363 $editPost = -1;
1364
1365 $newTitle = 'New';
1366
1367 $newName = sanitize_file_name($username);
1368 if ($channels_count) $newName .= '_' . base_convert(time()-1225000000,10,36);
1369 $nameField = 'text';
1370 $newNameL = '';
1371 }
1372 else
1373 {
1374 $nameField = 'hidden';
1375 $newNameL = $newName;
1376 }
1377
1378 $commentsCode = '';
1379 $commentsCode .= '<select id="newcomments" name="newcomments">';
1380 $commentsCode .= '<option value="closed" ' . ($newComments=='closed'?'selected':'') . '>Закрыты</option>';
1381 $commentsCode .= '<option value="open" ' . ($newComments=='open'?'selected':'') . '>Открыты</option>';
1382 $commentsCode .= '</select>';
1383
1384
1385 $categories = wp_dropdown_categories('show_count=1&echo=0&name=newcategory&hide_empty=0&selected=' . $newCat);
1386
1387 //! channel features
1388 $extraRows = '';
1389
1390 //accessPassword
1391 if (VWliveStreaming::inList($userkeys, $options['accessPassword']))
1392 {
1393 if ($editPost) $value = $channel->post_password;
1394 else $value = '';
1395
1396 $extraRows .= '<tr><td>УÑтановить пароль</td><td><input size=16 name="accessPassword" id="accessPassword" value="' . $value . '"><BR>Пароль необходим Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð²Ð°Ñ‚Ð½Ð¾Ð³Ð¾ проÑмотра. ОÑтавьте пуÑтым, еÑли Ñтого не требуетÑÑ.</td></tr>';
1397 }
1398
1399 //permission lists
1400 $permInfo = array(
1401 'access'=>'Открыть канал.',
1402 'chat'=>'Показать публичный чат.',
1403 'write'=>'ПиÑать в публичный чат.',
1404 'participants'=>'Смотреть доÑтупный ÑпиÑок.',
1405 'privateChat'=>'Приватный чат Ñо ÑпиÑком пользователей.'
1406 );
1407
1408 foreach (array('access','chat','write','participants','privateChat') as $field)
1409 if (VWliveStreaming::inList($userkeys, $options[$field . 'List']))
1410 {
1411 if ($editPost) $value = get_post_meta( $editPost, 'vw_'.$field.'List', true );
1412 else $value = '';
1413
1414 $extraRows .= '<tr><td>СпиÑок доÑтупа</td><td><textarea rows=2 cols=60 name="'.$field.'List" id="'.$field.'List">' . $value . '</textarea><BR>' .$permInfo[$field]. ' Создайте ÑпиÑок пользователей по логинам, разделенный запÑтыми. ОÑтавьте пуÑтым, чтобы разрешить вÑем.</td></tr>';
1415 }
1416
1417 //accessPrice
1418 if (VWliveStreaming::inList($userkeys, $options['accessPrice']))
1419 {
1420 if ($editPost>0) $value = get_post_meta( $editPost, 'vw_accessPrice', true );
1421 else $value = '0.00';
1422
1423 $extraRows .= '<tr><td>ДоÑтуп</td><td><input size=5 name="accessPrice" id="accessPrice" value="' . $value . '"><BR>ДоÑтуп к проÑмотру. ПоÑтавьте 0 - Ð´Ð»Ñ Ð¾Ð±Ñ‰ÐµÐ³Ð¾ доÑтупа.</td></tr>';
1424 }
1425
1426 //logoCustom
1427 if (VWliveStreaming::inList($userkeys, $options['logoCustom']))
1428 {
1429 if ($editPost>0) $value = get_post_meta( $editPost, 'vw_logoImage', true );
1430 else $value = $options['overLogo'];
1431
1432 $extraRows .= '<tr><td>Лого</td><td><input size=64 name="logoImage" id="logoImage" value="' . $value . '"><BR>Лого канала (формат .png). ОÑтавьте пуÑтым, чтобы пропуÑтить.</td></tr>';
1433 if ($editPost>0) $value = get_post_meta( $editPost, 'vw_logoLink', true );
1434 else $value = $options['overLink'];
1435
1436 $extraRows .= '<tr><td>Лого URL</td><td><input size=64 name="logoLink" id="logoImage" value="' . $value . '"><BR>СÑылка при нажатии на Лого.</td></tr>';
1437 }
1438
1439
1440 //ipCameras
1441 if (VWliveStreaming::inList($userkeys, $options['ipCameras']))
1442 {
1443 if ($editPost>0) $value = get_post_meta( $editPost, 'vw_ipCamera', true );
1444 else $value = '';
1445
1446 $extraRows .= '<tr><td>Доп.Камера</td><td><input size=64 name="ipCamera" id="ipCamera" value="' . $value . '"><BR> ÐаÑтройки Ð´Ð»Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратора.</td></tr>';
1447 }
1448
1449
1450
1451 //adsCustom
1452 if (VWliveStreaming::inList($userkeys, $options['adsCustom']))
1453 {
1454 if ($editPost>0) $value = get_post_meta( $editPost, 'vw_adsServer', true );
1455 else $value = $options['adServer'];
1456
1457 $extraRows .= '<tr><td>Доп.Сервер</td><td><input size=64 name="adsServer" id="adsServer" value="' . $value . '"><BR> ÐаÑтройки Ð´Ð»Ñ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратора.</td></tr>';
1458 }
1459
1460 //uploadPicture
1461 if (VWliveStreaming::inList($userkeys, $options['uploadPicture']))
1462 {
1463
1464 $extraRows .= '<tr><td>Изображение</td><td><input type="file" name="uploadPicture" id="uploadPicture"><BR> Обновить изображение канала.</td></tr>';
1465
1466
1467 $value=get_post_meta( $editPost, 'showImage', true );
1468
1469 $extraRows .= '<tr><td>Показать изображение</td><td><select name="showImage" id="showImage">';
1470 $extraRows .= '<option value="event" '.($value=='event'?'selected':'').'>Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ Ñобытии</option>';
1471 $extraRows .= '<option value="all" '.($value=='all'?'selected':'').'>Везде</option>';
1472 $extraRows .= '<option value="no" '.($value=='no'?'selected':'').'>Ðе показывать</option>';
1473 $extraRows .= '</select><BR>ÐаÑтройка отображениÑ.</td></tr>';
1474 }
1475
1476 if (VWliveStreaming::inList($userkeys, $options['eventDetails']))
1477 {
1478 if ($editPost>0) $value = get_post_meta( $editPost, 'eventTitle', true );
1479
1480 $extraRows .= '<tr><td>Event Title</td><td><input size=64 name="eventTitle" id="eventTitle" value="' . $value . '"></td></tr>';
1481
1482 if ($editPost>0) $value = get_post_meta( $editPost, 'eventStart', true );
1483 if ($editPost>0) $valueTime = get_post_meta( $editPost, 'eventStartTime', true );
1484 $extraRows .= '<tr><td>Ðачало потока</td><td>Date: <input size=32 name="eventStart" id="eventStart" value="' . $value . '"> Time: <input size=32 name="eventStartTime" id="eventStartTime" value="' . $valueTime . '"></td></tr>';
1485
1486 if ($editPost>0) $value = get_post_meta( $editPost, 'eventEnd', true );
1487 if ($editPost>0) $valueTime = get_post_meta( $editPost, 'eventEndTime', true );
1488 $extraRows .= '<tr><td>Конец потока</td><td>Date: <input size=32 name="eventEnd" id="eventEnd" value="' . $value . '"> Time: <input size=32 name="eventEndTime" id="eventEndTime" value="' . $valueTime . '"></td></tr>';
1489
1490 if ($editPost>0) $value = get_post_meta( $editPost, 'eventDescription', true );
1491 $extraRows .= '<tr><td> ОпиÑание потока</td><td><textarea rows=3 cols=60 name="eventDescription" id="eventDescription">' . $value . '</textarea><br> ОпиÑание когда транÑлÑÑ†Ð¸Ñ Ð¾Ñ„Ñ„Ð»Ð°Ð¹Ð½.</td></tr>';
1492
1493 }
1494
1495
1496 if ($editPost > 0 || $channels_count < $maxChannels)
1497 $htmlCode .= <<<HTMLCODE
1498<script language="JavaScript">
1499 function censorName()
1500 {
1501 document.adminForm.room.value = document.adminForm.room.value.replace(/^[\s]+|[\s]+$/g, '');
1502 document.adminForm.room.value = document.adminForm.room.value.replace(/[^0-9a-zA-Z_\-]+/g, '-');
1503 document.adminForm.room.value = document.adminForm.room.value.replace(/\-+/g, '-');
1504 document.adminForm.room.value = document.adminForm.room.value.replace(/^\-+|\-+$/g, '');
1505 if (document.adminForm.room.value.length>0) return true;
1506 else
1507 {
1508 alert("ТребуетÑÑ Ð¸Ð¼Ñ ÐºÐ°Ð½Ð°Ð»Ð°!");
1509 return false;
1510 }
1511 }
1512</script>
1513
1514
1515<form method="post" enctype="multipart/form-data" action="$this_page" name="adminForm" class="w-actionbox">
1516<h3>ÐаÑтройка $newTitle Канала</h3>
1517<table class="g-input" width="500px">
1518<tr><td>ИмÑ</td><td><input name="newname" type="$nameField" id="newname" value="$newName" size="20" maxlength="64" onChange="censorName()"/>$newNameL</td></tr>
1519<tr><td>ОпиÑание</td><td><textarea rows=3 cols=60 name='description' id='description'>$newDescription</textarea></td></tr>
1520<tr><td>Рубрика</td><td>$categories</td></tr>
1521<tr><td>Комментарии</td><td>$commentsCode</td></tr>
1522$extraRows
1523<tr><td></td><td><input class="videowhisperButtonLS g-btn type_primary" type="submit" name="button" id="button" value="Сохранить" /></td></tr>
1524</table>
1525<input type="hidden" name="editPost" id="editPost" value="$editPost" />
1526</form>
1527HTMLCODE;
1528 }
1529
1530 $htmlCode .= html_entity_decode(stripslashes($options['customCSS']));
1531
1532 return $htmlCode;
1533
1534 }
1535
1536
1537
1538 function shortcode_channels($atts)
1539 {
1540 $options = get_option('VWliveStreamingOptions');
1541 $atts = shortcode_atts(
1542 array(
1543 'perPage'=>$options['perPage'],
1544 'ban' => '0',
1545 'perrow' => '',
1546 'order_by' => 'edate',
1547 'category_id' => '',
1548 'select_category' => '1',
1549 'select_order' => '1',
1550 'select_page' => '1',
1551 'include_css' => '1',
1552 'url_vars' => '1',
1553 'url_vars_fixed' => '1',
1554 'id' => ''
1555 ), $atts, 'videowhisper_channels');
1556
1557 $id = $atts['id'];
1558 if (!$id) $id = uniqid();
1559
1560 if ($atts['url_vars'])
1561 {
1562 $cid = (int) $_GET['cid'];
1563 if ($cid)
1564 {
1565 $atts['category_id'] = $cid;
1566 if ($atts['url_vars_fixed']) $atts['select_category'] = '0';
1567 }
1568 }
1569
1570 $ajaxurl = admin_url() . 'admin-ajax.php?action=vwls_channels&pp=' . $atts['perPage']. '&pr=' . $atts['perrow'] . '&ob=' . $atts['order_by'] . '&cat=' . $atts['category_id'] . '&sc=' . $atts['select_category'] . '&so=' . $atts['select_order'] . '&sp=' . $atts['select_page']. '&id=' .$id;
1571
1572 if ($atts['ban']) $ajaxurl .= '&ban=' . $atts['ban'];
1573
1574 $htmlCode = <<<HTMLCODE
1575<script>
1576var aurl$id = '$ajaxurl';
1577var \$j = jQuery.noConflict();
1578var loader$id;
1579
1580 function loadChannels$id(message){
1581
1582 if (message)
1583 if (message.length > 0)
1584 {
1585 \$j("#videowhisperChannels$id").html(message);
1586 }
1587
1588 if (loader$id) loader$id.abort();
1589
1590 loader$id = \$j.ajax({
1591 url: aurl$id,
1592 success: function(data) {
1593 \$j("#videowhisperChannels$id").html(data);
1594 }
1595 });
1596 }
1597
1598 \$j(function(){
1599 loadChannels$id();
1600 setInterval("loadChannels$id()", 10000);
1601 });
1602
1603</script>
1604
1605<div id="videowhisperChannels$id">
1606 Loading Channels...
1607</div>
1608HTMLCODE;
1609
1610 $htmlCode .= html_entity_decode(stripslashes($options['customCSS']));
1611
1612 return $htmlCode;
1613 }
1614
1615
1616 function html_watch($stream, $width='100%', $height='100%')
1617 {
1618 $stream = sanitize_file_name($stream);
1619
1620 $streamLabel = preg_replace('/[^A-Za-z0-9\-\_]/', '', $stream);
1621
1622 $swfurl = plugin_dir_url(__FILE__) . "ls/live_watch.swf?ssl=1&n=" . urlencode($stream);
1623 $swfurl .= "&prefix=" . urlencode(admin_url() . 'admin-ajax.php?action=vwls&task=');
1624 $swfurl .= '&extension='.urlencode('_none_');
1625 $swfurl .= '&ws_res=' . urlencode( plugin_dir_url(__FILE__) . 'ls/');
1626
1627 $bgcolor="#333333";
1628
1629
1630
1631
1632 return $htmlCode;
1633 }
1634
1635
1636 function shortcode_watch($atts)
1637 {
1638 $stream = '';
1639 if (is_single())
1640 if (get_post_type( get_the_ID() ) == 'channel') $stream = get_the_title(get_the_ID());
1641
1642
1643 $atts = shortcode_atts(array('channel' => $stream, 'width' => '100%', 'height' => '100%'), $atts, 'videowhisper_watch');
1644
1645 if (!$stream) $stream = $atts['channel']; //parameter channel="name"
1646 if (!$stream) $stream = $_GET['n'];
1647 $stream = sanitize_file_name($stream);
1648
1649 if (!$stream)
1650 {
1651 return "Watch Error: Missing channel name!";
1652 }
1653
1654 $width=$atts['width']; if (!$width) $width = "100%";
1655 $height=$atts['height']; if (!$height) $height = "100%";
1656
1657 //HLS if iOS/Android detected
1658 $agent = $_SERVER['HTTP_USER_AGENT'];
1659 $Android = stripos($agent,"Android");
1660 $iOS = ( strstr($agent,'iPhone') || strstr($agent,'iPod') || strstr($agent,'iPad'));
1661
1662 if ($Android||$iOS) return do_shortcode("[videowhisper_hls channel=\"$stream\"]");
1663
1664 $options = get_option('VWliveStreamingOptions');
1665 $watchStyle = html_entity_decode($options['watchStyle']);
1666
1667 $streamLabel = preg_replace('/[^A-Za-z0-9\-\_]/', '', $stream);
1668
1669
1670 $afterCode = <<<HTMLCODE
1671<br style="clear:both" />
1672
1673<style type="text/css">
1674<!--
1675
1676#videowhisper_container_$streamLabel
1677{
1678$watchStyle
1679}
1680
1681-->
1682</style>
1683
1684HTMLCODE;
1685
1686 return VWliveStreaming::html_watch($stream, $width, $height) . $afterCode ;
1687
1688 }
1689
1690
1691 function transcodeStream($stream, $required=0, $detect=2, $convert=1)
1692 {
1693
1694 //$detect: 0 = no, 1 = auto, 2 = always (update)
1695 //$convert: 0 = no, 1 = auto , 2 = always
1696
1697 if (!$stream) return;
1698
1699 $options = get_option('VWliveStreamingOptions');
1700
1701 if ( !$options['transcodingAuto'] && $convert != 2) return; //disabled
1702
1703 // check every 2 minutes
1704 if (!$required)
1705 if (!VWliveStreaming::timeTo($stream . '/transcodeCheck', 60, $options)) return;
1706
1707 //detect transcoding process - cancel if already started
1708 $cmd = "ps aux | grep '/i_$stream -i rtmp'";
1709 exec($cmd, $output, $returnvalue);
1710 //var_dump($output);
1711
1712 $transcoding = 0;
1713 foreach ($output as $line)
1714 if (strstr($line, "ffmpeg"))
1715 {
1716 $transcoding = 1;
1717 break;
1718 }
1719
1720 if ($transcoding) return "i_". $stream; //already transcoding - nothing to do
1721
1722 //is it a post channel?
1723 global $wpdb;
1724 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . sanitize_file_name($stream) . "' and post_type='channel' LIMIT 0,1" );
1725
1726 //is feature enabled?
1727 if ($postID)
1728 {
1729 $transcodeEnabled = get_post_meta($postID, 'vw_transcode', true);
1730 $videoCodec = get_post_meta($postID, 'stream-codec-video', true);
1731 }
1732 else
1733 {
1734 if ($options['anyChannels'] || $options['userChannels']) $transcodeEnabled = 1;
1735 }
1736
1737 //rtmp keys
1738 if ($options['externalKeysTranscoder'])
1739 {
1740 $current_user = wp_get_current_user();
1741
1742 $key = md5('vw' . $options['webKey'] . $current_user->ID . $postID);
1743
1744 $keyView = md5('vw' . $options['webKey']. $postID);
1745
1746 //?session&room&key&broadcaster&broadcasterid
1747 $rtmpAddress = $options['rtmp_server'] . '?'. urlencode('i_' . $stream) .'&'. urlencode($stream) .'&'. $key . '&1&' . $current_user->ID . '&videowhisper';
1748 $rtmpAddressView = $options['rtmp_server'] . '?'. urlencode('ffmpeg_' . $stream) .'&'. urlencode($stream) .'&'. $keyView . '&0&videowhisper';
1749 $rtmpAddressViewI = $options['rtmp_server'] . '?'. urlencode('ffmpegInfo_' . $stream) .'&'. urlencode($stream) .'&'. $keyView . '&0&videowhisper';
1750
1751 //VWliveStreaming::webSessionSave("/i_". $stream, 1);
1752 }
1753 else
1754 {
1755 $rtmpAddress = $options['rtmp_server'];
1756 $rtmpAddressView = $options['rtmp_server'];
1757 }
1758
1759 //paths
1760 $uploadsPath = $options['uploadsPath'];
1761 if (!file_exists($uploadsPath)) mkdir($uploadsPath);
1762
1763 $upath = $uploadsPath . "/$stream/";
1764 if (!file_exists($upath)) mkdir($upath);
1765
1766
1767 //detect codecs - do transcoding only if necessary
1768 if ($detect == 2 || ($detect == 1 && !$videoCodec))
1769 {
1770
1771 $log_file = $upath . "videowhisper_streaminfo.log";
1772
1773 $cmd = $options['ffmpegPath'] .' -y -i "' . $rtmpAddressViewI .'/'. $stream . '" 2>&1 ';
1774 $info = shell_exec($cmd);
1775
1776 //video
1777 if (!preg_match('/Stream #(?:[0-9\.]+)(?:.*)\: Video: (?P<videocodec>.*)/',$info,$matches))
1778 preg_match('/Could not find codec parameters \(Video: (?P<videocodec>.*)/',$info,$matches);
1779 list($videoCodec) = explode(' ',$matches[1]);
1780 if ($videoCodec && $postID) update_post_meta( $postID, 'stream-codec-video', strtolower($videoCodec) );
1781
1782 //audio
1783 $matches = array();
1784 if (!preg_match('/Stream #(?:[0-9\.]+)(?:.*)\: Audio: (?P<audiocodec>.*)/',$info,$matches))
1785 preg_match('/Could not find codec parameters \(Audio: (?P<audiocodec>.*)/',$info,$matches);
1786
1787 list($audioCodec) = explode(' ',$matches[1]);
1788 if ($audioCodec && $postID) update_post_meta( $postID, 'stream-codec-audio', strtolower($audioCodec) );
1789
1790 if (($videoCodec || $audioCodec) && $postID) update_post_meta( $postID, 'stream-codec-detect', time() );
1791
1792 exec("echo '".addslashes($info)."' >> $log_file", $output, $returnvalue);
1793 exec("echo '$cmd' >> $log_file.cmd", $output, $returnvalue);
1794
1795 }
1796
1797 //do any conversions after detection
1798 if ($convert)
1799 {
1800 if (!$videoCodec && $postID) $videoCodec = get_post_meta($postID, 'stream-codec-video', true);
1801 if (!$audioCodec && $postID) $audioCodec = get_post_meta($postID, 'stream-codec-audio', true);
1802
1803
1804 //valid mp4 for html5 playback?
1805 if (($sourceExt == 'mp4') && ($videoCodec == 'h264') && ($audioCodec = 'aac')) $isMP4 =1;
1806 else $isMP4 = 0;
1807
1808
1809 if ($isMP4 && $convert == 1) return $stream; //present format is fine - no conversion required
1810
1811 if (!$transcodeEnabled) return ''; //transcoding disabled
1812
1813 //start transcoding process
1814 $log_file = $upath . "videowhisper_transcode.log";
1815
1816
1817 //-vcodec copy
1818 $cmd = $options['ffmpegPath'] .' ' . $options['ffmpegTranscode'] . " -threads 1 -f flv \"" .
1819 $rtmpAddress . "/i_". $stream . "\" -i \"" . $rtmpAddressView ."/". $stream . "\" >&$log_file & ";
1820
1821
1822 //echo $cmd;
1823 exec($cmd, $output, $returnvalue);
1824 exec("echo '$cmd' >> $log_file.cmd", $output, $returnvalue);
1825
1826 //$cmd = "ps aux | grep '/i_$stream -i rtmp'";
1827 //exec($cmd, $output, $returnvalue);
1828
1829 return "i_". $stream;
1830 }
1831
1832
1833 }
1834
1835 function shortcode_hls($atts)
1836 {
1837 $stream = '';
1838 if (is_single())
1839 if (get_post_type( get_the_ID() ) == 'channel') $stream = get_the_title(get_the_ID());
1840
1841 $options = get_option('VWliveStreamingOptions');
1842
1843 $atts = shortcode_atts(array('channel' => $stream, 'width' => '480px', 'height' => '360px'), $atts, 'videowhisper_hls');
1844
1845
1846 if (!$stream) $stream = $atts['channel']; //parameter channel="name"
1847 if (!$stream) $stream = $_GET['n'];
1848
1849 $stream = sanitize_file_name($stream);
1850
1851 $width=$atts['width']; if (!$width) $width = "480px";
1852 $height=$atts['height']; if (!$height) $height = "360px";
1853
1854 if (!$stream)
1855 {
1856 return "Watch HLS Error: Missing channel name!";
1857 }
1858
1859 global $wpdb;
1860 $table_name = $wpdb->prefix . "vw_sessions";
1861
1862 $cnd = '';
1863 if ($strict) $cnd = " AND `type`='$type'";
1864
1865
1866 //transcoder active for this channel - only when rtmp status works
1867 /*
1868 $sqlS = "SELECT * FROM $table_name where session='ffmpeg_$username' and status='1' LIMIT 0,1";
1869 $session = $wpdb->get_row($sqlS);
1870 if ($session) $streamName = "i_$stream";
1871 else $streamName = $stream;
1872 */
1873
1874 //detect transcoding process
1875 $cmd = "ps aux | grep '/i_$stream -i rtmp'";
1876 exec($cmd, $output, $returnvalue);
1877 //var_dump($output);
1878
1879 /*
1880 $transcoding = 0;
1881
1882 foreach ($output as $line) if (strstr($line, "ffmpeg"))
1883 {
1884 $transcoding = 1;
1885 break;
1886 }
1887
1888 if ($transcoding) $streamName = "i_$stream";
1889 else $streamName = $stream;
1890
1891 */
1892
1893 //auto transcoding
1894 if ($options['transcodingAuto'])
1895 {
1896 $streamName = VWliveStreaming::transcodeStream($stream, 1); //require transcoding name
1897 }
1898
1899 if ($streamName)
1900 {
1901 $streamURL = $options['httpstreamer'] . $streamName . '/playlist.m3u8';
1902
1903
1904 $dir = $options['uploadsPath']. "/_thumbs";
1905 $thumbFilename = "$dir/" . $stream . ".jpg";
1906 $thumbUrl = VWliveStreaming::path2url($thumbFilename);
1907
1908
1909 $htmlCode = <<<HTMLCODE
1910<video id="videowhisper_hls_$stream" width="$width" height="$height" autobuffer autoplay controls poster="$thumbUrl">
1911 <source src="$streamURL" type='video/mp4'>
1912 <div class="fallback">
1913 <p>You must have an HTML5 capable browser with HLS support (Ex. Safari) to open this live stream: $streamURL</p>
1914 <p>Transcoding detected: $transcoding</p>
1915 </div>
1916</video>
1917HTMLCODE;
1918 }
1919 else $htmlCode = 'HLS format is not available and can not be transcoded for stream: '. $stream;
1920
1921 return $htmlCode;
1922 }
1923
1924
1925 function html_video($stream, $width = "100%", $height = '360px')
1926 {
1927
1928 $stream = sanitize_file_name($stream);
1929
1930 $swfurl = plugin_dir_url(__FILE__) . "ls/live_video.swf?ssl=1&n=" . urlencode($stream);
1931 $swfurl .= "&prefix=" . urlencode(admin_url() . 'admin-ajax.php?action=vwls&task=');
1932 $swfurl .= '&extension='.urlencode('_none_');
1933 $swfurl .= '&ws_res=' . urlencode( plugin_dir_url(__FILE__) . 'ls/');
1934
1935 $bgcolor="#333333";
1936
1937 $htmlCode = <<<HTMLCODE
1938<div id="videowhisper_container_$stream">
1939<object id="videowhisper_video_$stream" width="$width" height="$height" type="application/x-shockwave-flash" data="$swfurl">
1940<param name="movie" value="$swfurl"></param><param bgcolor="$bgcolor"><param name="scale" value="noscale" /> </param><param name="salign" value="lt"></param><param name="allowFullScreen"
1941value="true"></param><param name="allowscriptaccess" value="always"></param>
1942</object>
1943</div>
1944HTMLCODE;
1945
1946 return $htmlCode;
1947
1948 }
1949
1950 function shortcode_video($atts)
1951 {
1952 $stream = '';
1953 if (is_single())
1954 if (get_post_type( get_the_ID() ) == 'channel') $stream = get_the_title(get_the_ID());
1955
1956 $options = get_option('VWliveStreamingOptions');
1957
1958 $atts = shortcode_atts(array('channel' => $stream, 'width' => '480px', 'height' => '360px'), $atts, 'videowhisper_video');
1959
1960 if (!$stream) $stream = $atts['channel']; //parameter channel="name"
1961 if (!$stream) $stream = $_GET['n'];
1962
1963 $stream = sanitize_file_name($stream);
1964
1965
1966 $width=$atts['width']; if (!$width) $width = "100%";
1967 $height=$atts['height'];
1968 if (!$height) $height = '360px';
1969
1970 if (!$stream)
1971 {
1972 return "Watch Video Error: Missing channel name!";
1973 }
1974
1975 //HLS if iOS detected
1976 $agent = $_SERVER['HTTP_USER_AGENT'];
1977 $Android = stripos($agent,"Android");
1978 $iOS = ( strstr($agent,'iPhone') || strstr($agent,'iPod') || strstr($agent,'iPad'));
1979
1980 if ($Android||$iOS) return do_shortcode("[videowhisper_hls channel=\"$stream\" width=\"$width\" height=\"$height\"]");
1981
1982 $afterCode = <<<HTMLCODE
1983<br style="clear:both" />
1984
1985<style type="text/css">
1986<!--
1987
1988#videowhisper_container_$stream
1989{
1990position: relative;
1991width: $width;
1992height: $height;
1993border: solid 1px #999;
1994}
1995
1996-->
1997</style>
1998HTMLCODE;
1999
2000 return VWliveStreaming::html_video($stream, $width, $height) . $afterCode;
2001
2002 }
2003
2004
2005 function rtmp_address($userID, $postID, $broadcaster, $session, $room)
2006 {
2007
2008 //?session&room&key&broadcaster&broadcasterid
2009
2010 $options = get_option('VWliveStreamingOptions');
2011
2012
2013 if ($broadcaster)
2014 {
2015 $key = md5('vw' . $options['webKey'] . $userID . $postID);
2016 return $options['rtmp_server'] . '?'. urlencode($session) .'&'. urlencode($room) .'&'. $key . '&1&' . $userID . '&videowhisper';
2017 }
2018 else
2019 {
2020 $keyView = md5('vw' . $options['webKey']. $postID);
2021 return $options['rtmp_server'] . '?'. urlencode('-name-') .'&'. urlencode($room) .'&'. $keyView . '&0' . '&videowhisper';
2022 }
2023
2024 return $options['rtmp_server'];
2025
2026 }
2027
2028 function shortcode_external($atts)
2029 {
2030
2031 if (!is_user_logged_in()) return "<div class='error'>Only logged in users can broadcast!</div>";
2032
2033 $options = get_option('VWliveStreamingOptions');
2034
2035 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
2036
2037 //username
2038 $current_user = wp_get_current_user();
2039
2040 if ($current_user->$userName) $username=sanitize_file_name($current_user->$userName);
2041
2042 $postID = 0;
2043 if ($options['postChannels']) //1. channel post
2044 {
2045 $postID = get_the_ID();
2046 if (is_single())
2047 if (get_post_type( $postID ) == 'channel') $stream = get_the_title($postID);
2048 }
2049
2050 if (!$stream) $stream = $atts['channel']; //2. shortcode param
2051
2052 if ($options['anyChannels']) if (!$stream) $stream = $_GET['n']; //3. GET param
2053
2054 if ($options['userChannels']) if (!$stream) $stream = $username; //4. username
2055
2056 $stream = sanitize_file_name($stream);
2057
2058 if (!$stream) return "<div class='error'>Can't load broadcasting details: Missing channel name!</div>";
2059
2060 if ($postID>0 && $options['postChannels'])
2061 {
2062 $channel = get_post( $postID );
2063 if ($channel->post_author != $current_user->ID) return "<div class='error'>Only owner can broadcast (#$postID)!</div>";
2064 }
2065
2066 $rtmpAddress = VWliveStreaming::rtmp_address($current_user->ID, $postID, true, $stream, $stream);
2067 $rtmpAddressView = VWliveStreaming::rtmp_address($current_user->ID, $postID, false, $stream, $stream);
2068
2069 $codeWatch = htmlspecialchars(do_shortcode("[videowhisper_watch channel=\"$stream\"]"));
2070 $roomLink = VWliveStreaming::roomURL($stream);
2071
2072 $application = substr(strrchr($rtmpAddress, '/'),1);
2073
2074 $adrp1 = explode('://', $rtmpAddress);
2075 $adrp2 = explode('/', $adrp1[1]);
2076 $adrp3 = explode(':', $adrp2[0]);
2077
2078 $server = $adrp3[0];
2079 $port = $adrp3[1]; if (!$port) $port = 1935;
2080
2081 $htmlCode = <<<HTMLCODE
2082<h3>Broadcast Video</h3>
2083<div class="info w-actionbox color_alternate">
2084<P>After reviewing your encoder setting fields, retrieve settings you need from strings below.</P>
2085<p>RTMP Address / URL (full address, contains server, port if different than default 1935, application, parameters):<BR><I>$rtmpAddress</I></p>
2086<p>Application (contains application name and parameters):<BR><I>$application</I></p>
2087<p>Stream Name / Key (name of channel):<BR><I>$stream</I></p>
2088<p>Server:<BR><I>$server</I></p>
2089<p>Port:<BR><I>$port</I></p>
2090<p>Stream Address (RTMP Address with Stream Name):<BR><I>$rtmpAddress/$stream</I></p>
2091</div>
2092<p>Use specs above to broadcast channel '$stream' using external applications (Adobe Flash Media Live Encoder, Wirecast, GoCoder iOS app, OBS, XSplit).<br>Keep your secret broadcasting rtmp address safe as anyone having it may broadcast to your channel. As external encoders don't comunicate with site scripts, externally broadcast channel shows as online only if RTMP Session Control is enabled.</p>
2093
2094<p>Copy and paste strings: For mobile encoders send the strings above in an email or notes sharing app. In GoCoder copy and paste each string and save settings before switching between apps to get next string.</p>
2095<p>Warning: If advanced session control is enabled you can't connect at same time with web broadcasting interface and external encoder (duplicate named session will be refused by server). Connect with external encoder using details above and participate in chat with Watch interface.</p>
2096
2097<h3>Playback Video</h3>
2098<div class="info w-actionbox color_alternate">
2099<p>RTMP Address / URL (full address, contains server, port if different than default 1935, application, parameters):<BR><I>$rtmpAddressView</I></p>
2100<p>Stream Name:<BR><I>$stream</I></p>
2101<p>Stream Address (RTMP Address with Stream Name, for players that require these settings in 1 string):<BR><I>$rtmpAddressView/$stream</I></p>
2102</div>
2103<p>Use specs above to setup playback using 3rd party rtmp players (Strobe, JwPlayer, FlowPlayer).</p>
2104<h3>Chat & Video Embed</h3>
2105<div class="info w-actionbox color_alternate">
2106<p><I>$codeWatch</I></p>
2107</div>
2108<p>Embed chat & video on your site to show as on your <a href="">channel page</a>.</p>
2109HTMLCODE;
2110
2111 return $htmlCode;
2112
2113 }
2114
2115
2116 function shortcode_broadcast($atts)
2117 {
2118 $stream = '';
2119 if (!is_user_logged_in()) return "<div class='error'>" . __('Broadcasting not allowed: Only logged in users can broadcast!', 'livestreaming') . '</div>';
2120
2121 $options = get_option('VWliveStreamingOptions');
2122
2123 //username used with application
2124 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
2125
2126 $current_user = wp_get_current_user();
2127
2128 if ($current_user->$userName) $username=sanitize_file_name($current_user->$userName);
2129
2130 $postID = 0;
2131 if ($options['postChannels']) //1. channel post
2132 {
2133 $postID = get_the_ID();
2134 if (is_single())
2135 if (get_post_type( $postID ) == 'channel') $stream = get_the_title($postID);
2136 }
2137
2138 $atts = shortcode_atts(array('channel' => $stream), $atts, 'videowhisper_broadcast');
2139
2140
2141 if (!$stream) $stream = $atts['channel']; //2. shortcode param
2142
2143 if ($options['anyChannels']) if (!$stream) $stream = $_GET['n']; //3. GET param
2144
2145 if ($options['userChannels']) if (!$stream) $stream = $username; //4. username
2146
2147 $stream = sanitize_file_name($stream);
2148
2149 if (!$stream) return "<div class='error'>Can't load broadcasting interface: Missing channel name!</div>";
2150
2151 if ($postID>0 && $options['postChannels'])
2152 {
2153 $channel = get_post( $postID );
2154 if ($channel->post_author != $current_user->ID) return "<div class='error'>Only owner can broadcast (#$postID)!</div>";
2155 }
2156
2157
2158 $swfurl = plugin_dir_url(__FILE__) . "ls/live_broadcast.swf?ssl=1&room=" . urlencode($stream);
2159 $swfurl .= "&prefix=" . urlencode(admin_url() . 'admin-ajax.php?action=vwls&task=');
2160 $swfurl .= '&extension='.urlencode('_none_');
2161 $swfurl .= '&ws_res=' . urlencode( plugin_dir_url(__FILE__) . 'ls/');
2162
2163 $bgcolor="#333333";
2164
2165 $htmlCode = <<<HTMLCODE
2166<div id="videowhisper_container">
2167<object width="100%" height="100%" type="application/x-shockwave-flash" data="$swfurl">
2168<param name="movie" value="$swfurl"></param><param bgcolor="$bgcolor"><param name="scale" value="noscale" /> </param><param name="salign" value="lt"></param><param name="allowFullScreen"
2169value="true"></param><param name="allowscriptaccess" value="always"></param>
2170</object>
2171</div>
2172
2173<br style="clear:both" />
2174
2175<style type="text/css">
2176<!--
2177
2178#videowhisper_container
2179{
2180width: 100%;
2181height: 500px;
2182border: solid 3px #999;
2183}
2184
2185-->
2186</style>
2187
2188HTMLCODE;
2189
2190 if (!$options['transcoding']) return $htmlCode; //done
2191
2192
2193 //transcoding interface
2194 if ($stream)
2195 {
2196
2197 //access keys
2198 if ($current_user)
2199 {
2200 $userkeys = $current_user->roles;
2201 $userkeys[] = $current_user->user_login;
2202 $userkeys[] = $current_user->ID;
2203 $userkeys[] = $current_user->user_email;
2204 $userkeys[] = $current_user->display_name;
2205 }
2206
2207 $admin_ajax = admin_url() . 'admin-ajax.php';
2208
2209 if (VWliveStreaming::inList($userkeys, $options['transcode'])) //transcode feature enabled
2210 if ($options['transcoding']) if ($options['transcodingManual'])
2211 $htmlCode .= <<<HTMLCODE
2212<div id="vwinfo">
2213Stream Transcoding<BR>
2214<a href='#' class="button" id="transcoderon">ENABLE</a>
2215<a href='#' class="button" id="transcoderoff">DISABLE</a>
2216<div id="videowhisperTranscoder">A stream must be broadcast for transcoder to start. Activate to make stream available for iOS HLS.</div>
2217<p align="right">(<a href="javascript:void(0)" onClick="vwinfo.style.display='none';">hide</a>)</p>
2218</div>
2219
2220<style type="text/css">
2221<!--
2222
2223#vwinfo
2224{
2225 float: right;
2226 width: 25%;
2227 position: absolute;
2228 bottom: 10px;
2229 right: 10px;
2230 text-align:left;
2231 font-size: 14px;
2232 padding: 10px;
2233 margin: 10px;
2234 background-color: #666;
2235 border: 1px dotted #AAA;
2236 z-index: 1;
2237
2238 filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#999', endColorstr='#666'); /* for IE */
2239 background: -webkit-gradient(linear, left top, left bottom, from(#999), to(#666)); /* for webkit browsers */
2240 background: -moz-linear-gradient(top, #999, #666); /* for firefox 3.6+ */
2241
2242 box-shadow: 2px 2px 2px #333;
2243
2244
2245 -moz-border-radius: 9px;
2246 border-radius: 9px;
2247}
2248
2249#vwinfo > a {
2250 color: #F77;
2251 text-decoration: none;
2252}
2253
2254#vwinfo > .button {
2255 -moz-box-shadow:inset 0px 1px 0px 0px #f5978e;
2256 -webkit-box-shadow:inset 0px 1px 0px 0px #f5978e;
2257 box-shadow:inset 0px 1px 0px 0px #f5978e;
2258 background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #db4f48), color-stop(1, #944038) );
2259 background:-moz-linear-gradient( center top, #db4f48 5%, #944038 100% );
2260 filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#db4f48', endColorstr='#944038');
2261 background-color:#db4f48;
2262 border:1px solid #d02718;
2263 display:inline-block;
2264 color:#ffffff;
2265 font-family:Verdana;
2266 font-size:12px;
2267 font-weight:normal;
2268 font-style:normal;
2269 text-decoration:none;
2270 text-align:center;
2271 text-shadow:1px 1px 0px #810e05;
2272 padding: 5px;
2273 margin: 2px;
2274}
2275#vwinfo > .button:hover {
2276 background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #944038), color-stop(1, #db4f48) );
2277 background:-moz-linear-gradient( center top, #944038 5%, #db4f48 100% );
2278 filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#944038', endColorstr='#db4f48');
2279 background-color:#944038;
2280}
2281
2282-->
2283</style>
2284
2285<script type="text/javascript">
2286 var \$j = jQuery.noConflict();
2287 var loaderTranscoder;
2288 var transcodingOn = false;
2289
2290
2291 \$j.ajaxSetup ({
2292 cache: false
2293 });
2294 var ajax_load = "Loading...";
2295
2296 \$j("#transcoderon").click(function(){
2297 transcodingOn = true;
2298 if (loaderTranscoder) if (loaderTranscoder.abort === 'function') loaderTranscoder.abort();
2299 loaderTranscoder = \$j("#videowhisperTranscoder").html(ajax_load).load("$admin_ajax?action=vwls_trans&task=enable&stream=$stream");
2300 });
2301
2302 \$j("#transcoderoff").click(function(){
2303 transcodingOn = false;
2304 if (loaderTranscoder) if (loaderTranscoder.abort === 'function') loaderTranscoder.abort();
2305 loaderTranscoder = \$j("#videowhisperTranscoder").html(ajax_load).load("$admin_ajax?action=vwls_trans&task=close&stream=$stream");
2306 });
2307</script>
2308HTMLCODE;
2309 }
2310
2311 return $htmlCode ;
2312 }
2313
2314
2315
2316 function path2url($file, $Protocol='http://')
2317 {
2318 $url = $Protocol.$_SERVER['HTTP_HOST'];
2319
2320
2321 //on godaddy hosting uploads is in different folder like /var/www/clients/ ..
2322 $upload_dir = wp_upload_dir();
2323 if (strstr($file, $upload_dir['basedir']))
2324 return $upload_dir['baseurl'] . str_replace($upload_dir['basedir'], '', $file);
2325
2326 if (strstr($file, $_SERVER['DOCUMENT_ROOT']))
2327 return $url . str_replace($_SERVER['DOCUMENT_ROOT'], '', $file);
2328
2329
2330 return $url . $file;
2331 }
2332
2333
2334 function format_time($t,$f=':') // t = seconds, f = separator
2335 {
2336 return sprintf("%02d%s%02d%s%02d", floor($t/3600), $f, ($t/60)%60, $f, $t%60);
2337 }
2338
2339 function format_age($t)
2340 {
2341 if ($t<30) return "LIVE";
2342 return sprintf("%d%s%d%s%d%s", floor($t/86400), 'd ', ($t/3600)%24,'h ', ($t/60)%60,'m');
2343 }
2344
2345 //! AJAX
2346 function wp_enqueue_scripts()
2347 {
2348 wp_enqueue_script("jquery");
2349
2350 }
2351
2352 //! channels list ajax handler
2353
2354 function vwls_channels() //list channels
2355 {
2356 //ajax called
2357
2358 //channel meta:
2359 //edate s
2360 //btime s
2361 //wtime s
2362 //viewers n
2363 //maxViewers n
2364 //maxDate s
2365 //hasSnapshot 1
2366
2367 $options = get_option('VWliveStreamingOptions');
2368
2369 //widget id
2370 $id = sanitize_file_name($_GET['id']);
2371
2372 //pagination
2373 $perPage = (int) $_GET['pp'];
2374 if (!$perPage) $perPage = $options['perPage'];
2375
2376 $page = (int) $_GET['p'];
2377 $offset = $page * $perPage;
2378
2379 $perRow = (int) $_GET['pr'];
2380
2381 //admin side
2382 $ban = (int) $_GET['ban'];
2383
2384 //
2385 $category = (int) $_GET['cat'];
2386
2387 //order
2388 $order_by = sanitize_file_name($_GET['ob']);
2389 if (!$order_by) $order_by = 'edate';
2390
2391 //options
2392 $selectCategory = (int) $_GET['sc'];
2393 $selectOrder = (int) $_GET['so'];
2394 $selectPage = (int) $_GET['sp'];
2395
2396 //output clean
2397 ob_clean();
2398
2399 //thumbs dir
2400 $dir = $options['uploadsPath']. "/_thumbs";
2401
2402 $ajaxurl = admin_url() . 'admin-ajax.php?action=vwls_channels&pp=' . $perPage . '&pr=' .$perRow. '&sc=' . $selectCategory . '&so=' . $selectOrder . '&sp=' . $selectPage . '&id=' . $id;
2403 if ($ban) $ajaxurl .= '&ban=' . $ban; //admin side
2404
2405 if ($options['postChannels']) //channel posts enabled
2406 {
2407
2408 //! header option controls
2409
2410 $ajaxurlP = $ajaxurl . '&p='.$page;
2411 $ajaxurlPC = $ajaxurl . '&cat=' . $category ;
2412 $ajaxurlPO = $ajaxurl . '&ob='. $order_by;
2413 $ajaxurlCO = $ajaxurl . '&cat=' . $category . '&ob='.$order_by ;
2414
2415 echo '<div class="videowhisperListOptions">';
2416 if ($selectCategory)
2417 {
2418 echo '<div class="videowhisperDropdown">' . wp_dropdown_categories('echo=0&name=category' . $id . '&hide_empty=1&class=videowhisperSelect&show_option_all=' . __('Ð’Ñе рубрики', 'livestreaming') . '&selected=' . $category).'</div>';
2419 echo '<script>var category' . $id . ' = document.getElementById("category' . $id . '"); category' . $id . '.onchange = function(){aurl' . $id . '=\'' . $ajaxurlPO.'&cat=\'+ this.value; loadChannels' . $id . '(\'Загрузка категории...\')}
2420 </script>';
2421 }
2422
2423
2424 echo '</div>';
2425
2426
2427 //! query args
2428 $args=array(
2429 'post_type' => 'channel',
2430 'post_status' => 'publish',
2431 'posts_per_page' => $perPage,
2432 'offset' => $offset,
2433 'order' => 'DESC',
2434 'meta_query' => array(
2435 array( 'key' => 'hasSnapshot', 'value' => '1'),
2436 )
2437 );
2438
2439 if ($order_by != 'post_date')
2440 {
2441 $args['orderby'] = 'meta_value_num';
2442 $args['meta_key'] = $order_by;
2443 }
2444 else
2445 {
2446 $args['orderby'] = 'post_date';
2447 }
2448
2449 if ($category) $args['category'] = $category;
2450
2451 $postslist = get_posts( $args );
2452
2453 //! list channels
2454 if (count($postslist)>0)
2455 {
2456 $k = 0;
2457 foreach ( $postslist as $item )
2458 {
2459 if ($perRow) if ($k) if ($k % $perRow == 0) echo '<br>';
2460
2461 $edate = get_post_meta($item->ID, 'edate', true);
2462 $age = VWliveStreaming::format_age(time() - $edate);
2463 $name = sanitize_file_name($item->post_title);
2464
2465 if ($ban) $banLink = '<a class = "button" href="admin.php?page=live-streaming-live&ban=' . urlencode( $name ) . '">Забанить канал</a><br>';
2466
2467 echo '<div class="videowhisperChannel">';
2468 echo '<div class="videowhisperTitle">' . $name . '</div>';
2469 echo '<div class="videowhisperTime">' . $banLink . $age . '</div>';
2470
2471 $thumbFilename = "$dir/" . $name . ".jpg";
2472 $url = VWliveStreaming::roomURL($name);
2473
2474 $noCache = '';
2475 if ($age=='LIVE') $noCache='?'.((time()/10)%100);
2476
2477 $showImage=get_post_meta( $item->ID, 'showImage', true );
2478
2479 if (!file_exists($thumbFilename) || $showImage =='all') //show thumb instead
2480 {
2481 $attach_id = get_post_thumbnail_id($item->ID );
2482 if ($attach_id) $thumbFilename = get_attached_file($attach_id);
2483 }
2484
2485 if (file_exists($thumbFilename)) echo '<a href="' . $url . '"><IMG src="' . VWliveStreaming::path2url($thumbFilename) . $noCache .'" width="' . $options['thumbWidth'] . 'px" height="' . $options['thumbHeight'] . 'px"></a>';
2486 else echo '<a href="' . $url . '"><IMG SRC="' . plugin_dir_url(__FILE__). 'screenshot-3.jpg" width="' . $options['thumbWidth'] . 'px" height="' . $options['thumbHeight'] . 'px"></a>';
2487 echo "</div>";
2488
2489 }
2490 }
2491 else echo "Ðет каналов онлайн, ÑоответÑтвующих текущему выбору..";
2492
2493 //! pagination
2494 if ($selectPage)
2495 {
2496 echo "<BR>";
2497 if ($page>0) echo ' <a class="videowhisperButtonLS g-btn type_secondary" href="JavaScript: void()" onclick="aurl' . $id . '=\'' . $ajaxurlCO.'&p='.($page-1). '\'; loadChannels' . $id . '(\'Загрузка Ñтраницы...\');">Предыдущий</a> ';
2498
2499 if (count($postslist) == $perPage) echo ' <a class="videowhisperButtonLS g-btn type_secondary" href="JavaScript: void()" onclick="aurl' . $id . '=\'' . $ajaxurlCO.'&p='.($page+1). '\'; loadChannels' . $id . '(\'Загрузка Ñтраницы...\');">Следующий</a> ';
2500 }
2501
2502 }
2503 else // channel post disabled - check db
2504 {
2505 global $wpdb;
2506 $table_name3 = $wpdb->prefix . "vw_lsrooms";
2507
2508 $items = $wpdb->get_results("SELECT * FROM `$table_name3` WHERE status=1 ORDER BY edate DESC LIMIT $offset, ". $perPage);
2509 if ($items) foreach ($items as $item)
2510 {
2511 $age = VWliveStreaming::format_age(time() - $item->edate);
2512
2513 if ($ban) $banLink = '<a class = "button" href="admin.php?page=live-streaming-live&ban=' . urlencode( $item->name ) . '">Ban This Channel</a><br>';
2514
2515 echo '<div class="videowhisperChannel">';
2516 echo '<div class="videowhisperTitle">' . $item->name . '</div>';
2517 echo '<div class="videowhisperTime">' . $banLink . $age . '</div>';
2518
2519 $thumbFilename = "$dir/" . $item->name . ".jpg";
2520
2521 $url = VWliveStreaming::roomURL($item->name);
2522
2523 $noCache = '';
2524 if ($age=='LIVE') $noCache='?'.((time()/10)%100);
2525
2526 if (file_exists($thumbFilename)) echo '<a href="' . $url . '"><IMG src="' . VWliveStreaming::path2url($thumbFilename) . $noCache .'" width="' . $options['thumbWidth'] . 'px" height="' . $options['thumbHeight'] . 'px"></a>';
2527 else echo '<a href="' . $url . '"><IMG SRC="' . plugin_dir_url(__FILE__). 'screenshot-3.jpg" width="' . $options['thumbWidth'] . 'px" height="' . $options['thumbHeight'] . 'px"></a>';
2528 echo "</div>";
2529 }
2530
2531 //pagination
2532 if ($selectPage)
2533 {
2534 echo "<BR>";
2535 if ($page>0) echo ' <a class="videowhisperButtonLS g-btn type_secondary" href="JavaScript: void()" onclick="aurl' . $id . '=\'' . $ajaxurlCO.'&p='.($page-1). '\'; loadChannels' . $id . '(\'Loading previous page...\');">Previous</a> ';
2536
2537 if (count($items) == $perPage) echo ' <a class="videowhisperButtonLS g-btn type_secondary" href="JavaScript: void()" onclick="aurl' . $id . '=\'' . $ajaxurlCO.'&p='.($page+1). '\'; loadChannels' . $id . '(\'Loading next page...\');">Next</a> ';
2538 }
2539 }
2540
2541
2542
2543
2544 die;
2545 }
2546
2547 //! broadcast ajax handler
2548 function vwls_broadcast() //dedicated broadcasting page
2549 {
2550 ob_clean();
2551?>
2552<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
2553<head>
2554<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
2555<title>VideoWhisper Live Broadcast</title>
2556</head>
2557<body bgcolor="<?php echo $bgcolor?>">
2558<style type="text/css">
2559<!--
2560BODY
2561{
2562 padding-right: 6px;
2563 margin: 0px;
2564 background: #333;
2565 font-family: Arial, Helvetica, sans-serif;
2566 font-size: 12px;
2567 color: #EEE;
2568}
2569-->
2570</style>
2571<?php
2572 include(plugin_dir_path( __FILE__ ) . "ls/flash_detect.php");
2573
2574 echo do_shortcode('[videowhisper_broadcast]');
2575
2576 die;
2577 }
2578
2579 function fixPath($p) {
2580
2581 //adds ending slash if missing
2582
2583 // $p=str_replace('\\','/',trim($p));
2584 return (substr($p,-1)!='/') ? $p.='/' : $p;
2585 }
2586
2587
2588 function varSave($path, $var)
2589 {
2590 file_put_contents($path, serialize($var));
2591 }
2592
2593 function varLoad($path)
2594 {
2595 if (!file_exists($path)) return false;
2596
2597 return unserialize(file_get_contents($path));
2598 }
2599
2600 function updatePlaylist($stream, $active = true)
2601 {
2602 //updates playlist for channel $stream in global playlist
2603 if (!$stream) return;
2604
2605 $options = get_option('VWliveStreamingOptions');
2606
2607 $uploadsPath = $options['uploadsPath'];
2608 if (!file_exists($uploadsPath)) mkdir($uploadsPath);
2609 $playlistPathGlobal = $uploadsPath . '/playlist_global.txt';
2610 if (!file_exists($playlistPathGlobal)) VWliveStreaming::varSave($playlistPathGlobal, array());
2611
2612 $upath = $uploadsPath . "/$stream/";
2613 if (!file_exists($upath)) mkdir($upath);
2614 $playlistPath = $upath . 'playlist.txt';
2615 if (!file_exists($playlistPath)) VWliveStreaming::varSave($playlistPath, array());
2616
2617 $playlistGlobal = VWliveStreaming::varLoad($playlistPathGlobal);
2618 $playlist = VWliveStreaming::varLoad($playlistPath);
2619
2620 if ($active) $playlistGlobal[$stream] = $playlist;
2621 else unset($playlistGlobal[$stream]);
2622
2623 VWliveStreaming::varSave($playlistPathGlobal, $playlistGlobal);
2624
2625 VWliveStreaming::updatePlaylistSMIL();
2626 }
2627
2628 function updatePlaylistSMIL()
2629 {
2630 $options = get_option('VWliveStreamingOptions');
2631
2632 //! update Playlist SMIL
2633 $streamsPath = VWliveStreaming::fixPath($options['streamsPath']);
2634 $smilPath = $streamsPath . 'playlist.smil';
2635
2636 $smilCode .= <<<HTMLCODE
2637<smil>
2638 <head>
2639 </head>
2640 <body>
2641
2642HTMLCODE;
2643
2644 if ($options['playlists'])
2645 {
2646
2647 $uploadsPath = $options['uploadsPath'];
2648 if (!file_exists($uploadsPath)) mkdir($uploadsPath);
2649 $playlistPathGlobal = $uploadsPath . '/playlist_global.txt';
2650 if (!file_exists($playlistPathGlobal)) VWliveStreaming::varSave($playlistPathGlobal, array());
2651 $playlistGlobal = VWliveStreaming::varLoad($playlistPathGlobal);
2652
2653
2654 $streams = array_keys($playlistGlobal);
2655 foreach ($streams as $stream)
2656 $smilCode .= '<stream name="' . $stream . '"></stream>
2657 ';
2658
2659 foreach ($streams as $stream)
2660 foreach ($playlistGlobal[$stream] as $item)
2661 {
2662
2663 $smilCode .= '
2664 <playlist name="' . $stream . $item['Id'] . '" playOnStream="' . $stream . '" repeat="'. ($item['Repeat']?'true':'false') .'" scheduled="' . $item['Scheduled']. '">';
2665
2666 foreach ($item['Videos'] as $video)
2667 $smilCode .= '
2668 <video src="'. $video['Video'] . '" start="' . $video['Start'] . '" length="' . $video['Length'] . '"/>';
2669
2670 $smilCode .= '
2671 </playlist>';
2672 }
2673 }
2674 $smilCode .= <<<HTMLCODE
2675
2676 </body>
2677</smil>
2678HTMLCODE;
2679
2680 file_put_contents($smilPath, $smilCode);
2681 }
2682
2683
2684 function path2stream($path, $withExtension=true, $withPrefix=true)
2685 {
2686 $options = get_option( 'VWliveStreamingOptions' );
2687
2688 $stream = substr($path, strlen($options['streamsPath']));
2689 if ($stream[0]=='/') $stream = substr($stream, 1);
2690
2691 if ($withPrefix)
2692 {
2693 $ext = pathinfo($stream, PATHINFO_EXTENSION);
2694 $prefix = $ext . ':';
2695 }else $prefix = '';
2696
2697 if (!file_exists($options['streamsPath'] . '/' . $stream)) return '';
2698 elseif ($withExtension) return $prefix.$stream;
2699 else return $prefix.pathinfo($stream, PATHINFO_FILENAME);
2700 }
2701
2702 //! Playlist AJAX handler
2703
2704 function vwls_playlist()
2705 {
2706 ob_clean();
2707
2708 $postID = (int) $_GET['channel'];
2709
2710 if (!$postID)
2711 {
2712 echo "No channel ID provided!";
2713 die;
2714 }
2715
2716 $channel = get_post( $postID );
2717 if (!$channel)
2718 {
2719 echo "Channel not found!";
2720 die;
2721 }
2722
2723 $current_user = wp_get_current_user();
2724
2725 if ($channel->post_author != $current_user->ID)
2726 {
2727 echo "Access not permitted (different channel owner)!";
2728 die;
2729 }
2730
2731 $stream = sanitize_file_name($channel->post_title);
2732
2733 $options = get_option('VWliveStreamingOptions');
2734
2735 $uploadsPath = $options['uploadsPath'];
2736 if (!file_exists($uploadsPath)) mkdir($uploadsPath);
2737
2738 $upath = $uploadsPath . "/$stream/";
2739 if (!file_exists($upath)) mkdir($upath);
2740
2741 $playlistPath = $upath . 'playlist.txt';
2742
2743 if (!file_exists($playlistPath)) VWliveStreaming::varSave($playlistPath, array());
2744
2745 switch ($_GET['task'])
2746 {
2747 case 'list':
2748 $rows = VWliveStreaming::varLoad($playlistPath);
2749
2750
2751
2752 //sort rows by order
2753 if (count($rows))
2754 {
2755 //sort
2756 function cmp_by_order($a, $b) {
2757
2758 if ($a['Order'] == $b['Order']) return 0;
2759 return ($a['Order'] < $b['Order']) ? -1 : 1;
2760 }
2761
2762 usort($rows, 'cmp_by_order'); //sort
2763
2764 //update Ids to match keys (order)
2765 $updated = 0;
2766 foreach ($rows as $key => $value)
2767 if ($rows[$key]['Id'] != $key)
2768 {
2769 $rows[$key]['Id'] = $key;
2770 $updated = 1;
2771 }
2772 if ($updated) VWliveStreaming::varSave($playlistPath, $rows);
2773
2774 }
2775
2776
2777 //Return result to jTable
2778 $jTableResult = array();
2779 $jTableResult['Result'] = "OK";
2780 $jTableResult['Records'] = $rows;
2781 print json_encode($jTableResult);
2782
2783 break;
2784
2785 case 'videolist':
2786 $ItemId = (int) $_GET['item'];
2787 $jTableResult = array();
2788
2789 $playlist = VWliveStreaming::varLoad($playlistPath);
2790
2791 if ($schedule = $playlist[$ItemId])
2792 {
2793 if (!$schedule['Videos']) $schedule['Videos'] = array();
2794
2795 //sort videos
2796
2797
2798
2799 //sort rows by order
2800 if (count($schedule['Videos']))
2801 {
2802
2803 //sort
2804 function cmp_by_order($a, $b) {
2805
2806 if ($a['Order'] == $b['Order']) return 0;
2807 return ($a['Order'] < $b['Order']) ? -1 : 1;
2808 }
2809
2810 usort($schedule['Videos'], 'cmp_by_order'); //sort
2811
2812 //update Ids to match keys (order)
2813 $updated = 0;
2814 foreach ($schedule['Videos'] as $key => $value)
2815 if ($schedule['Videos'][$key]['Id'] != $key)
2816 {
2817 $schedule['Videos'][$key]['Id'] = $key;
2818 $updated = 1;
2819 }
2820
2821 $playlist[$ItemId] = $schedule;
2822 if ($updated) VWliveStreaming::varSave($playlistPath, $playlist);
2823
2824 }
2825
2826 $jTableResult['Records'] = $schedule['Videos'];
2827 $jTableResult['Result'] = "OK";
2828 }
2829 else
2830 {
2831 $jTableResult['Result'] = "ERROR";
2832 $jTableResult['Message'] = "Schedule $ItemId not found!";
2833 }
2834
2835 print json_encode($jTableResult);
2836 break;
2837
2838 case 'videoupdate':
2839 //delete then add new
2840
2841 $playlist = VWliveStreaming::varLoad($playlistPath);
2842 $ItemId = (int) $_POST['ItemId'];
2843 $Id = (int) $_POST['Id'];
2844
2845 $jTableResult = array();
2846 if ($playlist[$ItemId])
2847 {
2848
2849 //find and remove record with that Id
2850 foreach ($playlist[$ItemId]['Videos'] as $key => $value)
2851 if ($value['Id'] == $Id)
2852 {
2853 unset($playlist[$ItemId]['Videos'][$key]);
2854 break;
2855 }
2856
2857 VWliveStreaming::varSave($playlistPath,$playlist);
2858 }
2859
2860 case 'videoadd':
2861 $playlist = VWliveStreaming::varLoad($playlistPath);
2862 $ItemId = (int) $_POST['ItemId'];
2863
2864 $jTableResult = array();
2865 if ($schedule = $playlist[$ItemId])
2866 {
2867 if (!$schedule['Videos']) $schedule['Videos'] = array();
2868
2869 $maxOrder = 0; $maxId = 0;
2870 foreach ($schedule['Videos'] as $item)
2871 {
2872 if ($item['Order'] > $maxOrder) $maxOrder = $item['Order'];
2873 if ($item['Id'] > $maxId) $maxId = $item['Id'];
2874 }
2875
2876 $item = array();
2877 $item['Video'] = sanitize_text_field($_POST['Video']);
2878 $item['Id'] = (int) $_POST['Id'];
2879 $item['Order'] = (int) $_POST['Order'];
2880 $item['Start'] = (int) $_POST['Start'];
2881 $item['Length'] = (int) $_POST['Length'];
2882
2883 if (!$item['Order']) $item['Order'] = $maxOrder + 1;
2884 if (!$item['Id']) $item['Id'] = $maxId + 1;
2885
2886 $playlist[$ItemId]['Videos'][] = $item;
2887
2888 VWliveStreaming::varSave($playlistPath,$playlist);
2889
2890 $jTableResult['Result'] = "OK";
2891 $jTableResult['Record'] = $item;
2892 }
2893 else
2894 {
2895 $jTableResult['Result'] = "ERROR";
2896 $jTableResult['Message'] = "Schedule $ItemId not found!";
2897 }
2898
2899 //Return result to jTable
2900 print json_encode($jTableResult);
2901
2902 break;
2903
2904 case 'videoremove':
2905 $playlist = VWliveStreaming::varLoad($playlistPath);
2906 $ItemId = (int) $_GET['item'];
2907 $Id = (int) $_POST['Id'];
2908
2909 $jTableResult = array();
2910 if ($schedule = $playlist[$ItemId])
2911 {
2912
2913 //find and remove record with that Id
2914 foreach ($playlist[$ItemId]['Videos'] as $key => $value)
2915 if ($value['Id'] == $Id)
2916 {
2917 unset($playlist[$ItemId]['Videos'][$key]);
2918 break;
2919 }
2920
2921 VWliveStreaming::varSave($playlistPath,$playlist);
2922
2923 $jTableResult['Result'] = "OK";
2924 $jTableResult['Remaining'] = $playlist[$ItemId]['Videos'];
2925 }
2926 else
2927 {
2928 $jTableResult['Result'] = "ERROR";
2929 $jTableResult['Message'] = "Schedule $ItemId not found!";
2930 }
2931
2932 //Return result to jTable
2933 print json_encode($jTableResult);
2934
2935 break;
2936
2937 case 'source':
2938
2939 //retrieve videos owned by user (from all channels)
2940
2941 //query
2942 $args=array(
2943 'post_type' => $options['custom_post_video'],
2944 'author' => $current_user->ID,
2945 'orderby' => 'post_date',
2946 'order' => 'DESC',
2947 );
2948
2949 $postslist = get_posts( $args );
2950 $rows = array();
2951
2952 if (count($postslist)>0)
2953 {
2954 foreach ( $postslist as $item )
2955 {
2956 $row = array();
2957 $row['DisplayText'] = $item->post_title;
2958
2959 $video_id = $item->ID;
2960
2961 //retrieve video stream
2962 $streamPath = '';
2963 $videoPath = get_post_meta($video_id, 'video-source-file', true);
2964 $ext = pathinfo($videoPath, PATHINFO_EXTENSION);
2965
2966 //use conversion if available
2967 $videoAdaptive = get_post_meta($video_id, 'video-adaptive', true);
2968 if ($videoAdaptive) $videoAlts = $videoAdaptive;
2969 else $videoAlts = array();
2970
2971 foreach (array('high', 'mobile') as $frm)
2972 if ($alt = $videoAlts[$frm])
2973 if (file_exists($alt['file']))
2974 {
2975 $ext = pathinfo($alt['file'], PATHINFO_EXTENSION);
2976 $streamPath = VWliveStreaming::path2stream($alt['file']);
2977 break;
2978 };
2979
2980 //user original
2981 if (!$streamPath)
2982 if (in_array($ext, array('flv','mp4','m4v')))
2983 {
2984 //use source if compatible
2985 $streamPath = VWliveStreaming::path2stream($videoPath);
2986 }
2987
2988 $row['Value'] = $streamPath;
2989 $rows[] = $row;
2990 }
2991 }
2992 //Return result to jTable
2993 $jTableResult = array();
2994 $jTableResult['Result'] = "OK";
2995 $jTableResult['Options'] = $rows;
2996 print json_encode($jTableResult);
2997
2998 break;
2999
3000 case 'update':
3001 //delete then create new
3002 $Id = (int) $_POST['Id'];
3003
3004 $playlist = VWliveStreaming::varLoad($playlistPath);
3005 if (!is_array($playlist)) $playlist = array();
3006
3007 foreach ($playlist as $key => $value)
3008 if ($value['Id'] == $Id)
3009 {
3010 unset($playlist[$key]);
3011 break;
3012 }
3013
3014 VWliveStreaming::varSave($playlistPath,$playlist);
3015
3016 case 'create':
3017
3018 $playlist = VWliveStreaming::varLoad($playlistPath);
3019 if (!is_array($playlist)) $playlist = array();
3020
3021 $maxOrder = 0; $maxId = 0;
3022 foreach ($playlist as $item)
3023 {
3024 if ($item['Order'] > $maxOrder) $maxOrder = $item['Order'];
3025 if ($item['Id'] > $maxId) $maxId = $item['Id'];
3026 }
3027
3028 $item = array();
3029 $item['Id'] = (int) $_POST['Id'];
3030 $item['Video'] = sanitize_text_field($_POST['Video']);
3031 $item['Repeat'] = (int) $_POST['Repeat'];
3032 $item['Scheduled'] = sanitize_text_field($_POST['Scheduled']);
3033 $item['Order'] = (int) $_POST['Order'];
3034 if (!$item['Order']) $item['Order'] = $maxOrder + 1;
3035 if (!$item['Id']) $item['Id'] = $maxId + 1;
3036 if (!$item['Scheduled']) $item['Scheduled'] = date('Y-m-j h:i:s');
3037
3038 $playlist[$item['Id']] = $item;
3039
3040 VWliveStreaming::varSave($playlistPath, $playlist);
3041
3042 //Return result to jTable
3043 $jTableResult = array();
3044 $jTableResult['Result'] = "OK";
3045 $jTableResult['Record'] = $item;
3046 print json_encode($jTableResult);
3047 break;
3048
3049 case 'delete':
3050 $Id = (int) $_POST['Id'];
3051
3052 $playlist = VWliveStreaming::varLoad($playlistPath);
3053 if (!is_array($playlist)) $playlist = array();
3054
3055 foreach ($playlist as $key => $value)
3056 if ($value['Id'] == $Id)
3057 {
3058 unset($playlist[$key]);
3059 break;
3060 }
3061
3062 VWliveStreaming::varSave($playlistPath, $playlist);
3063
3064 //Return result to jTable
3065 $jTableResult = array();
3066 $jTableResult['Result'] = "OK";
3067 print json_encode($jTableResult);
3068 break;
3069
3070 default:
3071 echo 'Action not supported!';
3072 }
3073
3074 die;
3075
3076 }
3077
3078 //! manual transcoding ajax handler
3079
3080 function vwls_trans()
3081 {
3082
3083 ob_clean();
3084
3085 $stream = sanitize_file_name($_GET['stream']);
3086
3087 if (!$stream)
3088 {
3089 echo "No stream name provided!";
3090 return;
3091 }
3092
3093 $options = get_option('VWliveStreamingOptions');
3094
3095 $uploadsPath = $options['uploadsPath'];
3096 if (!file_exists($uploadsPath)) mkdir($uploadsPath);
3097
3098 $upath = $uploadsPath . "/$stream/";
3099 if (!file_exists($upath)) mkdir($upath);
3100
3101 $rtmp_server=$options['rtmp_server'];
3102
3103 switch ($_GET['task'])
3104 {
3105 case 'enable':
3106
3107 if ( !is_user_logged_in() )
3108 {
3109 echo "Not authorised!";
3110 exit;
3111 }
3112
3113 $cmd = "ps aux | grep '/i_$stream -i rtmp'";
3114 exec($cmd, $output, $returnvalue);
3115 //var_dump($output);
3116
3117 $admin_ajax = admin_url() . 'admin-ajax.php';
3118
3119 $transcoding = 0;
3120
3121 foreach ($output as $line) if (strstr($line, "ffmpeg"))
3122 {
3123 $columns = preg_split('/\s+/',$line);
3124 echo "Transcoder is currently Active (".$columns[1]." CPU: ".$columns[2]." Mem: ".$columns[3].")";
3125 $transcoding = 1;
3126 }
3127
3128 if ($transcoding)
3129 {
3130 echo '<script>
3131
3132 setTimeout(\' if (loaderTranscoder) if (loaderTranscoder.abort === \\\'function\\\') loaderTranscoder.abort(); if (transcodingOn) loaderTranscoder = $j("#videowhisperTranscoder").html(ajax_load).load("'.$admin_ajax.'?action=vwls_trans&task=enable&stream='.$stream.'");\', 120000 );
3133
3134 </script>';
3135 }
3136
3137 if (!$transcoding)
3138 {
3139
3140 $current_user = wp_get_current_user();
3141
3142
3143 global $wpdb;
3144 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . sanitize_file_name($stream) . "' and post_type='channel' LIMIT 0,1" );
3145
3146 if ($options['externalKeysTranscoder'])
3147 {
3148 $key = md5('vw' . $options['webKey'] . $current_user->ID . $postID);
3149
3150 $keyView = md5('vw' . $options['webKey']. $postID);
3151
3152 //?session&room&key&broadcaster&broadcasterid
3153 $rtmpAddress = $options['rtmp_server'] . '?'. urlencode('i_' . $stream) .'&'. urlencode($stream) .'&'. $key . '&1&' . $current_user->ID . '&videowhisper';
3154 $rtmpAddressView = $options['rtmp_server'] . '?'. urlencode('ffmpeg_' . $stream) .'&'. urlencode($stream) .'&'. $keyView . '&0&videowhisper';
3155
3156 //VWliveStreaming::webSessionSave("/i_". $stream, 1);
3157 }
3158 else
3159 {
3160 $rtmpAddress = $options['rtmp_server'];
3161 $rtmpAddressView = $options['rtmp_server'];
3162 }
3163
3164 echo "Transcoding process currently not active for '$stream'.<BR>";
3165 $log_file = $upath . "videowhisper_transcode.log";
3166
3167
3168 exec("tail -n 1 $log_file", $output1, $returnvalue);
3169 echo "Logs: ". substr($output1[0],0,100) . " ...<br>";
3170
3171 //-vcodec copy
3172 $cmd = $options['ffmpegPath'] .' ' . $options['ffmpegTranscode'] . " -threads 1 -f flv \"" .
3173 $rtmpAddress . "/i_". $stream . "\" -i \"" . $rtmpAddressView ."/". $stream . "\" >&$log_file & ";
3174
3175
3176 //echo $cmd;
3177 exec($cmd, $output, $returnvalue);
3178 exec("echo '$cmd' >> $log_file.cmd", $output, $returnvalue);
3179
3180 $cmd = "ps aux | grep '/i_$stream -i rtmp'";
3181 exec($cmd, $output, $returnvalue);
3182 //var_dump($output);
3183
3184 foreach ($output as $line) if (strstr($line, "ffmpeg"))
3185 {
3186 $columns = preg_split('/\s+/',$line);
3187 echo "Launching transcoder process #".$columns[1]." ...";
3188 }
3189
3190
3191 echo '<script>
3192
3193 setTimeout(\' if (loaderTranscoder) if (loaderTranscoder.abort === \\\'function\\\') loaderTranscoder.abort(); if (transcodingOn) loaderTranscoder = $j("#videowhisperTranscoder").html(ajax_load).load("'.$admin_ajax.'?action=vwls_trans&task=enable&stream='.$stream.'");\', 120000 );
3194
3195 </script>';
3196
3197 }
3198
3199 $admin_ajax = admin_url() . 'admin-ajax.php';
3200
3201 echo "<BR><a target='_blank' href='".$admin_ajax . "?action=vwls_trans&task=html5&stream=$stream'> Preview </a> (open in Safari)";
3202 break;
3203
3204
3205 case 'close':
3206 if ( !is_user_logged_in() )
3207 {
3208 echo "Not authorised!";
3209 exit;
3210 }
3211
3212 $cmd = "ps aux | grep '/i_$stream -i rtmp'";
3213 exec($cmd, $output, $returnvalue);
3214 //var_dump($output);
3215
3216 $transcoding = 0;
3217 foreach ($output as $line) if (strstr($line, "ffmpeg"))
3218 {
3219 $columns = preg_split('/\s+/',$line);
3220 $cmd = "kill -9 " . $columns[1];
3221 exec($cmd, $output, $returnvalue);
3222 echo "<BR>Closing #".$columns[1]." CPU: ".$columns[2]." Mem: ".$columns[3];
3223 $transcoding = 1;
3224 }
3225
3226 if (!$transcoding)
3227 {
3228 echo "Transcoder not found for '$stream'! Nothing to close.";
3229 }
3230
3231 break;
3232
3233
3234 case "html5";
3235?>
3236<p>iOS live stream link (open with Safari or test with VLC): <a href="<?php echo $options['httpstreamer']?>i_<?php echo $stream?>/playlist.m3u8"><br />
3237 <?php echo $stream?> Video</a></p>
3238
3239
3240<p>HTML5 live video embed below should be accessible <u>only in <B>Safari</B> browser</u> (PC or iOS):</p>
3241<?php
3242 echo do_shortcode('[videowhisper_hls channel="'.$stream.'"]');
3243?>
3244<p> Due to HTTP based live streaming technology limitations, video can have 15s or more latency. Use a browser with flash support for faster interactions based on RTMP. </p>
3245<p>Most devices other than iOS, support regular flash playback for live streams.</p>
3246
3247<style type="text/css">
3248<!--
3249BODY
3250{
3251 margin:0px;
3252 background: #333;
3253 font-family: Arial, Helvetica, sans-serif;
3254 font-size: 14px;
3255 color: #EEE;
3256 padding: 20px;
3257}
3258
3259a {
3260 color: #F77;
3261 text-decoration: none;
3262}
3263-->
3264</style>
3265<?php
3266
3267 break;
3268 }
3269 die;
3270 }
3271
3272
3273
3274 function shortcode_livesnapshots()
3275 {
3276
3277
3278
3279 global $wpdb;
3280 $table_name = $wpdb->prefix . "vw_sessions";
3281 $table_name2 = $wpdb->prefix . "vw_lwsessions";
3282
3283 $root_url = get_bloginfo( "url" ) . "/";
3284
3285 //clean recordings
3286 VWliveStreaming::cleanSessions(0);
3287 VWliveStreaming::cleanSessions(1);
3288
3289
3290 $items = $wpdb->get_results("SELECT * FROM `$table_name` where status='1' and type='1'");
3291
3292 $livesnapshotsCode .= "<div>Live Channels";
3293 if ($items) foreach ($items as $item)
3294 {
3295 $count = $wpdb->get_results("SELECT count(*) as no FROM `$table_name2` where status='1' and type='1' and room='".$item->room."'");
3296
3297
3298 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $item->room . "' and post_type='channel' LIMIT 0,1" );
3299 if ($postID) $url = get_post_permalink($postID);
3300 else $url = plugin_dir_url(__FILE__) . 'ls/channel.php?n=' . urlencode($item->name);
3301
3302
3303 $urli = $root_url . "wp-content/plugins/videowhisper-live-streaming-integration/ls/snapshots/".urlencode($item->room). ".jpg";
3304 if (!file_exists("wp-content/plugins/videowhisper-live-streaming-integration/ls/snapshots/".urlencode($item->room). ".jpg")) $urli = $root_url .
3305 "wp-content/plugins/videowhisper-live-streaming-integration/ls/snapshots/no_video.png";
3306
3307 $livesnapshotsCode .= "<div style='border: 1px dotted #390; width: 240px; padding: 1px'><a href='$urlc'><IMG width='240px' SRC='$urli'><div ><B>".$item->room."</B>
3308(".($count[0]->no+1).") ".($item->message?": ".$item->message:"") ."</div></a></div>";
3309 }
3310 else $livesnapshotsCode .= "<div>No broadcasters online.</div>";
3311
3312 $livesnapshotsCode .= "</div> ";
3313
3314 $options = get_option('VWliveStreamingOptions');
3315 $state = 'block' ;
3316 if (!$options['videowhisper']) $state = 'none';
3317 $livesnapshotsCode .= '<div id="VideoWhisper" style="display: ' . $state . ';"><p>Powered by VideoWhisper <a href="https://videowhisper.com/?p=WordPress+Live+Streaming">Live Video
3318Streaming Software</a>.</p></div>';
3319
3320
3321 echo $livesnapshotsCode;
3322 }
3323
3324 //! Widget
3325
3326 function widget($args) {
3327 extract($args);
3328 echo $before_widget;
3329 echo $before_title;?>Live Streaming<?php echo $after_title;
3330 VWliveStreaming::widgetContent();
3331 echo $after_widget;
3332 }
3333
3334 function widgetContent()
3335 {
3336 global $wpdb;
3337 $table_name = $wpdb->prefix . "vw_sessions";
3338 $table_name2 = $wpdb->prefix . "vw_lwsessions";
3339
3340 $root_url = get_bloginfo( "url" ) . "/";
3341
3342 //clean recordings
3343 VWliveStreaming::cleanSessions(0);
3344 VWliveStreaming::cleanSessions(1);
3345
3346 $items = $wpdb->get_results("SELECT * FROM `$table_name` where status='1' and type='1'");
3347
3348 echo "<ul>";
3349 if ($items) foreach ($items as $item)
3350 {
3351 $count = $wpdb->get_results("SELECT count(id) as no FROM `$table_name2` where status='1' and type='1' and room='".$item->room."'");
3352
3353 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $item->room . "' and post_type='channel' LIMIT 0,1" );
3354 if ($postID) $url = get_post_permalink($postID);
3355 else $url = plugin_dir_url(__FILE__) . 'ls/channel.php?n=' . urlencode($item->name);
3356
3357
3358 echo "<li><a href='" . $url . "'><B>".$item->room."</B>
3359(".($count[0]->no+1).") ".($item->message?": ".$item->message:"") ."</a></li>";
3360 }
3361 else echo "<li>No broadcasters online.</li>";
3362 echo "</ul>";
3363
3364 $options = get_option('VWliveStreamingOptions');
3365
3366 if ($options['userChannels']||$options['anyChannels'])
3367 if (is_user_logged_in())
3368 {
3369 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
3370
3371 $current_user = wp_get_current_user();
3372
3373 if ($current_user->$userName) $username = $current_user->$userName;
3374 $username = sanitize_file_name($username);
3375 ?><a href="<?php echo plugin_dir_url(__FILE__); ?>ls/?n=<?php echo $username ?>"><img src="<?php echo plugin_dir_url(__FILE__);
3376 ?>ls/templates/live/i_webcam.png" align="absmiddle" border="0">Video Broadcast</a>
3377 <?php
3378 }
3379
3380 $state = 'block' ;
3381 if (!$options['videowhisper']) $state = 'none';
3382 echo '<div id="VideoWhisper" style="display: ' . $state . ';"><p>Powered by VideoWhisper <a href="https://videowhisper.com/?p=WordPress+Live+Streaming">Live Video Streaming
3383Software</a>.</p></div>';
3384 }
3385
3386
3387 function delete_associated_media($id, $unlink=false, $except=0) {
3388
3389 $htmlCode .= "Removing... ";
3390
3391 $media = get_children(array(
3392 'post_parent' => $id,
3393 'post_type' => 'attachment'
3394 ));
3395 if (empty($media)) return $htmlCode;
3396
3397 foreach ($media as $file) {
3398
3399 if ($except) if ($file->ID == $except) break;
3400
3401 if ($unlink)
3402 {
3403 $filename = get_attached_file($file->ID);
3404 $htmlCode .= " Removing $filename #" . $file->ID;
3405 if (file_exists($filename)) unlink($filename);
3406 }
3407
3408 wp_delete_attachment($file->ID);
3409 }
3410
3411 return $htmlCode;
3412 }
3413
3414
3415 //! Channel Post
3416
3417 function the_title($title) {
3418 $title = esc_attr($title);
3419 $findthese = array(
3420 '#Protected:#',
3421 '#Private:#'
3422 );
3423 $replacewith = array(
3424 '', // What to replace "Protected:" with
3425 '' // What to replace "Private:" with
3426 );
3427 $title = preg_replace($findthese, $replacewith, $title);
3428 return $title;
3429 }
3430
3431
3432 function channel_page($content)
3433 {
3434
3435 $options = get_option('VWliveStreamingOptions');
3436 if (!$options['postChannels']) return $content;
3437
3438 if (!is_single()) return $content;
3439 $postID = get_the_ID() ;
3440
3441 if (get_post_type( $postID ) != $options['custom_post']) return $content;
3442
3443 // global $wpdb;
3444 // $stream = $wpdb->get_var( "SELECT post_name FROM $wpdb->posts WHERE ID = '" . $postID . "' and post_type='channel' LIMIT 0,1" );
3445
3446
3447 $stream = sanitize_file_name(get_the_title($postID));
3448
3449 global $wp_query;
3450
3451 $showBroadcastInterface = 0;
3452 if ($options['broadcasterRedirect'] && !array_key_exists( 'broadcast' , $wp_query->query_vars )) //don't redirect from broadcast page
3453 {
3454 $user = wp_get_current_user();
3455 if ( $user->exists()) //loggedin
3456 {
3457 $post = get_post($postID);
3458
3459 if ($user->ID == $post->post_author) //owner
3460 {
3461 if ($options['broadcasterRedirect'] == 'broadcast') $showBroadcastInterface = 1;
3462
3463 if ($options['broadcasterRedirect'] == 'dashboard')
3464 {
3465 $url = get_permalink(get_option("vwls_page_manage"));
3466 $string = '<script type="text/javascript">';
3467 $string .= 'window.location = "' . $url . '"';
3468 $string .= '</script>';
3469
3470 return $string;
3471 }
3472 }
3473 }
3474 }
3475
3476 $offline = '';
3477
3478 if( array_key_exists( 'broadcast' , $wp_query->query_vars ) || $showBroadcastInterface )
3479 {
3480 if (! $addCode = $offline = VWliveStreaming::channelInvalid($stream, true))
3481 $addCode = '[videowhisper_broadcast]';
3482 $showBroadcastInterface = 1;
3483 }
3484 elseif( array_key_exists( 'video' , $wp_query->query_vars ) )
3485 {
3486 if (! $addCode = $offline = VWliveStreaming::channelInvalid($stream))
3487 $addCode = '[videowhisper_video]';
3488 }
3489 elseif( array_key_exists( 'hls' , $wp_query->query_vars ) )
3490 {
3491 if (! $addCode = $offline = VWliveStreaming::channelInvalid($stream))
3492 $addCode = '[videowhisper_hls]';
3493 }
3494 elseif( array_key_exists( 'external' , $wp_query->query_vars ) )
3495 {
3496 $addCode = '[videowhisper_external]';
3497 $content = '';
3498 }
3499 else
3500 {
3501 if (! $addCode = $offline = VWliveStreaming::channelInvalid($stream))
3502 $addCode = "" . '[videowhisper_watch]';
3503 }
3504
3505 //ip camera or playlist: update snapshot
3506 if (get_post_meta( $postID, 'vw_ipCamera', true ) || get_post_meta( $postID, 'vw_playlistActive', true ))
3507 {
3508 VWliveStreaming::streamSnapshot($stream, true);
3509 }
3510
3511
3512 //set thumb
3513 $dir = $options['uploadsPath']. "/_snapshots";
3514 $thumbFilename = "$dir/$stream.jpg";
3515
3516 $attach_id = get_post_thumbnail_id($postID);
3517
3518 //update post thumb if file exists and missing post thumb
3519 if ( file_exists($thumbFilename) && !get_post_thumbnail_id( $postID ))
3520 {
3521 $wp_filetype = wp_check_filetype(basename($thumbFilename), null );
3522
3523 $attachment = array(
3524 'guid' => $thumbFilename,
3525 'post_mime_type' => $wp_filetype['type'],
3526 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $thumbFilename, ".jpg" ) ),
3527 'post_content' => '',
3528 'post_status' => 'inherit'
3529 );
3530
3531 $attach_id = wp_insert_attachment( $attachment, $thumbFilename, $postID );
3532 set_post_thumbnail($postID, $attach_id);
3533
3534 require_once( ABSPATH . 'wp-admin/includes/image.php' );
3535 $attach_data = wp_generate_attachment_metadata( $attach_id, $thumbFilename );
3536 wp_update_attachment_metadata( $attach_id, $attach_data );
3537 }
3538
3539 //clean other media
3540 if ($postID && $attach_id) VWliveStreaming::delete_associated_media($postID, false, $attach_id);
3541
3542
3543 $maxViewers = get_post_meta($postID, 'maxViewers', true);
3544 if (!is_array($maxViewers)) if ($maxViewers>0)
3545 {
3546 $maxDate = (int) get_post_meta($postID, 'maxDate', true);
3547 $addCode .= __('Maximum viewers','livestreaming') . ': ' . $maxViewers;
3548 if ($maxDate) $addCode .= ' on ' . date("F j, Y, g:i a", $maxDate);
3549 }
3550
3551
3552 if (!$offline) $addCode .= VWliveStreaming::eventInfo($postID);
3553
3554
3555 return $addCode . $content;
3556 }
3557
3558 function eventInfo($postID)
3559 {
3560 $eventTitle = get_post_meta($postID, 'eventTitle', true);
3561 if ($eventTitle)
3562 {
3563 $eventStart = get_post_meta($postID, 'eventStart', true);
3564 $eventEnd = get_post_meta($postID, 'eventEnd', true);
3565 $eventStartTime = get_post_meta($postID, 'eventStartTime', true);
3566 $eventEndTime = get_post_meta($postID, 'eventEndTime', true);
3567
3568 $eventDescription= get_post_meta($postID, 'eventDescription', true);
3569
3570 $showImage=get_post_meta( $postID, 'showImage', true );
3571 if ($showImage == 'event' || $showImage == 'all')
3572 {
3573 //get post thumb
3574 $attach_id = get_post_thumbnail_id($postID);
3575 if ($attach_id) $thumbFilename = get_attached_file($attach_id);
3576
3577 if (file_exists($thumbFilename)) $snapshot = VWliveStreaming::path2url($thumbFilename);
3578
3579 $eventCode .= '<IMG style="padding: 10px" SRC="'.$snapshot.'" ALIGN="LEFT">';
3580
3581 }
3582 $eventCode .= '<BR>';
3583 $eventCode .= '<H3>' . $eventTitle. '</H3>';
3584 if ($eventStart||$eventStartTime) $eventCode .= 'Starts: '.$eventStart . ' ' . $eventStartTime;
3585 if ($eventEnd||$eventEndTime) $eventCode .= '<BR>Ends: '.$eventEnd . ' ' . $eventEndTime ;
3586 if ($eventDescription) $eventCode .= '<p>'.$eventDescription.'</p>';
3587 $eventCode .= '<BR style="clear:both">';
3588 } else return '';
3589
3590 return $eventCode;
3591
3592 }
3593 public static function pre_get_posts($query)
3594 {
3595
3596 //add channels to post listings
3597 if(is_category() || is_tag())
3598 {
3599 $query_type = get_query_var('post_type');
3600
3601 if($query_type)
3602 if (is_array($query_type))
3603 {
3604 if (in_array('post',$query_type) && !in_array('channel',$query_type))
3605 $query_type[] = 'channel';
3606 $query->set('post_type', $query_type);
3607 }
3608 //else //default
3609 // $query_type = array('post', 'channel');
3610
3611 }
3612
3613 return $query;
3614 }
3615
3616 function columns_head_channel($defaults) {
3617 $defaults['featured_image'] = 'Snapshot';
3618 $defaults['edate'] = 'Last Online';
3619
3620 return $defaults;
3621 }
3622
3623 function columns_register_sortable( $columns ) {
3624 $columns['edate'] = 'edate';
3625
3626 return $columns;
3627 }
3628
3629
3630 function columns_content_channel($column_name, $post_id)
3631 {
3632
3633 if ($column_name == 'featured_image')
3634 {
3635
3636 global $wpdb;
3637 $postName = $wpdb->get_var( "SELECT post_title FROM $wpdb->posts WHERE ID = '" . $post_id . "' and post_type='channel' LIMIT 0,1" );
3638
3639 if ($postName)
3640 {
3641 $options = get_option('VWliveStreamingOptions');
3642 $dir = $options['uploadsPath']. "/_thumbs";
3643 $thumbFilename = "$dir/" . $postName . ".jpg";
3644
3645 $url = VWliveStreaming::roomURL($postName);
3646
3647 if (file_exists($thumbFilename)) echo '<a href="' . $url . '"><IMG src="' . VWliveStreaming::path2url($thumbFilename) .'" width="' . $options['thumbWidth'] . 'px" height="' . $options['thumbHeight'] . 'px"></a>';
3648
3649 }
3650
3651
3652
3653 }
3654
3655 if ($column_name == 'edate')
3656 {
3657 $edate = get_post_meta($post_id, 'edate', true);
3658 if ($edate)
3659 {
3660 echo ' ' . VWliveStreaming::format_age(time() - $edate);
3661
3662 }
3663
3664
3665 }
3666
3667 }
3668
3669 public static function duration_column_orderby( $vars ) {
3670 if ( isset( $vars['orderby'] ) && 'edate' == $vars['orderby'] ) {
3671 $vars = array_merge( $vars, array(
3672 'meta_key' => 'edate',
3673 'orderby' => 'meta_value_num'
3674 ) );
3675 }
3676
3677 return $vars;
3678 }
3679
3680
3681 public static function query_vars( $query_vars ){
3682 // array of recognized query vars
3683 $query_vars[] = 'broadcast';
3684 $query_vars[] = 'video';
3685 $query_vars[] = 'hls';
3686 $query_vars[] = 'external';
3687 $query_vars[] = 'vwls_eula';
3688 $query_vars[] = 'vwls_crossdomain';
3689 $query_vars[] = 'vwls_fullchannel';
3690
3691 return $query_vars;
3692 }
3693
3694 function parse_request( &$wp )
3695 {
3696 if ( array_key_exists( 'vwls_eula', $wp->query_vars ) ) {
3697 $options = get_option('VWliveStreamingOptions');
3698 echo html_entity_decode(stripslashes($options['eula_txt']));
3699 exit();
3700 }
3701
3702 if ( array_key_exists( 'vwls_crossdomain', $wp->query_vars ) ) {
3703 $options = get_option('VWliveStreamingOptions');
3704 echo html_entity_decode(stripslashes($options['crossdomain_xml']));
3705 exit();
3706 }
3707
3708 if ( array_key_exists( 'vwls_fullchannel', $wp->query_vars ) ) {
3709
3710 $stream = sanitize_file_name($wp->query_vars['vwls_fullchannel']);
3711
3712 if (!$stream)
3713 {
3714 echo "No channel name provided!";
3715 exit;
3716
3717 }
3718
3719 echo '<title>' . $stream . '</title>
3720<body style="margin:0; padding:0; width:100%; height:100%">
3721';
3722 echo VWliveStreaming::html_watch($stream);
3723
3724 exit();
3725 }
3726
3727 }
3728
3729 // Register Custom Post Type
3730 function channel_post() {
3731
3732 $options = get_option('VWliveStreamingOptions');
3733 if (!$options['postChannels']) return;
3734
3735 //only if missing
3736 if (post_type_exists($options['custom_post'])) return;
3737
3738 $labels = array(
3739 'name' => _x( 'Channels', 'Post Type General Name', 'text_domain' ),
3740 'singular_name' => _x( 'Channel', 'Post Type Singular Name', 'text_domain' ),
3741 'menu_name' => __( 'Channels', 'text_domain' ),
3742 'parent_item_colon' => __( 'Parent Channel:', 'text_domain' ),
3743 'all_items' => __( 'All Channels', 'text_domain' ),
3744 'view_item' => __( 'View Channel', 'text_domain' ),
3745 'add_new_item' => __( 'Add New Channel', 'text_domain' ),
3746 'add_new' => __( 'New Channel', 'text_domain' ),
3747 'edit_item' => __( 'Edit Channel', 'text_domain' ),
3748 'update_item' => __( 'Update Channel', 'text_domain' ),
3749 'search_items' => __( 'Search Channels', 'text_domain' ),
3750 'not_found' => __( 'No Channels found', 'text_domain' ),
3751 'not_found_in_trash' => __( 'No Channels found in Trash', 'text_domain' ),
3752 );
3753 $args = array(
3754 'label' => __( 'channel', 'text_domain' ),
3755 'description' => __( 'Video Channels', 'text_domain' ),
3756 'labels' => $labels,
3757 'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'comments', 'custom-fields', 'page-attributes', ),
3758 'taxonomies' => array( 'category', 'post_tag' ),
3759 'hierarchical' => false,
3760 'public' => true,
3761 'show_ui' => true,
3762 'show_in_menu' => true,
3763 'show_in_nav_menus' => true,
3764 'show_in_admin_bar' => true,
3765 'menu_position' => 5,
3766 'can_export' => true,
3767 'has_archive' => true,
3768 'exclude_from_search' => false,
3769 'publicly_queryable' => true,
3770 'menu_icon' => 'dashicons-video-alt',
3771 'capability_type' => 'post',
3772 'capabilities' => array(
3773 'create_posts' => 'do_not_allow', // false < WP 4.5
3774 'edit_posts' => 'edit_posts',
3775 'edit_post' => 'edit_post',
3776 'edit_other_posts' => 'edit_other_posts',
3777 'delete_post' => 'delete_post',
3778
3779 ),
3780 'map_meta_cap' => true, // Set to `false`, if users are not allowed to edit/delete existing posts
3781 );
3782 register_post_type( $options['custom_post'], $args );
3783
3784 add_rewrite_endpoint( 'broadcast', EP_ALL );
3785 add_rewrite_endpoint( 'video', EP_ALL );
3786 add_rewrite_endpoint( 'hls', EP_ALL );
3787 add_rewrite_endpoint( 'external', EP_ALL );
3788
3789 add_rewrite_rule( 'eula.txt$', 'index.php?vwls_eula=1', 'top' );
3790 add_rewrite_rule( 'crossdomain.xml$', 'index.php?vwls_crossdomain=1', 'top' );
3791 add_rewrite_rule( '^fullchannel/([\w]*)?', 'index.php?vwls_fullchannel=$matches[1]', 'top' );
3792
3793
3794 //flush_rewrite_rules();
3795
3796 }
3797
3798
3799 //! Billing Integration
3800
3801 function balance($userID)
3802 {
3803 //get current user balance
3804
3805 if (!$userID) return 0;
3806
3807 if (function_exists( 'mycred_get_users_cred')) return mycred_get_users_cred($userID);
3808
3809 return 0;
3810 }
3811
3812 function transaction($ref = "ppv_live_webcams", $user_id = 1, $amount = 0, $entry = "PPV Live Webcams transaction.", $ref_id = null, $data = null)
3813 {
3814 //ref = explanation ex. ppv_client_payment
3815 //entry = explanation ex. PPV client payment in room.
3816 //utils: ref_id (int|string|array) , data (int|string|array|object)
3817
3818 if ($amount == 0) return; //nothing
3819
3820 if ($amount>0)
3821 {
3822 if (function_exists('mycred_add')) mycred_add($ref, $user_id, $amount, $entry, $ref_id, $data);
3823 }
3824 else
3825 {
3826 if (function_exists('mycred_subtract')) mycred_subtract( $ref, $user_id, $amount, $entry, $ref_id, $data );
3827 }
3828 }
3829
3830 function userPaidAccess($userID, $postID)
3831 {
3832 //checks if user has access to content that may be fore sale
3833
3834 if (!class_exists( 'myCRED_Sell_Content_Module' ) ) return true; //sell content disabled
3835
3836 $meta = get_post_meta($postID, 'myCRED_sell_content', true);
3837
3838 if (!$meta) return true; // not for sale
3839 if (!$meta['price']) return true; //or no price
3840
3841 if (!$userID) return false; //not logged in: did not purchase
3842
3843 //check transaction log
3844 global $wpdb;
3845
3846 $table_nameC = $wpdb->prefix . "myCRED_log";
3847 $isBuyer = $wpdb->get_col( $sql = "SELECT user_id FROM {$table_nameC} WHERE user_id={$userID} AND ref = 'buy_content' AND ref_id = {$postID} AND creds < 0" );
3848 if (!$isBuyer) return false; //did not purchase
3849 else return true;
3850 }
3851
3852 //! Admin
3853
3854
3855 function admin_init()
3856 {
3857 add_meta_box(
3858 'vwls-nav-menus',
3859 'Channel Categories',
3860 array('VWliveStreaming', 'nav_menus'),
3861 'nav-menus',
3862 'side',
3863 'default');
3864 }
3865
3866 function nav_menus()
3867 {
3868
3869 //$object, $taxonomy
3870
3871 global $nav_menu_selected_id;
3872 $taxonomy_name = 'category';
3873
3874 // Paginate browsing for large numbers of objects.
3875 $per_page = 50;
3876 $pagenum = isset( $_REQUEST[$taxonomy_name . '-tab'] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1;
3877 $offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0;
3878
3879 $args = array(
3880 'child_of' => 0,
3881 'exclude' => '',
3882 'hide_empty' => false,
3883 'hierarchical' => 1,
3884 'include' => '',
3885 'number' => $per_page,
3886 'offset' => $offset,
3887 'order' => 'ASC',
3888 'orderby' => 'name',
3889 'pad_counts' => false,
3890 );
3891
3892 $terms = get_terms( $taxonomy_name, $args );
3893
3894 if ( ! $terms || is_wp_error($terms) ) {
3895 echo '<p>' . __( 'No items.' ) . '</p>';
3896 return;
3897 }
3898
3899 $num_pages = ceil( wp_count_terms( $taxonomy_name , array_merge( $args, array('number' => '', 'offset' => '') ) ) / $per_page );
3900
3901 $page_links = paginate_links( array(
3902 'base' => add_query_arg(
3903 array(
3904 $taxonomy_name . '-tab' => 'all',
3905 'paged' => '%#%',
3906 'item-type' => 'taxonomy',
3907 'item-object' => $taxonomy_name,
3908 )
3909 ),
3910 'format' => '',
3911 'prev_text' => __('«'),
3912 'next_text' => __('»'),
3913 'total' => $num_pages,
3914 'current' => $pagenum
3915 ));
3916
3917 $db_fields = false;
3918 if ( is_taxonomy_hierarchical( $taxonomy_name ) ) {
3919 $db_fields = array( 'parent' => 'parent', 'id' => 'term_id' );
3920 }
3921
3922 $walker = new Walker_Nav_Menu_Checklist( $db_fields );
3923
3924 $current_tab = 'most-used';
3925 if ( isset( $_REQUEST[$taxonomy_name . '-tab'] ) && in_array( $_REQUEST[$taxonomy_name . '-tab'], array('all', 'most-used', 'search') ) ) {
3926 $current_tab = $_REQUEST[$taxonomy_name . '-tab'];
3927 }
3928
3929 if ( ! empty( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] ) ) {
3930 $current_tab = 'search';
3931 }
3932
3933 $removed_args = array(
3934 'action',
3935 'customlink-tab',
3936 'edit-menu-item',
3937 'menu-item',
3938 'page-tab',
3939 '_wpnonce',
3940 );
3941
3942?>
3943 <div id="taxonomy-<?php echo $taxonomy_name; ?>" class="taxonomydiv">
3944 <ul id="taxonomy-<?php echo $taxonomy_name; ?>-tabs" class="taxonomy-tabs add-menu-item-tabs">
3945 <li <?php echo ( 'most-used' == $current_tab ? ' class="tabs"' : '' ); ?>>
3946 <a class="nav-tab-link" data-type="tabs-panel-<?php echo esc_attr( $taxonomy_name ); ?>-pop" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($taxonomy_name . '-tab', 'most-used', remove_query_arg($removed_args))); ?>#tabs-panel-<?php echo $taxonomy_name; ?>-pop">
3947 <?php _e( 'Most Used' ); ?>
3948 </a>
3949 </li>
3950 <li <?php echo ( 'all' == $current_tab ? ' class="tabs"' : '' ); ?>>
3951 <a class="nav-tab-link" data-type="tabs-panel-<?php echo esc_attr( $taxonomy_name ); ?>-all" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($taxonomy_name . '-tab', 'all', remove_query_arg($removed_args))); ?>#tabs-panel-<?php echo $taxonomy_name; ?>-all">
3952 <?php _e( 'View All' ); ?>
3953 </a>
3954 </li>
3955 <li <?php echo ( 'search' == $current_tab ? ' class="tabs"' : '' ); ?>>
3956 <a class="nav-tab-link" data-type="tabs-panel-search-taxonomy-<?php echo esc_attr( $taxonomy_name ); ?>" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($taxonomy_name . '-tab', 'search', remove_query_arg($removed_args))); ?>#tabs-panel-search-taxonomy-<?php echo $taxonomy_name; ?>">
3957 <?php _e( 'Search' ); ?>
3958 </a>
3959 </li>
3960 </ul><!-- .taxonomy-tabs -->
3961
3962 <div id="tabs-panel-<?php echo $taxonomy_name; ?>-pop" class="tabs-panel <?php
3963 echo ( 'most-used' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
3964 ?>">
3965 <ul id="<?php echo $taxonomy_name; ?>checklist-pop" class="categorychecklist form-no-clear" >
3966 <?php
3967 $popular_terms = get_terms( $taxonomy_name, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false ) );
3968 $args['walker'] = $walker;
3969 echo walk_nav_menu_tree( array_map(array('VWliveStreaming', 'nav_menu_item'), $popular_terms), 0, (object) $args );
3970?>
3971 </ul>
3972 </div><!-- /.tabs-panel -->
3973
3974 <div id="tabs-panel-<?php echo $taxonomy_name; ?>-all" class="tabs-panel tabs-panel-view-all <?php
3975 echo ( 'all' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
3976 ?>">
3977 <?php if ( ! empty( $page_links ) ) : ?>
3978 <div class="add-menu-item-pagelinks">
3979 <?php echo $page_links; ?>
3980 </div>
3981 <?php endif; ?>
3982 <ul id="<?php echo $taxonomy_name; ?>checklist" data-wp-lists="list:<?php echo $taxonomy_name?>" class="categorychecklist form-no-clear">
3983 <?php
3984 $args['walker'] = $walker;
3985 echo walk_nav_menu_tree( array_map(array('VWliveStreaming', 'nav_menu_item'), $terms), 0, (object) $args );
3986?>
3987 </ul>
3988 <?php if ( ! empty( $page_links ) ) : ?>
3989 <div class="add-menu-item-pagelinks">
3990 <?php echo $page_links; ?>
3991 </div>
3992 <?php endif; ?>
3993 </div><!-- /.tabs-panel -->
3994
3995 <div class="tabs-panel <?php
3996 echo ( 'search' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
3997 ?>" id="tabs-panel-search-taxonomy-<?php echo $taxonomy_name; ?>">
3998 <?php
3999 if ( isset( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] ) ) {
4000 $searched = esc_attr( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] );
4001 $search_results = get_terms( $taxonomy_name, array( 'name__like' => $searched, 'fields' => 'all', 'orderby' => 'count', 'order' => 'DESC', 'hierarchical' => false ) );
4002 } else {
4003 $searched = '';
4004 $search_results = array();
4005 }
4006?>
4007 <p class="quick-search-wrap">
4008 <input type="search" class="quick-search input-with-default-title" title="<?php esc_attr_e('Search'); ?>" value="<?php echo $searched; ?>" name="quick-search-taxonomy-<?php echo $taxonomy_name; ?>" />
4009 <span class="spinner"></span>
4010 <?php submit_button( __( 'Search' ), 'button-small quick-search-submit button-secondary hide-if-js', 'submit', false, array( 'id' => 'submit-quick-search-taxonomy-' . $taxonomy_name ) ); ?>
4011 </p>
4012
4013 <ul id="<?php echo $taxonomy_name; ?>-search-checklist" data-wp-lists="list:<?php echo $taxonomy_name?>" class="categorychecklist form-no-clear">
4014 <?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?>
4015 <?php
4016 $args['walker'] = $walker;
4017 echo walk_nav_menu_tree( array_map(array('VWliveStreaming', 'nav_menu_item'), $search_results), 0, (object) $args );
4018?>
4019 <?php elseif ( is_wp_error( $search_results ) ) : ?>
4020 <li><?php echo $search_results->get_error_message(); ?></li>
4021 <?php elseif ( ! empty( $searched ) ) : ?>
4022 <li><?php _e('No results found.'); ?></li>
4023 <?php endif; ?>
4024 </ul>
4025 </div><!-- /.tabs-panel -->
4026
4027 <p class="button-controls">
4028 <span class="list-controls">
4029 <a href="<?php
4030 echo esc_url(add_query_arg(
4031 array(
4032 $taxonomy_name . '-tab' => 'all',
4033 'selectall' => 1,
4034 ),
4035 remove_query_arg($removed_args)
4036 ));
4037 ?>#taxonomy-<?php echo $taxonomy_name; ?>" class="select-all"><?php _e('Select All'); ?></a>
4038 </span>
4039
4040 <span class="add-to-menu">
4041 <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-taxonomy-menu-item" id="<?php echo esc_attr( 'submit-taxonomy-' . $taxonomy_name ); ?>" />
4042 <span class="spinner"></span>
4043 </span>
4044 </p>
4045
4046 </div><!-- /.taxonomydiv -->
4047 <?php
4048 }
4049
4050
4051 function single_template($single_template)
4052 {
4053
4054 if (!is_single()) return $single_template;
4055
4056 $options = get_option('VWliveStreamingOptions');
4057 //if (!$options['custom_post']) $options['custom_post'] = 'channel';
4058
4059 $postID = get_the_ID();
4060
4061 if ( get_post_type( $postID ) != $options['custom_post']) return $single_template;
4062
4063 if ($options['postTemplate'] == '+plugin')
4064 {
4065 $single_template_new = dirname( __FILE__ ) . '/template-channel.php';
4066 if (file_exists($single_template_new)) return $single_template_new;
4067 }
4068
4069
4070 $single_template_new = get_stylesheet_directory() . '/' . $options['postTemplate'];
4071
4072 if (file_exists($single_template_new)) return $single_template_new;
4073 else return $single_template;
4074 }
4075
4076 function nav_menu_item( $menu_item )
4077 {
4078
4079 $menu_item->ID = $menu_item->term_id;
4080 $menu_item->db_id = 0;
4081 $menu_item->menu_item_parent = 0;
4082 $menu_item->object_id = (int) $menu_item->term_id;
4083 $menu_item->post_parent = (int) $menu_item->parent;
4084 $menu_item->type = 'custom';
4085
4086 $object = get_taxonomy( $menu_item->taxonomy );
4087 $menu_item->object = $object->name;
4088 $menu_item->type_label = $object->labels->singular_name;
4089
4090 $menu_item->title = $menu_item->name;
4091
4092 $options = get_option('VWliveStreamingOptions');
4093 if ($options['disablePageC']=='0')
4094 {
4095 $page_id = get_option("vwls_page_channels");
4096 $permalink = get_permalink( $page_id);
4097 $menu_item->url = add_query_arg(array('cid' => $menu_item->object_id, 'category' => $menu_item->name), $permalink);
4098 } else $menu_item->url = get_term_link( $menu_item, $menu_item->taxonomy ) . '?channels=1' ;
4099
4100 $menu_item->target = '';
4101 $menu_item->attr_title = '';
4102 $menu_item->description = get_term_field( 'description', $menu_item->term_id, $menu_item->taxonomy );
4103 $menu_item->classes = array();
4104 $menu_item->xfn = '';
4105
4106 /**
4107 * @param object $menu_item The menu item object.
4108 */
4109 return $menu_item;
4110 }
4111
4112
4113 function getDirectorySize($path)
4114 {
4115 $totalsize = 0;
4116 $totalcount = 0;
4117 $dircount = 0;
4118
4119 if (!file_exists($path))
4120 {
4121 $total['size'] = $totalsize;
4122 $total['count'] = $totalcount;
4123 $total['dircount'] = $dircount;
4124 return $total;
4125 }
4126
4127 if ($handle = opendir($path))
4128 {
4129 while (false !== ($file = readdir($handle)))
4130 {
4131 $nextpath = $path . '/' . $file;
4132 if ($file != '.' && $file != '..' && !is_link($nextpath))
4133 {
4134 if (is_dir($nextpath))
4135 {
4136 $dircount++;
4137 $result = VWliveStreaming::getDirectorySize($nextpath);
4138 $totalsize += $result['size'];
4139 $totalcount += $result['count'];
4140 $dircount += $result['dircount'];
4141 }
4142 elseif (is_file($nextpath))
4143 {
4144 $totalsize += filesize($nextpath);
4145 $totalcount++;
4146 }
4147 }
4148 }
4149 }
4150 closedir($handle);
4151 $total['size'] = $totalsize;
4152 $total['count'] = $totalcount;
4153 $total['dircount'] = $dircount;
4154 return $total;
4155 }
4156
4157 function sizeFormat($size)
4158 {
4159 //echo $size;
4160 if($size<1024)
4161 {
4162 return $size." bytes";
4163 }
4164 else if($size<(1024*1024))
4165 {
4166 $size=round($size/1024,2);
4167 return $size." KB";
4168 }
4169 else if($size<(1024*1024*1024))
4170 {
4171 $size=round($size/(1024*1024),2);
4172 return $size." MB";
4173 }
4174 else
4175 {
4176 $size=round($size/(1024*1024*1024),2);
4177 return $size." GB";
4178 }
4179
4180 }
4181
4182 function admin_menu() {
4183
4184 add_menu_page('Live Streaming', 'Live Streaming', 'manage_options', 'live-streaming', array('VWliveStreaming', 'options'), 'dashicons-video-alt',82);
4185 add_submenu_page("live-streaming", "Live Streaming", "Settings", 'manage_options', "live-streaming", array('VWliveStreaming', 'options'));
4186 add_submenu_page("live-streaming", "Live Streaming", "Statistics", 'manage_options', "live-streaming-stats", array('VWliveStreaming', 'adminStats'));
4187 add_submenu_page("live-streaming", "Live Streaming", "Live & Ban", 'manage_options', "live-streaming-live", array('VWliveStreaming', 'adminLive'));
4188 add_submenu_page("live-streaming", "Live Streaming", "Documentation", 'manage_options', "live-streaming-docs", array('VWliveStreaming', 'adminDocs'));
4189
4190 //hide add submenu
4191 global $submenu;
4192 unset($submenu['edit.php?post_type=channel'][10]);
4193 }
4194
4195 function admin_head() {
4196 if( get_post_type() != 'channel') return;
4197
4198 //hide add button
4199 echo '<style type="text/css">
4200 #favorite-actions {display:none;}
4201 .add-new-h2{display:none;}
4202 .tablenav{display:none;}
4203 </style>';
4204 }
4205
4206
4207 function adminStats()
4208 {
4209 $options = get_option('VWliveStreamingOptions');
4210
4211?>
4212 <h3>Channels Statistics</h3>
4213<?php
4214
4215
4216
4217 if ($_GET['regenerateThumbs'])
4218 {
4219 $dir=$options['uploadsPath'];
4220 $dir .= "/_snapshots";
4221 echo '<div class="info">Regenerating thumbs for listed channels.</div>';
4222 }
4223
4224 global $wpdb;
4225 $table_name = $wpdb->prefix . "vw_sessions";
4226 $table_name2 = $wpdb->prefix . "vw_lwsessions";
4227 $table_name3 = $wpdb->prefix . "vw_lsrooms";
4228
4229 $items = $wpdb->get_results("SELECT * FROM `$table_name3` ORDER BY edate DESC LIMIT 0, 200");
4230 echo "<table class='wp-list-table widefat'><thead><tr><th>Channel</th><th>Last Access</th><th>Broadcast Time</th><th>Watch Time</th><th>Last Reset</th><th>Type</th><th>Logs</th></tr></thead>";
4231
4232
4233
4234 if ($items) foreach ($items as $item)
4235 {
4236 echo "<tr><th>".$item->name;
4237
4238 if ($_GET['regenerateThumbs'])
4239 {
4240 //
4241 $stream=$item->name;
4242 $filename = "$dir/$stream.jpg";
4243
4244 if (file_exists($filename))
4245 {
4246 //generate thumb
4247 $thumbWidth = $options['thumbWidth'];
4248 $thumbHeight = $options['thumbHeight'];
4249
4250 $src = imagecreatefromjpeg($filename);
4251 list($width, $height) = getimagesize($filename);
4252 $tmp = imagecreatetruecolor($thumbWidth, $thumbHeight);
4253
4254 $dir = $options['uploadsPath']. "/_thumbs";
4255 if (!file_exists($dir)) mkdir($dir);
4256
4257 $thumbFilename = "$dir/$stream.jpg";
4258 imagecopyresampled($tmp, $src, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $width, $height);
4259 imagejpeg($tmp, $thumbFilename, 95);
4260
4261 $sql="UPDATE `$table_name3` set status='1' WHERE name ='$stream'";
4262 $wpdb->query($sql);
4263
4264
4265 } else
4266 {
4267 echo "<div class='warning'>Snapshot missing!</div>";
4268 $sql="UPDATE `$table_name3` set status='0' WHERE name ='$stream'";
4269 $wpdb->query($sql);
4270
4271 }
4272 }
4273
4274 global $wpdb;
4275 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $item->name . "' and post_type='channel' LIMIT 0,1" );
4276
4277 if (!$options['anyChannels'] && !$options['userChannels'])
4278 {
4279 if (!$postID)
4280 {
4281 $wpdb->query( "DELETE FROM `$table_name3` WHERE name ='".$item->name."'");
4282 echo "<br>DELETED: No channel post.";
4283 }
4284 }
4285
4286
4287 echo "</th><td>". VWliveStreaming::format_age(time() - $item->edate)."</td><td>". VWliveStreaming::format_time($item->btime) . "</td><td>". VWliveStreaming::format_time($item->wtime)."</td><td>" . VWliveStreaming::format_age(time() - $item->rdate)."</td><td>".($item->type>1?"Premium " . ($item->type-1) :"Standard")."</td>";
4288
4289 //channel text logs
4290 $upload_c = VWliveStreaming::getDirectorySize($options['uploadsPath'] . '/'.$item->name);
4291 $upload_size = VWliveStreaming::sizeFormat($upload_c['size']);
4292 $logsurl = VWliveStreaming::path2url($options['uploadsPath'] . '/'.$item->name);
4293
4294 echo '<td>'."<a target='_blank' href='$logsurl'>$upload_size ($upload_c[count] files)</a>".'</td></tr>';
4295
4296 $broadcasting = $wpdb->get_results("SELECT * FROM `$table_name` WHERE room = '".$item->name."' ORDER BY edate DESC LIMIT 0, 100");
4297 if ($broadcasting)
4298 foreach ($broadcasting as $broadcaster)
4299 {
4300 echo "<tr><td colspan='7'> - " . $broadcaster->username . " Type: " . $broadcaster->type . " Status: " . $broadcaster->status . " Started: " . VWliveStreaming::format_age(time() -$broadcaster->sdate). "</td></tr>";
4301 }
4302
4303 if ($postID)
4304 {
4305 $videoCodec = get_post_meta($postID, 'stream-codec-video', true);
4306 if ($videoCodec) echo "<tr><td colspan='7'> - Video Codec: " . $videoCodec . " Audio Codec: " . get_post_meta($postID, 'stream-codec-audio', true) . " Detection time: " . VWliveStreaming::format_age(time() - get_post_meta($postID, 'stream-codec-detect', true)). "</td></tr>";
4307 }
4308
4309 //
4310
4311 }
4312 echo "</table>";
4313?>
4314<p>This page shows latest accessed channels (maximum 200).</p>
4315 <p>External players and encoders (if enabled) are not monitored or controlled by this plugin, unless special <a href="https://videowhisper.com/?p=RTMP-Session-Control">rtmp side session control</a> is available.</p>
4316
4317
4318 <?php
4319
4320 //channel text logs
4321 $upload_c = VWliveStreaming::getDirectorySize($options['uploadsPath'] );
4322 $upload_size = VWliveStreaming::sizeFormat($upload_c['size']);
4323 $logsurl = VWliveStreaming::path2url($options['uploadsPath']);
4324
4325 echo '<p>Total temporary file usage (logs, snapshots, session info): '." <a target='_blank' href='$logsurl'>$upload_size (in $upload_c[count] files and $upload_c[dircount] folders)</a>".'</p>';
4326
4327 }
4328
4329 function adminLive()
4330 {
4331 $options = get_option('VWliveStreamingOptions');
4332
4333 $ban = sanitize_file_name($_GET['ban']);
4334
4335 if ($ban)
4336 {
4337?>
4338<h3>Banning Channel</h3>
4339<?php
4340 global $wpdb;
4341
4342 //delete post
4343 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $ban . "' and post_type='channel' LIMIT 0,1" );
4344 if (!$postID) echo "<br>Channel post '$ban' not found!";
4345 else
4346 {
4347 wp_delete_post($postID, true);
4348 echo "<br>Channel post '$ban' was deleted.";
4349 }
4350
4351 //delete room
4352 $table_name = $wpdb->prefix . "vw_lsrooms";
4353 $sql="DELETE FROM `$table_name` WHERE name = '$ban'";
4354 $wpdb->query($sql);
4355 echo "<br>Channel room '$ban' was deleted.";
4356
4357 //ban
4358 $options['bannedNames'] .= ($options['bannedNames']?',':'') . $ban;
4359 update_option('VWliveStreamingOptions', $options);
4360 echo '<br>Current ban list: ' . $options['bannedNames'] . ' <a href="admin.php?page=live-streaming&tab=broadcaster" class="button button-primary">Edit</a>';
4361 }
4362
4363 //broadcast link if allowed by settings
4364 if ($options['userChannels']||$options['anyChannels'])
4365 {
4366
4367 $root_url = get_bloginfo( "url" ) . "/";
4368 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
4369
4370 $current_user = wp_get_current_user();
4371
4372 if ($current_user->$userName) $username = $current_user->$userName;
4373 $username = sanitize_file_name($username);
4374
4375 $broadcast_url = admin_url() . 'admin-ajax.php?action=vwls_broadcast&n=';
4376
4377?>
4378
4379<h3>Channel '<?php echo $username; ?>': Go Live</h3>
4380<ul>
4381<li>
4382<a href="<?php echo $broadcast_url . urlencode($username); ?>"><img src="<?php echo $root_url; ?>wp-content/plugins/videowhisper-live-streaming-integration/ls/templates/live/i_webcam.png"
4383align="absmiddle" border="0">Start Broadcasting</a>
4384</li>
4385<li>
4386<a href="<?php echo $root_url; ?>wp-content/plugins/videowhisper-live-streaming-integration/ls/channel.php?n=<?php echo $username; ?>"><img src="<?php echo $root_url;
4387 ?>wp-content/plugins/videowhisper-live-streaming-integration/ls/templates/live/i_uvideo.png" align="absmiddle" border="0">View Channel</a>
4388</li>
4389</ul>
4390<p>To allow users to broadcast from frontend (as configured in settings), <a href='widgets.php'>enable the widget</a> and/or channel posts and frontend management page.
4391<br>On some templates/setups you also need to add the page to site menu.
4392</p>
4393<?php
4394 }
4395?>
4396<h3>Recent Channels</h3>
4397<?php
4398
4399 echo do_shortcode('[videowhisper_channels ban="1"]');
4400
4401 }
4402
4403 function adminDocs()
4404 {
4405?>
4406<h2>VideoWhisper Live Streaming</h2>
4407
4408<h3>Quick Setup Tutorial</h3>
4409<ol>
4410<li>Install and activate the VideoWhisper Live Streaming Integration plugin </li>
4411<li>From <a href="admin.php?page=live-streaming&tab=server">Live Streaming > Settings : Server</a> in WP backend and configure settings (it's compulsory to fill a valid RTMP hosting address)</li>
4412<li>From <a href="options-permalink.php">Settings > Permalinks</a> enable a SEO friendly structure (ex. Post name)</li>
4413<li>From <a href="nav-menus.php">Appearance > Menus</a> add Channels and Broadcast Live pages to main site menu.
4414<ul>
4415 <li>Users can setup their channels and start broadcast from Broadcast Live page:
4416 <br><?php echo get_permalink(get_option("vwls_page_manage"))?></li>
4417 <li>After broadcasting, channels show in Channels list:
4418 <br><?php echo get_permalink(get_option("vwls_page_channels"))?></li>
4419</ul>
4420</li>
4421<li>Install and enable a <a href="admin.php?page=live-streaming&tab=billing">billing plugin</a> to allow owners to sell channel access</li>
4422<li>Install and enable the <a href="https://videosharevod.com/">VideoShareVOD</a> plugin to enable video broadcast archiving, video publishing, management</li>
4423</ol>
4424
4425<h3>ShortCodes</h3>
4426<ul>
4427 <li><h4>[videowhisper_watch channel="Channel Name" width="100%" height="100%"]</h4>
4428 Displays watch interface with video and discussion. If iOS is detected it shows HLS instead. Container style can be configured from plugin settings.</li>
4429 <li><h4>[videowhisper_video channel="Channel Name" width="480px" height="360px"]</h4>
4430 Displays video only interface. If iOS is detected it shows HLS instead.</li>
4431 <li><h4>[videowhisper_hls channel="Channel Name" width="480px" height="360px"]</h4>
4432 Displays HTML5 HLS (HTTP Live Streaming) video interface. Shows istead of watch and video interfaces if iOS is detected. Stream must be published in compatible format (H264,AAC) or transcoding must be enabled and active for stream to show.</li>
4433 <li>
4434 <h4>[videowhisper_broadcast channel="Channel Name"]</h4>
4435 Shows broadcasting interface. Channel name is detected depending on settings, post type, user. Only owner can access for channel posts.
4436 </li>
4437 <li>
4438 <h4>[videowhisper_external channel="Channel Name"]</h4>
4439 Shows settings for broadcasting with external applications. Channel name is detected depending on settings, post type, user. Only owner can access for channel posts.
4440 </li>
4441 <li>
4442 <h4>[videowhisper_channels perPage="4" perrow="" order_by="edate" category_id="" select_category="1" select_order="1" select_page="1" include_css="1" ban="0" id=""]</h4>
4443 Lists channels with snapshots, ordered by most recent online and with pagination.
4444 </li>
4445 <li>
4446 <h4>[videowhisper_livesnapshots]</h4>
4447 Older shortcode for backward compatibility. Displays full size snapshots of online channels. No pagination.
4448 </li>
4449 <li>
4450 <h4>
4451 [videowhisper_channel_manage]
4452 </h4>
4453 Displays channel management page.
4454 </li>
4455</ul>
4456<h3>Documentation, Support, Customizations</h3>
4457<ul>
4458<li>Home Page and Documentation: <a href="https://videowhisper.com/?p=WordPress+Live+Streaming">VideoWhisper - WordPress Live Streaming</a></li>
4459<li>WordPress Plugin Page: <a href="https://wordpress.org/plugins/videowhisper-live-streaming-integration/">VideoWhisper Live Streaming Integration</a></li>
4460<li>Contact Page: <a href="https://videowhisper.com/tickets_submit.php">Contact VideoWhisper</a></li>
4461</ul>
4462<p>After ordering solution and setting up existing editions, VideoWhisper.com developers can customize these for additional fees depending on exact requirements.</p>
4463 <?php
4464 }
4465
4466
4467 //! Channel Features List
4468
4469 function roomFeatures()
4470 {
4471 return array(
4472 'accessPassword' => array(
4473 'name'=>'Access Password',
4474 'description' =>'Can specify a password to protect channel access.',
4475 'installed' => 1,
4476 'default' => 'Super Admin, Administrator, Editor'),
4477 'accessList' => array(
4478 'name'=>'Access List',
4479 'description' =>'Channel owner can specify list of user logins, roles, emails that can access the channel.',
4480 'installed' => 1,
4481 'default' => 'None'),
4482 'accessPrice' => array(
4483 'name'=>'Access Price',
4484 'description' =>'Can setup a price per channel. Requires myCRED plugin installed and integration enabled from Billing.',
4485 'type' => 'number',
4486 'installed' => 1,
4487 'default' => 'None'),
4488 'chatList' => array(
4489 'name'=>'Chat List',
4490 'description' =>'Channel owner can specify list of user logins, roles, emails that can access the public chat.',
4491 'installed' => 1,
4492 'default' => 'None'),
4493 'writeList' => array(
4494 'name'=>'Chat Write List',
4495 'description' =>'Channel owner can specify list of user logins, roles, emails that can write in public chat.',
4496 'installed' => 1,
4497 'default' => 'None'),
4498 'participantsList' => array(
4499 'name'=>'Participants List',
4500 'description' =>'Channel owner can specify list of user logins, roles, emails that can view participants list.',
4501 'installed' => 1,
4502 'default' => 'None'),
4503 'privateChatList' => array(
4504 'name'=>'Private Chat List',
4505 'description' =>'Channel owner can specify list of user logins, roles, emails that can initiate private chat.',
4506 'installed' => 1,
4507 'default' => 'None'),
4508 'uploadPicture' => array(
4509 'name'=>'Upload Picture',
4510 'description' =>'Upload channel picture.',
4511 'installed' => 1,
4512 'default' => 'Super Admin, Administrator, Editor, Subscriber'),
4513 'eventDetails' => array(
4514 'name'=>'Event Details',
4515 'description' =>'Specify event title, start, end, description to show when show is offline.',
4516 'installed' => 1,
4517 'default' => 'Super Admin, Administrator, Editor, Subscriber'),
4518 'logoHide' => array(
4519 'name'=>'Hide Logo',
4520 'description' =>'Hides logo from channel.',
4521 'installed' => 1,
4522 'default' => 'Super Admin, Administrator, Editor'),
4523 'logoCustom' => array(
4524 'name'=>'Custom Logo',
4525 'description' =>'Can setup a custom logo. Overrides hide logo feature.',
4526 'installed' => 1,
4527 'default' => 'Super Admin, Administrator'),
4528 'adsHide' => array(
4529 'name'=>'Hide Ads',
4530 'description' =>'Hides ads from channel.',
4531 'installed' => 1,
4532 'default' => 'Super Admin, Administrator, Editor'),
4533 'ipCameras' => array(
4534 'name'=>'IP Cameras',
4535 'description' =>'Can configure re-streaming, including for IP cameras.',
4536 'installed' => 1,
4537 'default' => 'None'),
4538 'schedulePlaylists' => array(
4539 'name'=>'Playlist Scheduler',
4540 'description' =>'Can schedule channel playlist from VideoShareVOD videos.',
4541 'installed' => 1,
4542 'default' => 'None'),
4543 'adsCustom' => array(
4544 'name'=>'Custom Ads',
4545 'description' =>'Can setup a custom ad server. Overrides hide ads feature.',
4546 'installed' => 1,
4547 'default' => 'None'),
4548 'transcode' => array(
4549 'name'=>'Transcode',
4550 'description' =>'Enable transcoding for user channels.',
4551 'installed' => 1,
4552 'default' => 'Super Admin, Administrator, Editor'),
4553 'privateList' => array(
4554 'name'=>'Private Channels',
4555 'description' =>'Hide channels from public listings. Can be accessed by channel links.',
4556 'installed' => 0),
4557 'privateChat' => array(
4558 'name'=>'Private Chat',
4559 'description' =>'Disable chat from site watch interface.',
4560 'installed' => 0),
4561 'privateVideos' => array(
4562 'name'=>'Private Videos',
4563 'description' =>'Channel videos do not show in public listings. Only show on channel page.',
4564 'installed' => 0),
4565 'hiddenVideos' => array(
4566 'name'=>'Hidden Videos',
4567 'description' =>'Channel videos do not show in public or channel listings. Only owner can browse.',
4568 'installed' => 0),
4569 );
4570 }
4571
4572 //! Settings
4573 function adminOptionsDefault()
4574 {
4575 $root_url = get_bloginfo( "url" ) . "/";
4576 $upload_dir = wp_upload_dir();
4577
4578 return array(
4579 'userName' => 'user_nicename',
4580 'userPicture' => 'avatar',
4581 'profilePrefix' => $root_url.'author/',
4582 'profilePrefixChannel' => $root_url.'channel/',
4583 'loginLogo' => plugin_dir_url(__FILE__) .'login-logo.png',
4584
4585 'postChannels' => '1',
4586 'userChannels' => '0',
4587 'anyChannels' => '0',
4588
4589 'custom_post' => 'channel',
4590 'custom_post_video' => 'video',
4591
4592 'postTemplate' => '+plugin',
4593 'channelUrl' => 'post',
4594
4595 'disablePage' => '0',
4596 'disablePageC' => '0',
4597 'thumbWidth' => '240',
4598 'thumbHeight' => '180',
4599 'perPage' =>'6',
4600
4601 'postName' => 'custom',
4602
4603
4604 'rtmp_server' => 'rtmp://localhost/videowhisper',
4605 'rtmp_restrict_ip'=>'',
4606 'webStatus'=> 'auto',
4607
4608 'rtmp_amf' => 'AMF3',
4609 'httpstreamer' => 'http://localhost:1935/videowhisper-x/',
4610 'ffmpegPath' => '/usr/local/bin/ffmpeg',
4611 'ffmpegTranscode' => '-analyzeduration 0 -vcodec copy -acodec libfaac -ac 2 -ar 22050 -ab 96k',
4612 'streamsPath' => '/home/account/public_html/streams',
4613
4614 'ipcams' =>'0',
4615 'playlists' =>'0',
4616
4617 'canBroadcast' => 'members',
4618 'broadcastList' => 'Super Admin, Administrator, Editor, Author',
4619 'maxChannels' => '3',
4620 'externalKeys' => '1',
4621 'externalKeysTranscoder' => '1',
4622 'rtmpStatus' => '0',
4623
4624
4625 'canWatch' => 'all',
4626 'watchList' => 'Super Admin, Administrator, Editor, Author, Contributor, Subscriber',
4627 'onlyVideo' => '0',
4628 'noEmbeds' => '0',
4629
4630 'userWatchLimit' => '1',
4631 'userWatchInterval' => '2592000',
4632 'userWatchLimitDefault' => '108000',
4633 'userWatchLimits' => '',
4634 'userWatchLimitsConfig' => 'Administrator = 0
4635Super Admin = 0
4636Editor = 72000
4637Subscriber = 36000',
4638 'watchRoleParameters' => '',
4639 'watchRoleParametersConfig' =>'[disableChat]
4640Administrator = 0
4641Editor = 0
4642
4643[disableUsers]
4644Administrator = 0
4645Editor = 0
4646
4647[disableVideo]
4648Administrator = 0
4649Editor = 0
4650
4651[writeText]
4652Administrator = 1
4653Editor = 1
4654
4655[privateTextchat]
4656Administrator = 1
4657Editor = 1
4658 ',
4659
4660 'broadcasterRedirect' => '0',
4661
4662 'premiumList' => 'Super Admin, Administrator, Editor, Author',
4663 'canWatchPremium' => 'all',
4664 'watchListPremium' => 'Super Admin, Administrator, Editor, Author, Contributor, Subscriber',
4665
4666 'premiumLevelsNumber' =>'2',
4667 'premiumLevels' =>'',
4668
4669 // 'pLogo' => '1',
4670 'broadcastTime' => '600',
4671 'watchTime' => '3000',
4672 'pBroadcastTime' => '6000',
4673 'pWatchTime' => '30000',
4674 'timeReset' => '30',
4675 'bannedNames' => 'bann1, bann2',
4676
4677 'camResolution' => '640x480',
4678 'camFPS' => '15',
4679
4680 'camBandwidth' => '60000',
4681 'camMaxBandwidth' => '100000',
4682 'pCamBandwidth' => '75000',
4683 'pCamMaxBandwidth' => '200000',
4684 'transcoding' => '0',
4685 'transcodingAuto' => '2',
4686 'transcodingManual' => '0',
4687
4688 'videoCodec'=>'H264',
4689 'codecProfile' => 'baseline',
4690 'codecLevel' => '3.1',
4691
4692 'soundCodec'=> 'Nellymoser',
4693 'soundQuality' => '9',
4694 'micRate' => '22',
4695
4696 //! mobile settings
4697 'camResolutionMobile' => '480x360',
4698 'camFPSMobile' => '15',
4699
4700 'camBandwidthMobile' => '40000',
4701
4702 'videoCodecMobile'=>'H263',
4703 'codecProfileMobile' => 'baseline',
4704 'codecLevelMobile' => '3.1',
4705
4706 'soundCodecMobile'=> 'Speex',
4707 'soundQualityMobile' => '9',
4708 'micRateMobile' => '22',
4709 //mobile:end
4710
4711 'broadcastTime' => '600',
4712 'watchTime' => '3000',
4713 'pBroadcastTime' => '6000',
4714 'pWatchTime' => '30000',
4715 'timeReset' => '30',
4716 'bannedNames' => 'bann1, bann2',
4717
4718 'onlineExpiration0' =>'310',
4719 'onlineExpiration1' =>'40',
4720 'parameters' => '&bufferLive=1&bufferFull=1&showCredit=1&disconnectOnTimeout=1&offlineMessage=Channel+Offline&disableVideo=0&fillWindow=0&adsTimeout=15000&externalInterval=360000&statusInterval=90000&loaderProgress=1',
4721 'parametersBroadcaster' => '&bufferLive=2&bufferFull=2&showCamSettings=1&advancedCamSettings=1&configureSource=1&generateSnapshots=1&snapshotsTime=60000&room_limit=500&showTimer=1&showCredit=1&disconnectOnTimeout=1&externalInterval=360000&statusInterval=30000&loaderProgress=1&selectCam=1&selectMic=1',
4722 'layoutCode' => 'id=0&label=Video&x=10&y=45&width=325&height=298&resize=true&move=true; id=1&label=Chat&x=340&y=45&width=293&height=298&resize=true&move=true; id=2&label=Users&x=638&y=45&width=172&height=298&resize=true&move=true',
4723 'watchStyle' => 'width: 100%;
4724height: 400px;
4725border: solid 3px #999;',
4726
4727 'overLogo' => $root_url .'wp-content/plugins/videowhisper-live-streaming-integration/ls/logo.png',
4728 'loaderImage' => '',
4729
4730 'overLink' => 'https://videowhisper.com',
4731 'adServer' => 'ads',
4732 'adsInterval' => '20000',
4733 'adsCode' => '<B>Sample Ad</B><BR>Edit ads from plugin settings. Also edit Ads Interval in milliseconds (0 to disable ad calls). Also see <a href="http://www.adinchat.com" target="_blank"><U><B>AD in Chat</B></U></a> compatible ad management server for setting up ad rotation. Ads do not show on premium channels.',
4734
4735 'cssCode' =>'title {
4736 font-family: Arial, Helvetica, _sans;
4737 font-size: 11;
4738 font-weight: bold;
4739 color: #FFFFFF;
4740 letter-spacing: 1;
4741 text-decoration: none;
4742}
4743
4744story {
4745 font-family: Verdana, Arial, Helvetica, _sans;
4746 font-size: 14;
4747 font-weight: normal;
4748 color: #FFFFFF;
4749}',
4750 'translationCode' => '<t text="Video is Disabled" translation="Video is Disabled"/>
4751<t text="Bold" translation="Bold"/>
4752<t text="Sound is Enabled" translation="Sound is Enabled"/>
4753<t text="Publish a video stream using the settings below without any spaces." translation="Publish a video stream using the settings below without any spaces."/>
4754<t text="Click Preview for Streaming Settings" translation="Click Preview for Streaming Settings"/>
4755<t text="DVD NTSC" translation="DVD NTSC"/>
4756<t text="DVD PAL" translation="DVD PAL"/>
4757<t text="Video Source" translation="Video Source"/>
4758<t text="Send" translation="Send"/>
4759<t text="Cinema" translation="Cinema"/>
4760<t text="Update Show Title" translation="Update Show Title"/>
4761<t text="Public Channel: Click to Copy" translation="Public Channel: Click to Copy"/>
4762<t text="Channel Link" translation="Channel Link"/>
4763<t text="Kick" translation="Kick"/>
4764<t text="Embed Channel HTML Code" translation="Embed Channel HTML Code"/>
4765<t text="Open In Browser" translation="Open In Browser"/>
4766<t text="Embed Video HTML Code" translation="Embed Video HTML Code"/>
4767<t text="Snapshot Image Link" translation="Snapshot Image Link"/>
4768<t text="SD" translation="SD"/>
4769<t text="External Encoder" translation="External Encoder"/>
4770<t text="Source" translation="Source"/>
4771<t text="Very Low" translation="Very Low"/>
4772<t text="Low" translation="Low"/>
4773<t text="HDTV" translation="HDTV"/>
4774<t text="Webcam" translation="Webcam"/>
4775<t text="Resolution" translation="Resolution"/>
4776<t text="Emoticons" translation="Emoticons"/>
4777<t text="HDCAM" translation="HDCAM"/>
4778<t text="FullHD" translation="FullHD"/>
4779<t text="Preview Shows as Compressed" translation="Preview Shows as Compressed"/>
4780<t text="Rate" translation="Rate"/>
4781<t text="Very Good" translation="Very Good"/>
4782<t text="Preview Shows as Captured" translation="Preview Shows as Captured"/>
4783<t text="Framerate" translation="Framerate"/>
4784<t text="High" translation="High"/>
4785<t text="Toggle Preview Compression" translation="Toggle Preview Compression"/>
4786<t text="Latency" translation="Latency"/>
4787<t text="CD" translation="CD"/>
4788<t text="Your connection performance:" translation="Your connection performance:"/>
4789<t text="Small Delay" translation="Small Delay"/>
4790<t text="Sound Effects" translation="Sound Effects"/>
4791<t text="Username" translation="Nickname"/>
4792<t text="Medium Delay" translation="Medium Delay"/>
4793<t text="Toggle Microphone" translation="Toggle Microphone"/>
4794<t text="Video is Enabled" translation="Video is Enabled"/>
4795<t text="Radio" translation="Radio"/>
4796<t text="Talk" translation="Talk"/>
4797<t text="Viewers" translation="Viewers"/>
4798<t text="Toggle External Encoder" translation="Toggle External Encoder"/>
4799<t text="Sound is Disabled" translation="Sound is Disabled"/>
4800<t text="Sound Fx" translation="Sound Effects"/>
4801<t text="Good" translation="Good"/>
4802<t text="Toggle Webcam" translation="Toggle Webcam"/>
4803<t text="Bandwidth" translation="Bandwidth"/>
4804<t text="Underline" translation="Underline"/>
4805<t text="Select Microphone Device" translation="Select Microphone Device"/>
4806<t text="Italic" translation="Italic"/>
4807<t text="Select Webcam Device" translation="Select Webcam Device"/>
4808<t text="Big Delay" translation="Big Delay"/>
4809<t text="Excellent" translation="Excellent"/>
4810<t text="Apply Settings" translation="Apply Settings"/>
4811<t text="Very High" translation="Very High"/>',
4812
4813 'customCSS' => <<<HTMLCODE
4814<style type="text/css">
4815
4816.videowhisperChannel
4817{
4818position: relative;
4819display:inline-block;
4820
4821 border:1px solid #aaa;
4822 background-color:#777;
4823 padding: 0px;
4824 margin: 2px;
4825
4826 width: 240px;
4827 height: 180px;
4828}
4829
4830.videowhisperChannel:hover {
4831 border:1px solid #fff;
4832}
4833
4834.videowhisperChannel IMG
4835{
4836padding: 0px;
4837margin: 0px;
4838border: 0px;
4839}
4840
4841.videowhisperTitle
4842{
4843position: absolute;
4844top:5px;
4845left:5px;
4846font-size: 20px;
4847color: #FFF;
4848text-shadow:1px 1px 1px #333;
4849}
4850
4851.videowhisperTime
4852{
4853position: absolute;
4854bottom:8px;
4855left:5px;
4856font-size: 15px;
4857color: #FFF;
4858text-shadow:1px 1px 1px #333;
4859}
4860
4861
4862.videowhisperButtonLS {
4863
4864 display:inline-block;
4865
4866 -webkit-border-top-left-radius:6px;
4867 -moz-border-radius-topleft:6px;
4868 border-top-left-radius:6px;
4869 -webkit-border-top-right-radius:6px;
4870 -moz-border-radius-topright:6px;
4871 border-top-right-radius:6px;
4872 -webkit-border-bottom-right-radius:6px;
4873 -moz-border-radius-bottomright:6px;
4874 border-bottom-right-radius:6px;
4875 -webkit-border-bottom-left-radius:6px;
4876 -moz-border-radius-bottomleft:6px;
4877 border-bottom-left-radius:6px;
4878
4879 border:1px solid #dcdcdc;
4880 box-shadow: none;
4881
4882 font-size:14px;
4883 text-indent:0;
4884 font-family:Verdana;
4885 font-weight:bold;
4886 font-style:normal;
4887 text-decoration:none;
4888 text-align:center;
4889
4890 background-color:#e9e9e9;
4891 color:#444444;
4892
4893 width: 200px;
4894
4895 margin: 2px;
4896 padding: 8px;
4897}
4898
4899
4900.videowhisperButtonLS:hover {
4901 background-color:#f9f9f9;
4902}
4903
4904.videowhisperButtonLS:active {
4905 position:relative;
4906 top:1px;
4907}
4908
4909td {
4910 padding: 4px;
4911}
4912
4913table, .videowhisperTable {
4914 border-spacing: 4px;
4915 border-collapse: separate;
4916}
4917
4918.videowhisperDropdown {
4919 display:inline-block;
4920 border: 1px solid #111;
4921 overflow: hidden;
4922 border-radius:3px;
4923 color: #eee;
4924 background: #556570;
4925 width: 240px;
4926}
4927
4928.videowhisperSelect {
4929 width: 100%;
4930 border: none;
4931 box-shadow: none;
4932 background: transparent;
4933 background-image: none;
4934 -webkit-appearance: none;
4935}
4936
4937.videowhisperSelect:focus {
4938 outline: none;
4939}
4940
4941</style>
4942
4943HTMLCODE
4944 ,
4945 'uploadsPath' => $upload_dir['basedir'] . '/vwls',
4946
4947 'tokenKey' => 'VideoWhisper',
4948 'webKey' => 'VideoWhisper',
4949 'manualArchiving' => '',
4950
4951 'serverRTMFP' => 'rtmfp://stratus.adobe.com/f1533cc06e4de4b56399b10d-1a624022ff71/',
4952 'p2pGroup' => 'VideoWhisper',
4953 'supportRTMP' => '1',
4954 'supportP2P' => '0',
4955 'alwaysRTMP' => '1',
4956 'alwaysP2P' => '0',
4957 'alwaysWatch' => '1',
4958 'disableBandwidthDetection' => '1',
4959 'mycred' => '1',
4960 'tips' => 1,
4961 'tipRatio' => '0.90',
4962 'tipOptions' => '<tips>
4963<tip amount="1" label="1$ Like!" note="Like!" sound="coins1.mp3" />
4964<tip amount="2" label="2$ Big Like!" note="Big Like!" sound="coins2.mp3" />
4965<tip amount="5" label="5$ Great!" note="Great!" sound="coins2.mp3" />
4966<tip amount="10" label="10$ Excellent!" note="Excellent!" sound="register.mp3"/>
4967<tip amount="20" label="20$ Ultimate!" note="Ultimate!" sound="register.mp3"/>
4968</tips>',
4969 'eula_txt' =>'The following Terms of Use (the "Terms") is a binding agreement between you, either an individual subscriber, customer, member, or user of at least 18 years of age or a single entity ("you", or collectively "Users") and owners of this application, service site and networks that allow for the distribution and reception of video, audio, chat and other content (the "Service").
4970
4971By accessing the Service and/or by clicking "I agree", you agree to be bound by these Terms of Use. You hereby represent and warrant to us that you are at least eighteen (18) years of age or and otherwise capable of entering into and performing legal agreements, and that you agree to be bound by the following Terms and Conditions. If you use the Service on behalf of a business, you hereby represent to us that you have the authority to bind that business and your acceptance of these Terms of Use will be treated as acceptance by that business. In that event, "you" and "your" will refer to that business in these Terms of Use.
4972
4973Prohibited Conduct
4974
4975The Services may include interactive areas or services (" Interactive Areas ") in which you or other users may create, post or store content, messages, materials, data, information, text, music, sound, photos, video, graphics, applications, code or other items or materials on the Services ("User Content" and collectively with Broadcaster Content, " Content "). You are solely responsible for your use of such Interactive Areas and use them at your own risk. BY USING THE SERVICE, INCLUDING THE INTERACTIVE AREAS, YOU AGREE NOT TO violate any law, contract, intellectual property or other third-party right or commit a tort, and that you are solely responsible for your conduct while on the Service. You agree that you will abide by these Terms of Service and will not:
4976
4977use the Service for any purposes other than to disseminate or receive original or appropriately licensed content and/or to access the Service as such services are offered by us;
4978
4979rent, lease, loan, sell, resell, sublicense, distribute or otherwise transfer the licenses granted herein;
4980
4981post, upload, or distribute any defamatory, libelous, or inaccurate Content;
4982
4983impersonate any person or entity, falsely claim an affiliation with any person or entity, or access the Service accounts of others without permission, forge another persons digital signature, misrepresent the source, identity, or content of information transmitted via the Service, or perform any other similar fraudulent activity;
4984
4985delete the copyright or other proprietary rights notices on the Service or Content;
4986
4987make unsolicited offers, advertisements, proposals, or send junk mail or spam to other Users of the Service, including, without limitation, unsolicited advertising, promotional materials, or other solicitation material, bulk mailing of commercial advertising, chain mail, informational announcements, charity requests, petitions for signatures, or any of the foregoing related to promotional giveaways (such as raffles and contests), and other similar activities;
4988
4989harvest or collect the email addresses or other contact information of other users from the Service for the purpose of sending spam or other commercial messages;
4990
4991use the Service for any illegal purpose, or in violation of any local, state, national, or international law, including, without limitation, laws governing intellectual property and other proprietary rights, and data protection and privacy;
4992
4993defame, harass, abuse, threaten or defraud Users of the Service, or collect, or attempt to collect, personal information about Users or third parties without their consent;
4994
4995remove, circumvent, disable, damage or otherwise interfere with security-related features of the Service or Content, features that prevent or restrict use or copying of any content accessible through the Service, or features that enforce limitations on the use of the Service or Content;
4996
4997reverse engineer, decompile, disassemble or otherwise attempt to discover the source code of the Service or any part thereof, except and only to the extent that such activity is expressly permitted by applicable law notwithstanding this limitation;
4998
4999modify, adapt, translate or create derivative works based upon the Service or any part thereof, except and only to the extent that such activity is expressly permitted by applicable law notwithstanding this limitation;
5000
5001intentionally interfere with or damage operation of the Service or any user enjoyment of them, by any means, including uploading or otherwise disseminating viruses, adware, spyware, worms, or other malicious code;
5002
5003relay email from a third party mail servers without the permission of that third party;
5004
5005use any robot, spider, scraper, crawler or other automated means to access the Service for any purpose or bypass any measures we may use to prevent or restrict access to the Service;
5006
5007manipulate identifiers in order to disguise the origin of any Content transmitted through the Service;
5008
5009interfere with or disrupt the Service or servers or networks connected to the Service, or disobey any requirements, procedures, policies or regulations of networks connected to the Service;use the Service in any manner that could interfere with, disrupt, negatively affect or inhibit other users from fully enjoying the Service, or that could damage, disable, overburden or impair the functioning of the Service in any manner;
5010
5011use or attempt to use another user account without authorization from such user and us;
5012
5013attempt to circumvent any content filtering techniques we employ, or attempt to access any service or area of the Service that you are not authorized to access; or
5014
5015attempt to indicate in any manner that you have a relationship with us or that we have endorsed you or any products or services for any purpose.
5016
5017Further, BY USING THE SERVICE, INCLUDING THE INTERACTIVE AREAS YOU AGREE NOT TO post, upload to, transmit, distribute, store, create or otherwise publish through the Service any of the following:
5018
5019Content that would constitute, encourage or provide instructions for a criminal offense, violate the rights of any party, or that would otherwise create liability or violate any local, state, national or international law or regulation;
5020
5021Content that may infringe any patent, trademark, trade secret, copyright or other intellectual or proprietary right of any party. By posting any Content, you represent and warrant that you have the lawful right to distribute and reproduce such Content;
5022
5023Content that is unlawful, libelous, defamatory, obscene, pornographic, indecent, lewd, suggestive, harassing, threatening, invasive of privacy or publicity rights, abusive, inflammatory, fraudulent or otherwise objectionable;
5024
5025Content that impersonates any person or entity or otherwise misrepresents your affiliation with a person or entity;
5026
5027private information of any third party, including, without limitation, addresses, phone numbers, email addresses, Social Security numbers and credit card numbers;
5028
5029viruses, corrupted data or other harmful, disruptive or destructive files; and
5030
5031Content that, in the sole judgment of Service moderators, is objectionable or which restricts or inhibits any other person from using or enjoying the Interactive Areas or the Service, or which may expose us or our users to any harm or liability of any type.
5032
5033Service takes no responsibility and assumes no liability for any Content posted, stored or uploaded by you or any third party, or for any loss or damage thereto, nor is liable for any mistakes, defamation, slander, libel, omissions, falsehoods, obscenity, pornography or profanity you may encounter. Your use of the Service is at your own risk. Enforcement of the user content or conduct rules set forth in these Terms of Service is solely at Service discretion, and failure to enforce such rules in some instances does not constitute a waiver of our right to enforce such rules in other instances. In addition, these rules do not create any private right of action on the part of any third party or any reasonable expectation that the Service will not contain any content that is prohibited by such rules. As a provider of interactive services, Service is not liable for any statements, representations or Content provided by our users in any public forum, personal home page or other Interactive Area. Service does not endorse any Content or any opinion, recommendation or advice expressed therein, and Service expressly disclaims any and all liability in connection with Content. Although Service has no obligation to screen, edit or monitor any of the Content posted in any Interactive Area, Service reserves the right, and has absolute discretion, to remove, screen or edit any Content posted or stored on the Service at any time and for any reason without notice, and you are solely responsible for creating backup copies of and replacing any Content you post or store on the Service at your sole cost and expense. Any use of the Interactive Areas or other portions of the Service in violation of the foregoing violates these Terms and may result in, among other things, termination or suspension of your rights to use the Interactive Areas and/or the Service.
5034',
5035 'crossdomain_xml' =>'<cross-domain-policy>
5036<allow-access-from domain="*"/>
5037<site-control permitted-cross-domain-policies="master-only"/>
5038</cross-domain-policy>',
5039 'videowhisper' => 0
5040 );
5041
5042 }
5043
5044 function setupOptions()
5045 {
5046
5047 $adminOptions = VWliveStreaming::adminOptionsDefault();
5048
5049 $features = VWliveStreaming::roomFeatures();
5050 foreach ($features as $key=>$feature) if ($feature['installed']) $adminOptions[$key] = $feature['default'];
5051
5052 $options = get_option('VWliveStreamingOptions');
5053 if (!empty($options)) {
5054 foreach ($options as $key => $option)
5055 $adminOptions[$key] = $option;
5056 }
5057 update_option('VWliveStreamingOptions', $adminOptions);
5058
5059
5060 return $adminOptions;
5061 }
5062
5063
5064
5065 function options()
5066 {
5067 $options = VWliveStreaming::setupOptions();
5068 $optionsDefault = VWliveStreaming::adminOptionsDefault();
5069
5070 if (isset($_POST))
5071 {
5072 foreach ($options as $key => $value)
5073 if (isset($_POST[$key])) $options[$key] = $_POST[$key];
5074
5075 //config parsing
5076 if (isset($_POST['userWatchLimitsConfig']))
5077 $options['userWatchLimits'] = parse_ini_string(sanitize_textarea_field($_POST['userWatchLimitsConfig']));
5078
5079 if (isset($_POST['watchRoleParametersConfig']))
5080 $options['watchRoleParameters'] = parse_ini_string(sanitize_textarea_field($_POST['watchRoleParametersConfig']), true);
5081
5082
5083 update_option('VWliveStreamingOptions', $options);
5084 }
5085
5086 $page_id = get_option("vwls_page_manage");
5087 if ($page_id != '-1' && $options['disablePage']!='0') VWliveStreaming::deletePages();
5088
5089 $page_idC = get_option("vwls_page_channels");
5090 if ($page_idC != '-1' && $options['disablePageC']!='0') VWliveStreaming::deletePages();
5091
5092
5093 $active_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : 'support';
5094?>
5095
5096
5097<div class="wrap">
5098<?php screen_icon(); ?>
5099<h2>VideoWhisper Live Streaming Settings</h2>
5100
5101<h2 class="nav-tab-wrapper">
5102 <a href="admin.php?page=live-streaming&tab=server" class="nav-tab <?php echo $active_tab=='server'?'nav-tab-active':'';?>">Server</a>
5103 <a href="admin.php?page=live-streaming&tab=general" class="nav-tab <?php echo $active_tab=='general'?'nav-tab-active':'';?>">Integration</a>
5104 <a href="admin.php?page=live-streaming&tab=broadcaster" class="nav-tab <?php echo $active_tab=='broadcaster'?'nav-tab-active':'';?>">Broadcast</a>
5105 <a href="admin.php?page=live-streaming&tab=premium" class="nav-tab <?php echo $active_tab=='premium'?'nav-tab-active':'';?>">Premium Channels</a>
5106 <a href="admin.php?page=live-streaming&tab=features" class="nav-tab <?php echo $active_tab=='features'?'nav-tab-active':'';?>">Channel Features</a>
5107 <a href="admin.php?page=live-streaming&tab=playlists" class="nav-tab <?php echo $active_tab=='playlists'?'nav-tab-active':'';?>">Playlists Scheduler</a>
5108 <a href="admin.php?page=live-streaming&tab=watcher" class="nav-tab <?php echo $active_tab=='watcher'?'nav-tab-active':'';?>">Watch</a>
5109 <a href="admin.php?page=live-streaming&tab=watch-limit" class="nav-tab <?php echo $active_tab=='watch-limit'?'nav-tab-active':'';?>">Watch Limit</a>
5110 <a href="admin.php?page=live-streaming&tab=watch-params" class="nav-tab <?php echo $active_tab=='watch-params'?'nav-tab-active':'';?>">Watch Params</a>
5111
5112 <a href="admin.php?page=live-streaming&tab=billing" class="nav-tab <?php echo $active_tab=='billing'?'nav-tab-active':'';?>">Billing</a>
5113 <a href="admin.php?page=live-streaming&tab=tips" class="nav-tab <?php echo $active_tab=='tips'?'nav-tab-active':'';?>">Tips</a>
5114 <a href="admin.php?page=live-streaming&tab=hls" class="nav-tab <?php echo $active_tab=='hls'?'nav-tab-active':'';?>">Mobile</a>
5115 <a href="admin.php?page=live-streaming&tab=app" class="nav-tab <?php echo $active_tab=='app'?'nav-tab-active':'';?>">Custom App</a>
5116 <a href="admin.php?page=live-streaming&tab=support" class="nav-tab <?php echo $active_tab=='support'?'nav-tab-active':'';?>">Support</a>
5117</h2>
5118
5119<form method="post" action="<?php echo $_SERVER["REQUEST_URI"]; ?>">
5120
5121<?php
5122 switch ($active_tab)
5123 {
5124 case 'watch-params':
5125 $options['watchRoleParametersConfig'] = htmlentities(stripslashes($options['watchRoleParametersConfig']));
5126
5127?>
5128<h3>Watch Parameters: Advanced Configuration by Role</h3>
5129This permits advanced configuration for watch interface parameters based on user role.
5130<br>For more details about available parameters and possible values see <a href="https://videowhisper.com/?p=php+live+streaming#integrate">PHP Live Streaming documentation</a>.
5131
5132<h4>Watch Role Parameters Configuration</h4>
5133<textarea name="watchRoleParametersConfig" id="watchRoleParametersConfig" cols="100" rows="5"><?php echo $options['watchRoleParametersConfig']?></textarea>
5134<BR>This overwrites parameters defined as permissions by channel owner.
5135Default:<br><textarea readonly cols="100" rows="3"><?php echo $optionsDefault['watchRoleParametersConfig']?></textarea>
5136
5137<BR>Parsed configuration (should be an array of arrays):
5138<?php
5139
5140 echo '<br><textarea readonly cols="100" rows="4">';
5141 var_dump($options['watchRoleParameters']);
5142 echo '</textarea>';
5143
5144
5145 if (!$current_user) $current_user = wp_get_current_user();
5146 echo '<h4>Testing</h4>Your role(s): '; var_dump($current_user->roles);
5147
5148 echo '<BR>Role Parameters: ';
5149 var_dump(VWliveStreaming::userParameters($current_user, $options['watchRoleParameters']));
5150
5151 break;
5152
5153 case 'watch-limit':
5154 $options['userWatchLimitsConfig'] = htmlentities(stripslashes($options['userWatchLimitsConfig']));
5155
5156?>
5157<h3>Watch Limit</h3>
5158Limit watch time per user (by keeping track for each user of total watch time on site).
5159<br>Only works for RTMP based clients (including external players when RTMP Session Control is setup). Does not work for HTML5 based mobile streaming.
5160<br>Only works for registered users as this records info as user metas. Does not work for site visitors: you should disable visitor access when using this.
5161<br>User watch time is updated based on <a href="admin.php?page=live-streaming&tab=watcher">statusInterval parameter</a>. If configured at 60000 (ms), will update once per minute. Warning: A low value can highly impact web server load when multiple users are online. Recommended interval is 1-5 minutes depending on average content length and acceptable grace time.
5162
5163<h4>Enable Watch Limit per User</h4>
5164<select name="userWatchLimit" id="userWatchLimit">
5165 <option value="1" <?php echo $options['userWatchLimit']?"selected":""?>>Yes</option>
5166 <option value="0" <?php echo $options['userWatchLimit']?"":"selected"?>>No</option>
5167</select>
5168
5169<h4>Limit Interval</h4>
5170<input name="userWatchInterval" type="text" id="userWatchInterval" size="12" maxlength="32" value="<?php echo $options['userWatchInterval']?>"/>s
5171<BR>Specify interval for limits in seconds (in example 2592000 = 1 month, Default: <?php echo $optionsDefault['userWatchInterval']?>).
5172
5173<h4>Default Limit</h4>
5174<input name="userWatchLimitDefault" type="text" id="userWatchLimitDefault" size="12" maxlength="32" value="<?php echo $options['userWatchLimitDefault']?>"/>s
5175<br>Default limit for user in seconds (Ex: 108000 = 30h, Default: <?php echo $optionsDefault['userWatchLimitDefault']?>).
5176
5177<h4>User Watch Limits Configuration</h4>
5178<textarea name="userWatchLimitsConfig" id="userWatchLimitsConfig" cols="100" rows="5"><?php echo $options['userWatchLimitsConfig']?></textarea>
5179<BR>Assign limit in hours, by role, one per line. Set 0 for unlimited.
5180Default:<br><textarea readonly cols="100" rows="3"><?php echo $optionsDefault['userWatchLimitsConfig']?></textarea>
5181
5182<BR>Parsed configuration (should be an array):<BR>
5183<?php
5184
5185 var_dump($options['userWatchLimits']);
5186
5187 if (!$current_user) $current_user = wp_get_current_user();
5188 echo '<h4>Testing</h4>Your role(s): '; var_dump($current_user->roles);
5189 echo '<BR>Your Watch Time: ' . get_user_meta( $current_user->ID, 'vwls_watch', true ) . 's';
5190 echo '<BR>Since: ' .date("F j, Y, g:i a", get_user_meta( $current_user->ID, 'vwls_watch_update', true ));
5191 echo '<BR>Your Limit: ' . $limit = VWliveStreaming::userWatchLimit($current_user, $options)?$limit.'s':'unlimited';
5192
5193 break;
5194
5195
5196 case 'playlists':
5197?>
5198
5199<h3>Playlist Scheduler Settings</h3>
5200This section is for configuring settings related to SMIL playlists. Playlist can be used to schedule videos to play as a live stream (on a channel).
5201Playlist support can be configured on <a href='https://www.wowza.com/forums/content.php?145-How-to-schedule-streaming-with-Wowza-Streaming-Engine-(StreamPublisher)#installation'>Wowza Streaming Engine</a> and requires web and rtmp on same servers (so web scripts can write playlists).
5202
5203<h4>Video Share VOD</h4>
5204<?php
5205 if (is_plugin_active('video-share-vod/video-share-vod.php'))
5206 {
5207 echo 'Detected.';
5208 $optionsVSV = get_option('VWvideoShareOptions');
5209 $custom_post_video = $optionsVSV['custom_post'];
5210
5211 echo ' Post type name: ' . $optionsVSV['custom_post'];
5212
5213 } else echo 'Not detected. Please install, activate and configure <a target="_blank" href="https://wordpress.org/plugins/video-share-vod/">Video Share VOD</a>!';
5214
5215?>
5216
5217<h4>Video Post Type Name</h4>
5218<input name="custom_post_video" type="text" id="custom_post_video" size="16" maxlength="32" value="<?php echo $options['custom_post_video']?>"/>
5219<br>Should be same as Video Share VOD post type name. Ex: video
5220
5221
5222<h4>Enable Playlists</h4>
5223<select name="playlists" id="playlists">
5224 <option value="1" <?php echo $options['playlists']?"selected":""?>>Yes</option>
5225 <option value="0" <?php echo $options['playlists']?"":"selected"?>>No</option>
5226</select>
5227<BR>Allows users to schedule playlists. Feature also needs to be enabled for channels owners from <a href='admin.php?page=live-streaming&tab=features'>Channel Features</a> : Playlist Scheduler .
5228<BR>This feature requires Wowza Streaming Engine and <a href="https://www.wowza.com/forums/content.php?145-How-to-schedule-streaming-with-Wowza-Streaming-Engine-(StreamPublisher)#installation">specific setup</a>: for VideoWhisper managed <a href="https://videowhisper.com/?p=wowza+media+server+hosting">hosting plans</a> and <a href="https://videowhisper.com/?p=Dedicated+Servers">servers</a> submit a support request for setting this up.
5229
5230<h4>Streams Path</h4>
5231<input name="streamsPath" type="text" id="streamsPath" size="100" maxlength="256" value="<?php echo $options['streamsPath']?>"/>
5232<BR>Used for .smil playlists (should be same as streams path configured in VideoShareVOD for RTMP delivery).
5233<BR> <?php
5234 echo $options['streamsPath'] . ' : ';
5235 if (file_exists($options['streamsPath']))
5236 {
5237 echo 'Found. ';
5238 if (is_writable($options['streamsPath'])) echo 'Writable. (OK)';
5239 else echo 'NOT writable.';
5240 }
5241 else echo '<b>NOT found!</b>';
5242
5243 // update when saving
5244 if (isset($_POST['playlists']))
5245 {
5246 echo '<BR><BR>SMIL updated on settings save.';
5247 VWliveStreaming::updatePlaylistSMIL();
5248 }
5249
5250 $streamsPath = VWliveStreaming::fixPath($options['streamsPath']);
5251 $smilPath = $streamsPath . 'playlist.smil';
5252
5253 if (file_exists($smilPath))
5254 {
5255 echo '<br><br>Playlist found: ' . $smilPath;
5256 $smil = file_get_contents($smilPath);
5257 echo '<br><textarea readonly cols="100" rows="10">' .htmlentities($smil). '</textarea>';
5258 }
5259
5260?>
5261
5262<?php
5263
5264 break;
5265 case 'app':
5266 $options['eula_txt'] = htmlentities(stripslashes($options['eula_txt']));
5267 $options['crossdomain_xml'] = htmlentities(stripslashes($options['crossdomain_xml']));
5268
5269 $eula_url = site_url() . '/eula.txt';
5270 $crossdomain_url = site_url() . '/crossdomain.xml';
5271
5272 //TEST: wp-admin/admin-ajax.php?action=vwls&task=vw_extlogin&videowhisper=1
5273?>
5274<h3>Application Settings</h3>
5275<p>This section is for configuring settings related to custom remote apps (iOS/Android/Desktop) that can be used in combination with this web based solution. Such apps can be <a href="https://videowhisper.com/?p=iPhone-iPad-Apps">custom made</a> for each site. Broadcasting camera as RTMP from mobile devices is only possible with mobile apps, due to mobile browser limitations.</p>
5276
5277<h4>Default Webcam Resolution</h4>
5278<select name="camResolutionMobile" id="camResolutionMobile">
5279<?php
5280 foreach (array('160x120','240x180','320x240','426x240','480x360', '640x360', '640x480', '720x480', '720x576', '854x480', '1280x720', '1440x1080', '1920x1080') as $optItm)
5281 {
5282?>
5283 <option value="<?php echo $optItm;?>" <?php echo $options['camResolutionMobile']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
5284 <?php
5285 }
5286?>
5287 </select>
5288 <br>Higher resolution will require <a target="_blank" href="https://videochat-scripts.com/recommended-h264-video-bitrate-based-on-resolution/">higher bandwidth</a> to avoid visible blocking and quality loss (ex. 1Mbps required for 640x360). Webcam capture resolution should be similar to video size in player/watch interface (capturing higher resolution will require more resources without visible quality improvement and lower will display pixelation when zoomed in player).
5289
5290<h4>Webcam Frames Per Second</h4>
5291<select name="camFPSMobile" id="camFPSMobile">
5292<?php
5293 foreach (array('1','8','10','12','15','29','30','60') as $optItm)
5294 {
5295?>
5296 <option value="<?php echo $optItm;?>" <?php echo $options['camFPSMobile']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
5297 <?php
5298 }
5299?>
5300 </select>
5301
5302<h4>Video Stream Bandwidth</h4>
5303<input name="camBandwidthMobile" type="text" id="camBandwidthMobile" size="7" maxlength="7" value="<?php echo $options['camBandwidthMobile']?>"/> (bytes/s)
5304<br>This sets size of video stream (without audio) and therefore the video quality.
5305<br>Total stream size should be less than maximum broadcaster upload speed (multiply by 8 to get bps, ex. 50000b/s requires connection higher than 400kbps).
5306<br>Do a speed test from broadcaster computer to a location near your streaming (rtmp) server using a tool like <a href="http://www.speedtest.net" target="_blank">SpeedTest.net</a> . Drag and zoom to a server in contry/state where you host (Ex: central US if you host with VideoWhisper) and select it. The upload speed is the maximum data you'll be able to broadcast.
5307
5308<?php
5309 /*
5310
5311<h4>Video Codec</h4>
5312<select name="videoCodecMobile" id="videoCodecMobile">
5313 <option value="H264" <?php echo $options['videoCodecMobile']=='H264'?"selected":""?>>H264</option>
5314 <option value="H263" <?php echo $options['videoCodecMobile']=='H263'?"selected":""?>>H263</option>
5315</select>
5316<BR>Mobile apps don't currently support H264 (due to Adobe Air limitations).
5317
5318
5319<h4>H264 Video Codec Profile</h4>
5320<select name="codecProfileMobile" id="codecProfileMobile">
5321 <option value="main" <?php echo $options['codecProfileMobile']=='main'?"selected":""?>>main</option>
5322 <option value="baseline" <?php echo $options['codecProfileMobile']=='baseline'?"selected":""?>>baseline</option>
5323</select>
5324<br>Recommended: Baseline
5325
5326<h4>H264 Video Codec Level</h4>
5327<select name="codecLevelMobile" id="codecLevelMobile">
5328<?php
5329 foreach (array('1', '1b', '1.1', '1.2', '1.3', '2', '2.1', '2.2', '3', '3.1', '3.2', '4', '4.1', '4.2', '5', '5.1') as $optItm)
5330 {
5331?>
5332 <option value="<?php echo $optItm;?>" <?php echo $options['codecLevelMobile']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
5333 <?php
5334 }
5335?>
5336 </select>
5337<br>Recommended: 3.1
5338
5339<h4>Sound Codec</h4>
5340<select name="soundCodecMobile" id="soundCodecMobile">
5341 <option value="Speex" <?php echo $options['soundCodecMobile']=='Speex'?"selected":""?>>Speex</option>
5342 <option value="Nellymoser" <?php echo $options['soundCodecMobile']=='Nellymoser'?"selected":""?>>Nellymoser</option>
5343</select>
5344<BR>Speex is recommended for voice audio.
5345<BR>Current web codecs used by Flash plugin are not currently supported by iOS. For delivery to iOS, audio should be transcoded to AAC (HE-AAC or AAC-LC up to 48 kHz, stereo audio).
5346
5347<h4>Speex Sound Quality</h4>
5348<select name="soundQualityMobile" id="soundQualityMobile">
5349<?php
5350 foreach (array('0', '1','2','3','4','5','6','7','8','9','10') as $optItm)
5351 {
5352?>
5353 <option value="<?php echo $optItm;?>" <?php echo $options['soundQualityMobile']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
5354 <?php
5355 }
5356?>
5357 </select>
5358 <br>Higher quality requires more <a href="http://www.videochat-scripts.com/speex-vs-nellymoser-bandwidth/" target="_blank" >bandwidth</a>.
5359<br>Speex quality 9 requires 34.2kbps and generates 4275 b/s transfer. Quality 10 requires 42.2 kbps.
5360
5361<h4>Nellymoser Sound Rate</h4>
5362<select name="micRateMobile" id="micRateMobile">
5363<?php
5364 foreach (array('5', '8', '11', '22','44') as $optItm)
5365 {
5366?>
5367 <option value="<?php echo $optItm;?>" <?php echo $options['micRateMobile']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
5368 <?php
5369 }
5370?>
5371 </select>
5372<br>Higher quality requires more <a href="http://www.videochat-scripts.com/speex-vs-nellymoser-bandwidth/" target="_blank" >bandwidth</a>.
5373<br>NellyMoser rate 22 requires 44.1kbps and generates 5512b/s transfer. Rate 44 requires 88.2 kbps.
5374
5375*/
5376?>
5377
5378<h4><?php _e('End User License Agreement','vw2wvc'); ?></h4>
5379<textarea name="eula_txt" id="eula_txt" cols="100" rows="8"><?php echo $options['eula_txt']?></textarea>
5380<br>Users are required to accept this agreement before registering from app.
5381<br>After updating permalinks (<a href="options-permalink.php">Save Changes on Permalinks page</a>) this should become available as <a href="<?php echo $eula_url ?>"><?php echo $eula_url ?></a>.
5382<br>This works if file doesn't already exist. You can also create the file for faster serving.
5383
5384<h4><?php _e('Cross Domain Policy','vw2wvc'); ?></h4>
5385<textarea name="crossdomain_xml" id="crossdomain_xml" cols="100" rows="4"><?php echo $options['crossdomain_xml']?></textarea>
5386<br>This is required for applications to access interface and scripts on site.
5387<br>After updating permalinks (<a href="options-permalink.php">Save Changes on Permalinks page</a>) this should become available as <a href="<?php echo $crossdomain_url ?>"><?php echo $crossdomain_url ?></a>.
5388<br>This works if file doesn't already exist. You can also create the file for faster serving.
5389<?php
5390
5391 break;
5392
5393 case 'support':
5394 //! Support
5395?>
5396<h3>Hosting Requirements</h3>
5397<UL>
5398<LI><a href="https://videowhisper.com/?p=Requirements">Hosting Requirements</a> This advanced software requires web hosting and rtmp hosting.</LI>
5399<LI><a href="https://videowhisper.com/?p=RTMP+Hosting">Estimate Hosting Needs</a> Evaluate hosting needs: volume and features.</LI>
5400<LI><a href="http://hostrtmp.com/compare/">Compare Hosting Options</a> Hosting options starting from $9/month.</LI>
5401</UL>
5402
5403<h3>Software Documentation</h3>
5404<UL>
5405<LI><a href="admin.php?page=live-streaming-docs">Backend Documentation</a> Includes tutorial with local links to configure main features, menus, pages.</LI>
5406<LI><a href="http://broadcastlivevideo.com/setup-tutorial/">BroadcastLiveVideo Tutorial</a> Setup a turnkey live video broadcasting site.</LI>
5407<LI><a href="https://videowhisper.com/?p=wordpress+live+streaming">VideoWhisper Plugin Homepage</a> Plugin and application documentation.</LI>
5408</UL>
5409
5410<h3>Contact and Feedback</h3>
5411<a href="https://videowhisper.com/tickets_submit.php">Sumit a Ticket</a> with your questions, inquiries and VideoWhisper support staff will try to address these as soon as possible.
5412<br>Although the free license does not include any services (as installation and troubleshooting), VideoWhisper staff can clarify requirements, features, installation steps or suggest additional services like customisations, hosting you may need for your project.
5413
5414<h3>Review and Discuss</h3>
5415You can publicly <a href="https://wordpress.org/support/view/plugin-reviews/videowhisper-live-streaming-integration">review this WP plugin</a> on the official WordPress site (after <a href="https://wordpress.org/support/register.php">registering</a>). You can describe how you use it and mention your site for visibility. You can also post on the <a href="https://wordpress.org/support/plugin/videowhisper-live-streaming-integration">WP support forums</a> - these are not monitored by support so use a <a href="https://videowhisper.com/tickets_submit.php">ticket</a> if you want to contact VideoWhisper.
5416<BR>If you like this plugin and decide to order a commercial license or other services from <a href="http://videowhisper.com/">VideoWhisper</a>, use this coupon code for 5% discount: giveme5
5417
5418<h3>News and Updates</h3>
5419You can also get connected with VideoWhisper and follow updates using <a href="http://twitter.com/videowhisper"> Twitter </a>, <a href="http://www.facebook.com/pages/VideoWhisper/121234178858"> Facebook </a>, <a href="https://plus.google.com/105178389419893112810?prsrc=3" >Google+</a>
5420
5421
5422 <?php
5423 break;
5424
5425 case 'general':
5426
5427 $broadcast_url = admin_url() . 'admin-ajax.php?action=vwls_broadcast&n=';
5428 $root_url = get_bloginfo( "url" ) . "/";
5429
5430
5431 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
5432
5433 $current_user = wp_get_current_user();
5434
5435 if ($current_user->$userName) $username = $current_user->$userName;
5436 $username = sanitize_file_name($username);
5437
5438
5439 $options['translationCode'] = htmlentities(stripslashes($options['translationCode']));
5440 $options['adsCode'] = htmlentities(stripslashes($options['adsCode']));
5441 $options['customCSS'] = htmlentities(stripslashes($options['customCSS']));
5442 $options['cssCode'] = htmlentities(stripslashes($options['cssCode']));
5443
5444
5445?>
5446<h3>General Integration Settings</h3>
5447<h4>Username</h4>
5448<select name="userName" id="userName">
5449 <option value="display_name" <?php echo $options['userName']=='display_name'?"selected":""?>>Display Name</option>
5450 <option value="user_login" <?php echo $options['userName']=='user_login'?"selected":""?>>Login (Username)</option>
5451 <option value="user_nicename" <?php echo $options['userName']=='user_nicename'?"selected":""?>>Nicename</option>
5452</select>
5453
5454<h4>User Profile Link</h4>
5455<input name="profilePrefix" type="text" id="profilePrefix" size="100" maxlength="200" value="<?php echo $options['profilePrefix']?>"/>
5456<BR>Specify a url prefix for listing user profile.
5457 Default:<br><textarea readonly cols="100" rows="1"><?php echo $optionsDefault['profilePrefix']?></textarea>
5458
5459<h4>Channel Profile Link</h4>
5460<input name="profilePrefixChannel" type="text" id="profilePrefixChannel" size="100" maxlength="200" value="<?php echo $options['profilePrefixChannel']?>"/>
5461<BR>Specify a url prefix for listing channel profile (a broadcaster can have multiple channels). If blank will link to default channel page.
5462 Default:<br><textarea readonly cols="100" rows="1"><?php echo $optionsDefault['profilePrefixChannel']?></textarea>
5463
5464<h4>User Picture</h4>
5465<select name="userPicture" id="userPicture">
5466 <option value="0" <?php echo !$options['userPicture']?"selected":""?>>Disabled</option>
5467 <option value="avatar" <?php echo $options['userPicture']=='avatar'?"selected":""?>>WordPress Avatar</option>
5468</select>
5469<BR>Broadcaster will have channel thumbnail (snapshot) as avatar.
5470
5471<h4>Registration and Login Logo</h4>
5472<input name="loginLogo" type="text" id="loginLogo" size="100" maxlength="200" value="<?php echo $options['loginLogo']?>"/>
5473<br>Logo image to show on registration & login form (320x54px). Leave blank to disable.
5474<?php echo $options['loginLogo']?"<BR><img src='".$options['loginLogo']."'>":'';?>
5475
5476
5477<h4>Channel Page Layout URL</h4>
5478<select name="channelUrl" id="channelUrl">
5479 <option value="post" <?php echo $options['channelUrl']=='post'?"selected":""?>>Post (Theme)</option>
5480 <option value="full" <?php echo $options['channelUrl']=='full'?"selected":""?>>Full Page</option>
5481</select>
5482<br>URL where to show channels from listings (implemented in listings).
5483
5484<h4>Post Channels</h4>
5485<select name="postChannels" id="postChannels">
5486 <option value="1" <?php echo $options['postChannels']?"selected":""?>>Yes</option>
5487 <option value="0" <?php echo $options['postChannels']?"":"selected"?>>No</option>
5488</select>
5489<BR>Enables special post types (channels) and static urls for easy access to broadcast, watch and preview video.
5490<BR>This is required by other features like frontend channel management.
5491<BR><?php echo $root_url; ?>channel/chanel-name/broadcast
5492<BR><?php echo $root_url; ?>channel/chanel-name/
5493<BR><?php echo $root_url; ?>channel/chanel-name/video
5494<BR><?php echo $root_url; ?>channel/chanel-name/hls - Video must be transcoded to HLS format for iOS or published directly in such format with external encoder.
5495<BR><?php echo $root_url; ?>channel/chanel-name/external - Shows rtmp settings to use with external applications (if supported).
5496
5497<h4>Post Template Filename</h4>
5498<input name="postTemplate" type="text" id="postTemplate" size="20" maxlength="64" value="<?php echo $options['postTemplate']?>"/>
5499<br>Template file located in current theme folder, that should be used to render channel post page. Ex: page.php, single.php
5500<br><?php
5501 if ($options['postTemplate'] != '+plugin')
5502 {
5503 $single_template = get_stylesheet_directory() . '/' . $options['postTemplate'];
5504 echo $single_template . ' : ';
5505 if (file_exists($single_template)) echo 'Found.';
5506 else echo 'Not Found! Use another theme file!';
5507 }
5508?>
5509<br>Set "+plugin" to use a template provided by this plugin, instead of theme templates.
5510
5511<h4>Maximum Number of Broadcasting Channels (per User)</h4>
5512<input name="maxChannels" type="text" id="maxChannels" size="2" maxlength="4" value="<?php echo $options['maxChannels']?>"/>
5513<BR>Maximum channels users are allowed to create from frontend if channel posts are enabled.
5514
5515<h4>User Channels</h4>
5516<select name="userChannels" id="userChannels">
5517 <option value="1" <?php echo $options['userChannels']?"selected":""?>>Yes</option>
5518 <option value="0" <?php echo $options['userChannels']?"":"selected"?>>No</option>
5519</select>
5520<BR>Enables users to start channel with own name by accessing a common static broadcasting link.
5521<BR><a href="<?php echo $broadcast_url; ?>"><img src="<?php echo $root_url; ?>wp-content/plugins/videowhisper-live-streaming-integration/ls/templates/live/i_webcam.png" align="absmiddle"
5522border="0"><?php echo $broadcast_url; ?></a>
5523
5524<h4>Custom Channels</h4>
5525<select name="anyChannels" id="anyChannels">
5526 <option value="1" <?php echo $options['anyChannels']?"selected":""?>>Yes</option>
5527 <option value="0" <?php echo $options['anyChannels']?"":"selected"?>>No</option>
5528</select>
5529<BR>Enables users to start channel by passing any channel name in link.
5530<BR><a href="<?php echo $broadcast_url . urlencode($username); ?>"><img src="<?php echo $root_url; ?>wp-content/plugins/videowhisper-live-streaming-integration/ls/templates/live/i_webcam.png"
5531align="absmiddle" border="0"><?php echo $broadcast_url . urlencode($username); ?></a>
5532
5533<h4>Floating Logo / Watermark</h4>
5534<input name="overLogo" type="text" id="overLogo" size="80" maxlength="256" value="<?php echo $options['overLogo']?>"/>
5535<?php echo $options['overLogo']?"<BR><img src='".$options['overLogo']."'>":'';?>
5536<h4>Logo Link</h4>
5537<input name="overLink" type="text" id="overLink" size="80" maxlength="256" value="<?php echo $options['overLink']?>"/>
5538
5539<h4>App Loader Image</h4>
5540<input name="loaderImage" type="text" id="loaderImage" size="80" maxlength="256" value="<?php echo $options['loaderImage']?>"/>
5541<br>Ex: <?php echo $root_url .'wp-content/plugins/videowhisper-live-streaming-integration/ls/loader.png'; ?>
5542<br>Leave blank to disable.
5543<?php echo $options['loaderImage']?"<BR><img src='".$options['loaderImage']."'>":'';?>
5544
5545
5546<h4>Chat Advertising Server</h4>
5547<input name="adServer" type="text" id="adServer" size="80" maxlength="256" value="<?php echo $options['adServer']?>"/>
5548<br>Use 'ads' for local content. See <a href="http://www.adinchat.com" target="_blank"><U><b>AD in Chat</b></U></a> compatible ad management server. This can be controlled by channel owners based on features setup.
5549
5550<h4>Chat Advertising Interval</h4>
5551<input name="adsInterval" type="text" id="adsInterval" size="6" maxlength="6" value="<?php echo $options['adsInterval']?>"/>
5552<BR>Setup adsInterval in milliseconds (0 to disable ad calls).
5553
5554<h4>Chat Advertising Content</h4>
5555<textarea name="adsCode" id="adsCode" cols="64" rows="8"><?php echo $options['adsCode']?></textarea>
5556<br>Shows from time to time in chat, if internal 'ads' server is enabled.
5557
5558<h4>App CSS</h4>
5559<textarea name="cssCode" id="cssCode" cols="100" rows="5"><?php echo $options['cssCode']?></textarea>
5560<BR>Some texts from flash application can be styled (title, story).
5561Default:<br><textarea readonly cols="100" rows="3"><?php echo $optionsDefault['cssCode']?></textarea>
5562
5563<h4>Translation Code</h4>
5564<textarea name="translationCode" id="translationCode" cols="100" rows="5"><?php echo $options['translationCode']?></textarea>
5565<br>Generate by writing and sending "/videowhisper translation" in chat (contains xml tags with text and translation attributes). Texts are added to list only after being shown once in interface. If any texts don't show up in generated list you can manually add new entries for these. Same translation file is used for interfaces so setting should cumulate all translations.
5566Default:<br><textarea readonly cols="100" rows="3"><?php echo $optionsDefault['translationCode']?></textarea>
5567
5568<h4>Custom CSS</h4>
5569<textarea name="customCSS" id="customCSS" cols="100" rows="5"><?php echo $options['customCSS']?></textarea>
5570<BR>Used in elements added by this plugin. Include <style type="text/css"> </style> container.
5571Default:<br><textarea readonly cols="100" rows="3"><?php echo $optionsDefault['customCSS']?></textarea>
5572
5573<h4>Page for Management</h4>
5574<p>Add channel management page (Page ID <a href='post.php?post=<?php echo get_option("vwls_page_manage"); ?>&action=edit'><?php echo get_option("vwls_page_manage"); ?></a>) with shortcode [videowhisper_channel_manage]</p>
5575<select name="disablePage" id="disablePage">
5576 <option value="0" <?php echo $options['disablePage']=='0'?"selected":""?>>Yes</option>
5577 <option value="1" <?php echo $options['disablePage']=='1'?"selected":""?>>No</option>
5578</select>
5579
5580<h4>External Application Addresses</h4>
5581<select name="externalKeys" id="externalKeys">
5582 <option value="0" <?php echo $options['externalKeys']?"":"selected"?>>No</option>
5583 <option value="1" <?php echo $options['externalKeys']?"selected":""?>>Yes</option>
5584</select>
5585<BR> Channel owners will receive access to their secret publishing and playback addresses for each channel.
5586<BR>Enables external application support by inserting authentication info (username, channel name, key for broadcasting/watching) directly in RTMP address. RTMP server will pass these parameters to webLogin scripts for direct authentication without website access. This feature requires special RTMP side support for managing these parameters.
5587
5588<h4>Page for Channels</h4>
5589<p>Add channel list page (Page ID <a href='post.php?post=<?php echo get_option("vwls_page_channels"); ?>&action=edit'><?php echo get_option("vwls_page_channels"); ?></a>) with shortcode [videowhisper_channels]</p>
5590<select name="disablePageC" id="disablePageC">
5591 <option value="0" <?php echo $options['disablePageC']=='0'?"selected":""?>>Yes</option>
5592 <option value="1" <?php echo $options['disablePageC']=='1'?"selected":""?>>No</option>
5593</select>
5594
5595<h4>Channel Thumb Width</h4>
5596<input name="thumbWidth" type="text" id="thumbWidth" size="4" maxlength="4" value="<?php echo $options['thumbWidth']?>"/>
5597
5598<h4>Channel Thumb Height</h4>
5599<input name="thumbHeight" type="text" id="thumbHeight" size="4" maxlength="4" value="<?php echo $options['thumbHeight']?>"/>
5600<BR><a href="admin.php?page=live-streaming&tab=stats®enerateThumbs=1">Regenerate Thumbs</a>
5601
5602<h4>Default Channels Per Page</h4>
5603<input name="perPage" type="text" id="perPage" size="3" maxlength="3" value="<?php echo $options['perPage']?>"/>
5604
5605
5606
5607<h4>Show VideoWhisper Powered by</h4>
5608<select name="videowhisper" id="videowhisper">
5609 <option value="0" <?php echo $options['videowhisper']?"":"selected"?>>No</option>
5610 <option value="1" <?php echo $options['videowhisper']?"selected":""?>>Yes</option>
5611</select>
5612
5613<?php
5614 break;
5615
5616 case 'hls':
5617?>
5618<h3>Mobile HTML5 HLS & Transcoding</h3>
5619Configure transcoding and HTML5 HLS delivery to mobile devices and Safari.
5620<p>Special Requirements: This functionality requires FFMPEG with necessary codecs on web host and publishing trough Wowza Streaming Engine server to deliver transcoded streams as HLS.
5621<BR>Recommended Hosting: <a href="http://videowhisper.com/?p=Wowza+Media+Server+Hosting#features" target="_vwhost">VideoWhisper Wowza Turnkey Managed Hosting</a> - turnkey rtmp address, configuration for archiving, transcoding streams, delivery to mobiles as HLS, playlists scheduler, IP cameras, advanced external encoder support.
5622</p>
5623<P>Clarifications:
5624Flash and RTMP camera streaming applications are not supported in mobile browsers. Special solutions are required for mobile users to implement support for this type of features (<A href="https://videowhisper.com/?p=iPhone-iPad-Apps">read more</a>).
5625<BR>Plain streaming is possible in mobile browser with HTML5 as HLS (HTTP Live Streaming).
5626<BR>Broadcasting from mobile is possible with generic RTMP mobile encoders like Wowza GoCoder for <a href="https://itunes.apple.com/us/app/wowza-gocoder/id640338185?mt=8">iOS</a> / <a href="https://play.google.com/store/apps/details?id=com.wowza.gocoder&hl=en">Android</a> that can be used to publish plain stream (no chat or interactions). Generic encoders require user to copy and paste rtmp address, channel name, settings and also <a href="https://videowhisper.com/?p=RTMP-Session-Control">RTMP Session Control</a> (included with VideoWhisper recommended Wowza hosting) to show external published streams as active channels on site.
5627<BR>For advanced interactions and easy usage/access with site credentials login, <a href="https://videowhisper.com/?p=iPhone-iPad-Apps#apps">custom apps can be developed</a> and then <a href="admin.php?page=live-streaming&tab=app">configured from this plugin</a>.
5628</p>
5629
5630<h4>Live Transcoding</h4>
5631<?php
5632
5633 $processUser = get_current_user();
5634 echo "This section shows transcoding and snapshot retrieval processes currently run by account '$processUser'.<BR>";
5635
5636 $cmd = "ps aux | grep 'ffmpeg'";
5637 exec($cmd, $output, $returnvalue);
5638 //var_dump($output);
5639
5640 $transcoders = 0;
5641 foreach ($output as $line) if (strstr($line, "ffmpeg"))
5642 {
5643 $columns = preg_split('/\s+/',$line);
5644 if ($processUser == $columns[0] && (!in_array($columns[10],array('sh','grep'))))
5645 {
5646
5647 echo "Process #".$columns[1]." CPU: ".$columns[2]." Mem: ".$columns[3].' Start: '.$columns[8].' CPU Time: '.$columns[9]. ' Cmd: ';
5648 for ($n=10; $n<24; $n++) echo $columns[$n].' ';
5649
5650 if ($_GET['kill']== $columns[1])
5651 {
5652 $kcmd = 'kill -KILL ' . $columns[1];
5653 exec($kcmd, $koutput, $kreturnvalue);
5654 echo ' <B>Killing process...</B>';
5655 }
5656 else echo ' <a href="admin.php?page=live-streaming&tab=hls&kill='.$columns[1].'">Kill</a>';
5657
5658 echo '<br>';
5659 $transcoders++;
5660 }
5661 }
5662
5663 if (!$transcoders) echo 'No live transcoding/snapshot processes detected.';
5664 else echo '<BR>Total processes for transcoding/snapshot: ' . $transcoders;
5665
5666?>
5667
5668
5669<h4>FFMPEG Path</h4>
5670<input name="ffmpegPath" type="text" id="ffmpegPath" size="100" maxlength="256" value="<?php echo $options['ffmpegPath']?>"/>
5671<BR> Path to latest FFMPEG. Required for transcoding of web based streams, generating snapshots for external broadcasting applications (requires <a href="https://videowhisper.com/?p=RTMP-Session-Control">rtmp session control</a> to notify plugin about these streams).
5672<?php
5673 echo "<BR>exec: ";
5674 if(function_exists('exec'))
5675 {
5676 echo "function is enabled";
5677
5678 if(exec('echo EXEC') == 'EXEC')
5679 {
5680 echo ' and works';
5681 $fexec =1;
5682 }
5683 else echo ' <b>but does not work</b>';
5684
5685 }else echo '<b>function is not enabled</b><BR>PHP function "exec" is required to run FFMPEG. Current hosting settings are not compatible with this functionality.';
5686
5687
5688 echo "<BR>FFMPEG: ";
5689 $cmd =$options['ffmpegPath'] . ' -version';
5690 $output="";
5691 exec($cmd, $output, $returnvalue);
5692 if ($returnvalue == 127) echo "<b>Warning: not detected: $cmd</b>";
5693 else
5694 {
5695 echo "found";
5696
5697 if ($returnvalue != 126)
5698 {
5699 echo '<BR>' . $output[0];
5700 echo '<BR>' . $output[1];
5701 }else
5702 echo ' but is NOT executable by current user: ' . $processUser;
5703 }
5704
5705 $cmd =$options['ffmpegPath'] . ' -codecs';
5706 exec($cmd, $output, $returnvalue);
5707
5708 //detect codecs
5709 if ($output) if (count($output))
5710 {
5711 echo "<br>Codec libraries:";
5712 foreach (array('h264', 'vp6','speex', 'nellymoser', 'fdk_aac', 'faac') as $cod)
5713 {
5714 $det=0; $outd="";
5715 echo "<BR>$cod : ";
5716 foreach ($output as $outp) if (strstr($outp,$cod)) { $det=1; $outd=$outp; };
5717 if ($det) echo "detected ($outd)"; else echo "<b>missing: configure and install FFMPEG with lib$cod if you don't have another library for that codec</b>";
5718 }
5719 }
5720?>
5721<BR>You need only 1 AAC codec. Depending on <a href="https://trac.ffmpeg.org/wiki/Encode/AAC#libfaac">AAC library available on your system</a> you may need to update transcoding parameters. Latest FFMPEG also includes a native encoder (aac).
5722
5723<h4>FFMPEG Transcoding Parameters</h4>
5724<input name="ffmpegTranscode" type="text" id="ffmpegTranscode" size="100" maxlength="256" value="<?php echo $options['ffmpegTranscode']?>"/>
5725<BR>For lower server load and higher performance, web clients should be configured to broadcast video already suitable for target device (H.264 Baseline 3.1 for most iOS devices) so only audio needs to be encoded.
5726
5727<BR>Ex.(transcode audio for iOS using latest FFMPEG with libfdk_aac): -c:v copy -c:a libfdk_aac -b:a 96k
5728<BR>Ex.(transcode audio for iOS using latest FFMPEG with native aac): -c:v copy -c:a aac -b:a 96k
5729<BR>Ex.(transcode audio for iOS using older FFMPEG with libfaac): -vcodec copy -acodec libfaac -ac 2 -ar 22050 -ab 96k
5730<BR>Ex.(transcode video+audio using older FFMPEG): -vcodec libx264 -s 480x360 -r 15 -vb 512k -x264opts vbv-maxrate=364:qpmin=4:ref=4 -coder 0 -bf 0 -analyzeduration 0 -level 3.1 -g 30 -maxrate 768k -acodec libfaac -ac 2 -ar 22050 -ab 96k
5731<BR>For advanced settings see <a href="https://developer.apple.com/library/ios/technotes/tn2224/_index.html#//apple_ref/doc/uid/DTS40009745-CH1-SETTINGSFILES">iOS HLS Supported Codecs<a> and <a href="https://trac.ffmpeg.org/wiki/Encode/AAC">FFMPEG AAC Encoding Guide</a>.
5732
5733<h4>HTTP Streaming Base URL</h4>
5734This is used for accessing transcoded streams on HLS playback. Usually available with <a href="https://videowhisper.com/?p=Wowza+Media+Server+Hosting">Wowza Hosting</a> .<br>
5735<input name="httpstreamer" type="text" id="httpstreamer" size="100" maxlength="256" value="<?php echo $options['httpstreamer']?>"/>
5736<BR>External players and encoders (if enabled) are not monitored or controlled by this plugin, unless special <a href="https://videowhisper.com/?p=RTMP-Session-Control">rtmp side session control</a> is available.
5737<BR>Application folder must match rtmp application (ex: videowhisper-x)
5738<BR>Ex: http://localhost:1935/videowhisper-x/ works when publishing to rtmp://localhost/videowhisper-x .
5739
5740<h4>Enable Transcoding</h4>
5741<select name="transcoding" id="transcoding">
5742 <option value="0" <?php echo $options['transcoding']?"":"selected"?>>No</option>
5743 <option value="1" <?php echo $options['transcoding']?"selected":""?>>Yes</option>
5744</select>
5745<BR>This enables account level transcoding based on FFMPEG.
5746<BR>Transcoding is required for re-encoding live streams broadcast using web client to new re-encoded streams accessible by iOS using HLS. This requires high server processing power for each stream.
5747<BR>HLS support is also required on RTMP server and this is usually available with <a href="https://videowhisper.com/?p=Wowza+Media+Server+Hosting">Wowza Hosting</a> .
5748<BR>Account level transcoding is not required when stream is already broadcast with external encoders in appropriate formats (H264, AAC with supported settings) or using Wowza Transcoder Addon (usually on dedicated servers).
5749
5750<h4>Auto Transcoding</h4>
5751<select name="transcodingAuto" id="transcodingAuto">
5752 <option value="0" <?php echo $options['transcodingAuto']?"":"selected"?>>No</option>
5753 <option value="1" <?php echo $options['transcodingAuto']=='1'?"selected":""?>>HLS</option>
5754 <option value="2" <?php echo $options['transcodingAuto']=='2'?"selected":""?>>Always</option>
5755</select>
5756<BR>HLS starts transcoder when HLS is requested (by a mobile user) and Always when broadcast occurs. As HLS latency is usually several seconds, first viewer may not be able to access stream.
5757<BR>Always will also check transcoding status from time to time (when broadcaster updates status). For external broadcasters (desktop/mobile), <a href="https://videowhisper.com/?p=RTMP-Session-Control#configure">RTMP Session Control</a> is required to activate web transcoding.
5758<BR>Auto transcoding will work only if channel post <a href="admin.php?page=live-streaming&tab=features">Transcode Feature</a> is enabled.
5759
5760<h4>Manual Transcoding</h4>
5761<select name="transcodingManual" id="transcodingManual">
5762 <option value="0" <?php echo $options['transcodingManual']?"":"selected"?>>No</option>
5763 <option value="1" <?php echo $options['transcodingManual']=='1'?"selected":""?>>Yes</option>
5764</select>
5765<BR>Shows transcoding panel to broadcaster for manually toggling transcoding at runtime (for use when automated transcoding is disabled).
5766
5767<h4>Support RTMP Streaming</h4>
5768<select name="supportRTMP" id="supportRTMP">
5769 <option value="0" <?php echo $options['supportRTMP']?"":"selected"?>>No</option>
5770 <option value="1" <?php echo $options['supportRTMP']?"selected":""?>>Yes</option>
5771</select>
5772<BR>Recommended: Yes. Streaming trough the relay RTMP server is most reliable and compulsory for some features like HLS, external player delivery.
5773
5774<h4>Always do RTMP Streaming</h4>
5775<p>Enable this if you want all streams to be published to server, no matter if there are registered subscribers or not (in example if you're using server side video archiving and need all streams
5776published for recording).</p>
5777<select name="alwaysRTMP" id="alwaysRTMP">
5778 <option value="0" <?php echo $options['alwaysRTMP']?"":"selected"?>>No</option>
5779 <option value="1" <?php echo $options['alwaysRTMP']?"selected":""?>>Yes</option>
5780</select>
5781<BR>Recommended: Yes. Warning: Disabling this can disable HLS delivery and increase starting latency for streams. This should be available as backup streaming solution even if P2P is used (in specific conditions).
5782<?php
5783 break;
5784
5785 case 'server':
5786
5787?>
5788<h3>Server Settings</h3>
5789Configure server settings for RTMP (live interactions and streaming) and HTTP (web scripts).
5790<br>To run this, make sure your hosting environment meets all <a href="https://videowhisper.com/?p=Requirements" target="_vwrequirements">requirements</a>.
5791<BR>Recommended hosting: <a href="http://videowhisper.com/?p=Wowza+Media+Server+Hosting#features" target="_vwhost">VideoWhisper Wowza turnkey managed plans</a> - turnkey rtmp address, configuration for archiving, transcoding streams, delivery to mobiles as HLS, playlists scheduler, IP cameras, advanced external encoder support.
5792
5793<h4>RTMP Address</h4>
5794<input name="rtmp_server" type="text" id="rtmp_server" size="100" maxlength="256" value="<?php echo $options['rtmp_server']?>"/>
5795<BR>If you don't have a videowhisper rtmp address
5796yet (from a managed rtmp host), go to <a href="https://videowhisper.com/?p=RTMP+Applications" target="_blank">RTMP Application Setup</a> for installation details.
5797<BR>A public accessible rtmp hosting server is required with custom videowhisper rtmp side. Ex: rtmp://your-server/videowhisper
5798<BR>The custom VideoWhisper rtmp side functionality is compulsory as it manages advanced functionality like chat, online user lists, interactions, webcam/microphone status, advanced session control.
5799
5800<h4>Streams Path (IP Camera Streams / Playlists)</h4>
5801<input name="streamsPath" type="text" id="streamsPath" size="100" maxlength="256" value="<?php echo $options['streamsPath']?>"/>
5802<BR>Path to .stream files monitored by streaming server for restreaming.
5803<BR>Such functionality requires Wowza Streaming Engine 4.2+, web and rtmp on same sever, <a href='https://www.wowza.com/forums/content.php?39-How-to-re-stream-video-from-an-IP-camera-(RTSP-RTP-re-streaming)#config_xml'>specific setup</a>. Streaming server loads configuration from web files, connects to IP camera stream or video file, loads stream and delivers in format suitable for web publishing.
5804<BR>This functionality is available with <a href="http://videowhisper.com/?p=Wowza+Media+Server+Hosting#plans" target="_vwhost">VideoWhisper Wowza plans</a>.
5805If custom ports are used, server firewall must be configured to allow connections.
5806<BR>Can be same as streams path configured in VideoShareVOD.
5807<BR> <?php
5808 echo $options['streamsPath'] . ' : ';
5809 if (file_exists($options['streamsPath']))
5810 {
5811 echo 'Found. ';
5812 if (is_writable($options['streamsPath'])) echo 'Writable. (OK)';
5813 else echo 'NOT writable.';
5814 }
5815 else echo '<b>NOT found!</b>';
5816?>
5817
5818<h4>Disable Bandwidth Detection</h4>
5819<p>Required on some rtmp servers that don't support bandwidth detection and return a Connection.Call.Fail error.</p>
5820<select name="disableBandwidthDetection" id="disableBandwidthDetection">
5821 <option value="0" <?php echo $options['disableBandwidthDetection']?"":"selected"?>>No</option>
5822 <option value="1" <?php echo $options['disableBandwidthDetection']?"selected":""?>>Yes</option>
5823</select>
5824
5825<h4>Token Key</h4>
5826<input name="tokenKey" type="text" id="tokenKey" size="32" maxlength="64" value="<?php echo $options['tokenKey']?>"/>
5827<BR>A <a href="https://videowhisper.com/?p=RTMP+Applications#settings">secure token</a> can be used with Wowza Media Server.
5828
5829<h4>Web Key</h4>
5830<input name="webKey" type="text" id="webKey" size="32" maxlength="64" value="<?php echo $options['webKey']?>"/>
5831<BR>A web key can be used for <a href="http://www.videochat-scripts.com/videowhisper-rtmp-web-authetication-check/">VideoWhisper RTMP Web Session Check</a>. Configure as documented on <a href="https://videowhisper.com/?p=RTMP-Session-Control#configure">RTMP Session Control Configuration</a>. Application.xml settings:<br>
5832
5833<textarea readonly cols="100" rows="4">
5834<?php
5835 $admin_ajax = admin_url() . 'admin-ajax.php';
5836 $webLogin = htmlentities($admin_ajax."?action=vwls&task=rtmp_login&s=");
5837 $webLogout = htmlentities($admin_ajax."?action=vwls&task=rtmp_logout&s=");
5838 $webStatus = htmlentities($admin_ajax."?action=vwls&task=rtmp_status");
5839
5840 echo htmlspecialchars("<Properties>
5841<Property>
5842<Name>acceptPlayers</Name>
5843<Value>true</Value>
5844</Property>
5845<Property>
5846<Name>webLogin</Name>
5847<Value>$webLogin</Value>
5848</Property>
5849<Property>
5850<Name>webKey</Name>
5851<Value>".$options['webKey']."</Value>
5852</Property>
5853<Property>
5854<Name>webLogout</Name>
5855<Value>$webLogout</Value>
5856</Property>
5857<Property>
5858<Name>webStatus</Name>
5859<Value>$webStatus</Value>
5860</Property>
5861</Properties>")
5862?>
5863</textarea>
5864<BR>Warnings: webStatus will not work on 3rd party servers without a full mode license for RTMP side (channel online status will not update). Test if functional by monitoring if external broadcast remains LIVE in <a href="admin.php?page=live-streaming-stats">Statistics</a>.
5865<BR>Broadcaster can't connect at same time from web broadcasting interface and external encoder with session control (as session name will be rejected as duplicate).
5866
5867<h4>Web Status</h4>
5868<select name="webStatus" id="webStatus">
5869 <option value="auto" <?php echo $options['webStatus']=='auto'?"selected":""?>>Auto</option>
5870 <option value="enabled" <?php echo $options['webStatus']=='enabled'?"selected":""?>>Enabled</option>
5871 <option value="disabled" <?php echo $options['webStatus']=='disabled'?"selected":""?>>Disabled</option>
5872</select>
5873<BR>Auto will automatically enable first time webLogin successful authentication occurs for a broadcaster. Will also configure the server IP restriction.
5874
5875<h4>Web Status Server IP Restriction</h4>
5876<input name="rtmp_restrict_ip" type="text" id="rtmp_restrict_ip" size="20" maxlength="48" value="<?php echo $options['rtmp_restrict_ip']?>"/>
5877<BR>Allow status updates only from configured IP. If not defined will configure automatically when first successful webLogin authorisation occurs for a broadcaster. Web status will not work if this is empty or not configured right.
5878<!--
5879<h4>Session Status</h4>
5880<select name="rtmpStatus" id="rtmpStatus">
5881 <option value="0" <?php echo $options['rtmpStatus']=='0'?"":"selected"?>>Auto</option>
5882 <option value="1" <?php echo $options['rtmpStatus']=='1'?"selected":""?>>RTMP</option>
5883</select>
5884<BR>Session status allows monitoring and controlling online users sessions.
5885<BR>Auto: Will monitor web sessions based on requests from HTTP clients (VideoWhisper web applications) and other clients by RTMP.
5886<BR>RTMP: Will monitor all clients by RTMP, including web clients. Web monitoring is disabled.
5887-->
5888
5889<h4>External Transcoder Keys</h4>
5890<select name="externalKeysTranscoder" id="externalKeysTranscoder">
5891 <option value="0" <?php echo $options['externalKeysTranscoder']?"":"selected"?>>No</option>
5892 <option value="1" <?php echo $options['externalKeysTranscoder']?"selected":""?>>Yes</option>
5893</select>
5894<BR>Direct authentication parameters will be used for transcoder, external stream thumbnails in case webLogin is enabled. RTMP server will pass these parameters to webLogin scripts for direct authentication without website access.
5895
5896<h4>On Demand Archiving</h4>
5897<input name="manualArchiving" type="text" id="manualArchiving" size="100" maxlength="200" value="<?php echo $options['manualArchiving']?>"/>
5898<BR>URL to control archiving by web. Leave blank to disable. Sample setting: http://[username]:[password]@[wowza-ip-address]:8086/livestreamrecord?app=videowhisper
5899<BR>On demand archiving can be enabled on Wowza server as documented at https://www.wowza.com/forums/content.php?123-How-to-record-live-streams-(HTTPLiveStreamRecord) . Also requires crossdomain.xml on Wowza web space.
5900
5901<h4>RTMFP Address</h4>
5902<p> Get your own independent RTMFP address by registering for a free <a href="https://www.adobe.com/cfusion/entitlement/index.cfm?e=cirrus" target="_blank">Adobe Cirrus developer key</a>. This is
5903required for P2P support.</p>
5904<input name="serverRTMFP" type="text" id="serverRTMFP" size="80" maxlength="256" value="<?php echo $options['serverRTMFP']?>"/>
5905<h4>P2P Group</h4>
5906<input name="p2pGroup" type="text" id="p2pGroup" size="32" maxlength="64" value="<?php echo $options['p2pGroup']?>"/>
5907<h4>Support RTMP Streaming</h4>
5908<select name="supportRTMP" id="supportRTMP">
5909 <option value="0" <?php echo $options['supportRTMP']?"":"selected"?>>No</option>
5910 <option value="1" <?php echo $options['supportRTMP']?"selected":""?>>Yes</option>
5911</select>
5912<BR>Recommended: Yes. Streaming trough the relay RTMP server is most reliable and compulsory for some features like HLS, external player delivery.
5913
5914<h4>Always do RTMP Streaming</h4>
5915<p>Enable this if you want all streams to be published to server, no matter if there are registered subscribers or not (in example if you're using server side video archiving and need all streams
5916published for recording).</p>
5917<select name="alwaysRTMP" id="alwaysRTMP">
5918 <option value="0" <?php echo $options['alwaysRTMP']?"":"selected"?>>No</option>
5919 <option value="1" <?php echo $options['alwaysRTMP']?"selected":""?>>Yes</option>
5920</select>
5921<BR>Recommended: Yes. Warning: Disabling this can disable HLS delivery and increase starting latency for streams. This should be available as backup streaming solution even if P2P is used (in specific conditions).
5922
5923<h4>Support P2P Streaming</h4>
5924<select name="supportP2P" id="supportP2P">
5925 <option value="0" <?php echo $options['supportP2P']?"":"selected"?>>No</option>
5926 <option value="1" <?php echo $options['supportP2P']?"selected":""?>>Yes</option>
5927</select>
5928<BR>Recommended: No. Warning: P2P is not reliable for most users with regular home connections (most users with regular connections will not be able to broadcast or watch video if that's enabled). P2P is great for users with server grade connections (public IP, high upload) or users in same network.
5929<BR>Warning: Streaming only P2P disables archiving, transcoding and mobile delivery (HLS) as streams no longer go trough server.
5930
5931<h4>Always do P2P Streaming</h4>
5932<select name="alwaysP2P" id="alwaysP2P">
5933 <option value="0" <?php echo $options['alwaysP2P']?"":"selected"?>>No</option>
5934 <option value="1" <?php echo $options['alwaysP2P']?"selected":""?>>Yes</option>
5935</select>
5936<BR>Recommended: No.
5937
5938<h4>Uploads Path</h4>
5939<p>Path where logs and snapshots will be uploaded. Make sure you use a location outside plugin folder to avoid losing logs on updates and plugin uninstallation.</p>
5940<input name="uploadsPath" type="text" id="uploadsPath" size="80" maxlength="256" value="<?php echo $options['uploadsPath']?>"/>
5941<?php
5942 if (!file_exists($options['uploadsPath'])) echo '<br><b>Warning: Folder does not exist. If this warning persists after first access check path permissions:</b> ' . $options['uploadsPath'];
5943 if (!strstr($options['uploadsPath'], get_home_path() )) echo '<br><b>Warning: Uploaded files may not be accessible by web (path is not within WP installation path).</b>';
5944
5945 echo '<br>WordPress Path: ' . get_home_path();
5946 echo '<br>WordPress URL: ' . get_site_url();
5947?>
5948<br>wp_upload_dir()['basedir'] : <?php $wud= wp_upload_dir(); echo $wud['basedir'] ?>
5949<br>$_SERVER['DOCUMENT_ROOT'] : <?php echo $_SERVER['DOCUMENT_ROOT'] ?>
5950
5951<h4>Show Channel Watch when Offline</h4>
5952<p>Display channel watch interface even if channel is not detected as broadcasting.</p>
5953<select name="alwaysWatch" id="alwaysWatch">
5954 <option value="0" <?php echo $options['alwaysWatch']?"":"selected"?>>No</option>
5955 <option value="1" <?php echo $options['alwaysWatch']?"selected":""?>>Yes</option>
5956</select>
5957<br>Useful when broadcasting with external apps and <a href="https://videowhisper.com/?p=RTMP-Session-Control">rtmp side session control</a> is not available.
5958<br>Watch interface always shows for channels that stream from IP cameras or playlists (not affected by this setting).
5959<BR>Warning: Enabling this disables event details, that show on channel page while channel is offline. Disabling this, requires broadcast to be started before viewers come to page.
5960<?php
5961 break;
5962 case 'broadcaster':
5963 $options['parametersBroadcaster'] = htmlentities(stripslashes($options['parametersBroadcaster']));
5964
5965?>
5966<h3>Video Broadcasting</h3>
5967Options for video broadcasting.
5968<h4>Who can broadcast video channels</h4>
5969<select name="canBroadcast" id="canBroadcast">
5970 <option value="members" <?php echo $options['canBroadcast']=='members'?"selected":""?>>All Members</option>
5971 <option value="list" <?php echo $options['canBroadcast']=='list'?"selected":""?>>Members in List</option>
5972</select>
5973<br>These users will be able to use broadcasting interface for managing channels (Broadcast Live) and have access to rtmp address keys for using external applications, if enabled.
5974
5975<h4>Members allowed to broadcast video (comma separated user names, roles, emails, IDs)</h4>
5976<textarea name="broadcastList" cols="64" rows="3" id="broadcastList"><?php echo $options['broadcastList']?>
5977</textarea>
5978
5979
5980<h4>Maximum Broadcating Time (0 = unlimited)</h4>
5981<input name="broadcastTime" type="text" id="broadcastTime" size="7" maxlength="7" value="<?php echo $options['broadcastTime']?>"/> (minutes/period)
5982
5983<h4>Maximum Channel Watch Time (total cumulated view time, 0 = unlimited)</h4>
5984<input name="watchTime" type="text" id="watchTime" size="10" maxlength="10" value="<?php echo $options['watchTime']?>"/> (minutes/period)
5985
5986<h4>Usage Period Reset (0 = never)</h4>
5987<input name="timeReset" type="text" id="timeReset" size="4" maxlength="4" value="<?php echo $options['timeReset']?>"/> (days)
5988
5989<h4>Banned Words in Names</h4>
5990<textarea name="bannedNames" cols="64" rows="3" id="bannedNames"><?php echo $options['bannedNames']?>
5991</textarea>
5992<br>Users trying to broadcast channels using these words will be disconnected.
5993
5994
5995<h4>Redirect broadcaster from own channel page</h4>
5996<select name="broadcasterRedirect" id="broadcasterRedirect">
5997 <option value="0" <?php echo $options['broadcasterRedirect']?"":"selected"?>>No</option>
5998 <option value="dashboard" <?php echo $options['broadcasterRedirect']=='dashboard'?"selected":""?>>Broadcast Live Dashboard</option>
5999 <option value="broadcast" <?php echo $options['broadcasterRedirect']=='broadcast'?"selected":""?>>Broadcast Channel</option>
6000</select>
6001<BR>Redirect broadcaster when accessing own channel page to dashboard or broadcasting interface instead of watch interface.
6002
6003
6004<h3>Web Broadcasting Interface</h3>
6005Settings for web based broadcasting interface. Do not apply for external apps.
6006
6007<h4>Default Webcam Resolution</h4>
6008<select name="camResolution" id="camResolution">
6009<?php
6010 foreach (array('160x120','320x240','426x240','480x360', '640x360', '640x480', '720x480', '720x576', '854x480', '1280x720', '1440x1080', '1920x1080') as $optItm)
6011 {
6012?>
6013 <option value="<?php echo $optItm;?>" <?php echo $options['camResolution']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
6014 <?php
6015 }
6016?>
6017 </select>
6018 <br>Higher resolution will require <a target="_blank" href="http://www.videochat-scripts.com/recommended-h264-video-bitrate-based-on-resolution/">higher bandwidth</a> to avoid visible blocking and quality loss (ex. 1Mbps required for 640x360) .Webcam capture resolution should be same as video size in player/watch interface.
6019
6020<h4>Default Webcam Frames Per Second</h4>
6021<select name="camFPS" id="camFPS">
6022<?php
6023 foreach (array('1','8','10','12','15','29','30','60') as $optItm)
6024 {
6025?>
6026 <option value="<?php echo $optItm;?>" <?php echo $options['camFPS']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
6027 <?php
6028 }
6029?>
6030 </select>
6031
6032
6033<h4>Video Stream Bandwidth</h4>
6034<input name="camBandwidth" type="text" id="camBandwidth" size="7" maxlength="7" value="<?php echo $options['camBandwidth']?>"/> (bytes/s)
6035<br>This sets size of video stream (without audio) and therefore the video quality.
6036<br>Total stream size should be less than maximum broadcaster upload speed (multiply by 8 to get bps, ex. 50000b/s requires connection higher than 400kbps).
6037<br>Do a speed test from broadcaster computer to a location near your streaming (rtmp) server using a tool like <a href="http://www.speedtest.net" target="_blank">SpeedTest.net</a> . Drag and zoom to a server in contry/state where you host (Ex: central US if you host with VideoWhisper) and select it. The upload speed is the maximum data you'll be able to broadcast.
6038
6039<h4>Maximum Video Stream Bandwidth (at runtime)</h4>
6040<input name="camMaxBandwidth" type="text" id="camMaxBandwidth" size="7" maxlength="7" value="<?php echo $options['camMaxBandwidth']?>"/> (bytes/s)
6041
6042<h4>Video Codec</h4>
6043<select name="videoCodec" id="videoCodec">
6044 <option value="H264" <?php echo $options['videoCodec']=='H264'?"selected":""?>>H264</option>
6045 <option value="H263" <?php echo $options['videoCodec']=='H263'?"selected":""?>>H263</option>
6046</select>
6047<BR>H264 provides better quality at same bandwidth but may not be supported by older RTMP server versions (ex. Red5).
6048<BR>When publishing to iOS with HLS, for lower server load and higher performance, web clients should be configured to broadcast video suitable for target device (H.264 Baseline 3.1) so only audio needs to be encoded.
6049
6050
6051<h4>H264 Video Codec Profile</h4>
6052<select name="codecProfile" id="codecProfile">
6053 <option value="main" <?php echo $options['codecProfile']=='main'?"selected":""?>>main</option>
6054 <option value="baseline" <?php echo $options['codecProfile']=='baseline'?"selected":""?>>baseline</option>
6055</select>
6056<br>Recommended: Baseline
6057
6058<h4>H264 Video Codec Level</h4>
6059<select name="codecLevel" id="codecLevel">
6060<?php
6061 foreach (array('1', '1b', '1.1', '1.2', '1.3', '2', '2.1', '2.2', '3', '3.1', '3.2', '4', '4.1', '4.2', '5', '5.1') as $optItm)
6062 {
6063?>
6064 <option value="<?php echo $optItm;?>" <?php echo $options['codecLevel']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
6065 <?php
6066 }
6067?>
6068 </select>
6069<br>Recommended: 3.1
6070
6071<h4>Sound Codec</h4>
6072<select name="soundCodec" id="soundCodec">
6073 <option value="Speex" <?php echo $options['soundCodec']=='Speex'?"selected":""?>>Speex</option>
6074 <option value="Nellymoser" <?php echo $options['soundCodec']=='Nellymoser'?"selected":""?>>Nellymoser</option>
6075</select>
6076<BR>Speex is recommended for voice audio.
6077<BR>Current web codecs used by Flash plugin are not currently supported by iOS. For delivery to iOS, audio should be transcoded to AAC (HE-AAC or AAC-LC up to 48 kHz, stereo audio).
6078
6079<h4>Speex Sound Quality</h4>
6080<select name="soundQuality" id="soundQuality">
6081<?php
6082 foreach (array('0', '1','2','3','4','5','6','7','8','9','10') as $optItm)
6083 {
6084?>
6085 <option value="<?php echo $optItm;?>" <?php echo $options['soundQuality']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
6086 <?php
6087 }
6088?>
6089 </select>
6090 <br>Higher quality requires more <a href="http://www.videochat-scripts.com/speex-vs-nellymoser-bandwidth/" target="_blank" >bandwidth</a>.
6091<br>Speex quality 9 requires 34.2kbps and generates 4275 b/s transfer. Quality 10 requires 42.2 kbps.
6092
6093<h4>Nellymoser Sound Rate</h4>
6094<select name="micRate" id="micRate">
6095<?php
6096 foreach (array('5', '8', '11', '22','44') as $optItm)
6097 {
6098?>
6099 <option value="<?php echo $optItm;?>" <?php echo $options['micRate']==$optItm?"selected":""?>> <?php echo $optItm;?> </option>
6100 <?php
6101 }
6102?>
6103 </select>
6104<br>Higher quality requires more <a href="http://www.videochat-scripts.com/speex-vs-nellymoser-bandwidth/" target="_blank" >bandwidth</a>.
6105<br>NellyMoser rate 22 requires 44.1kbps and generates 5512b/s transfer. Rate 44 requires 88.2 kbps.
6106
6107
6108<h4>Disable Embed/Link Codes</h4>
6109<select name="noEmbeds" id="noEmbeds">
6110 <option value="0" <?php echo $options['noEmbeds']?"":"selected"?>>No</option>
6111 <option value="1" <?php echo $options['noEmbeds']?"selected":""?>>Yes</option>
6112</select>
6113<h4>Show only Video</h4>
6114<select name="onlyVideo" id="onlyVideo">
6115 <option value="0" <?php echo $options['onlyVideo']?"":"selected"?>>No</option>
6116 <option value="1" <?php echo $options['onlyVideo']?"selected":""?>>Yes</option>
6117</select>
6118<BR>Disable all interactive elements (show title, users list, chat). Only plain video broadcasting is possible. During troubleshooting/development this should be disabled to get additional info from chat box.
6119
6120<h4>Parameters for Broadcaster Interface</h4>
6121<textarea name="parametersBroadcaster" id="parametersBroadcaster" cols="64" rows="8"><?php echo $options['parametersBroadcaster']?></textarea>
6122<br>For more details see <a href="https://videowhisper.com/?p=php+live+streaming#integrate">PHP Live Streaming documentation</a>.
6123<br>Ex: &snapshotsTime=60000&room_limit=500&externalInterval=360000&statusInterval=30000
6124 Default:<br><textarea readonly cols="100" rows="3"><?php echo $optionsDefault['parametersBroadcaster']?></textarea>
6125
6126<h4>Online Expiration</h4>
6127<p>How long to consider broadcaster online if no web status update occurs.</p>
6128<input name="onlineExpiration1" type="text" id="onlineExpiration1" size="5" maxlength="6" value="<?php echo $options['onlineExpiration1']?>"/>s
6129<br>Should be 10s higher than maximum statusInterval (ms) configured in parameters. A higher statusInterval decreases web server load caused by status updates.
6130<br>If lower than statusInterval that can cause web server online session sync errors and online users showing offline.
6131
6132<?php
6133 break;
6134
6135 // ! Premium channels
6136 case 'premium':
6137?>
6138<h3>Premium Channels</h3>
6139Options for premium channels. Premium channels have special settings and features that can be defined here.
6140Use in combination with <a href='admin.php?page=live-streaming&tab=features'>Channel Features</a> to define specific capabilities depending on role.
6141
6142<h4>Number of Premium Levels</h4>
6143<input name="premiumLevelsNumber" type="text" id="premiumLevelsNumber" size="7" maxlength="7" value="<?php echo $options['premiumLevelsNumber']?>"/>
6144<br>Number of premium membership levels.
6145
6146<?php
6147
6148 $premiumLev = unserialize($options['premiumLevels']);
6149
6150 for ($i=0; $i < $options['premiumLevelsNumber']; $i++)
6151 {
6152
6153 $premiumLev[$i]['level'] = $i+1;
6154
6155 foreach (array('premiumList','canWatchPremium','watchListPremium','pBroadcastTime','pWatchTime','pCamBandwidth','pCamMaxBandwidth') as $varName)
6156 {
6157 if (isset($_POST[$varName . $i])) $premiumLev[$i][$varName] = $_POST[$varName . $i];
6158 if (!isset($premiumLev[$i][$varName])) $premiumLev[$i][$varName] = $options[$varName]; //default from options
6159 }
6160?>
6161
6162<h3>Premium Level <?php echo ($i+1); ?></h3>
6163
6164<h4>Members that broadcast premium channels (Premium members: comma separated user names, roles, emails, IDs)</h4>
6165<textarea name="premiumList<?php echo $i ?>" cols="64" rows="3" id="premiumList<?php echo $i ?>"><?php echo $premiumLev[$i]['premiumList']?>
6166</textarea>
6167<br>Highest level match is selected.
6168<br>Warning: Certain plugins may implement roles that have a different label than role name. Ex: s2member_level1
6169
6170<h4>Who can watch premium channels</h4>
6171<select name="canWatchPremium<?php echo $i ?>" id="canWatchPremium<?php echo $i ?>">
6172 <option value="all" <?php echo $premiumLev[$i]['canWatchPremium']=='all'?"selected":""?>>Anybody</option>
6173 <option value="members" <?php echo $premiumLev[$i]['canWatchPremium']=='members'?"selected":""?>>All Members</option>
6174 <option value="list" <?php echo $premiumLev[$i]['canWatchPremium']=='list'?"selected":""?>>Members in List</option>
6175</select>
6176
6177<h4>Members allowed to watch premium channels (comma separated usernames, roles, emails, IDs)</h4>
6178<textarea name="watchListPremium<?php echo $i ?>" cols="64" rows="3" id="watchListPremium<?php echo $i ?>"><?php echo $premiumLev[$i]['watchListPremium']?>
6179</textarea>
6180
6181<h4>Maximum Broadcating Time (0 = unlimited)</h4>
6182<input name="pBroadcastTime<?php echo $i ?>" type="text" id="pBroadcastTime<?php echo $i ?>" size="7" maxlength="7" value="<?php echo $premiumLev[$i]['pBroadcastTime']?>"/> (minutes/period)
6183
6184<h4>Maximum Channel Watch Time (total cumulated view time, 0 = unlimited)</h4>
6185<input name="pWatchTime<?php echo $i ?>" type="text" id="pWatchTime<?php echo $i ?>" size="10" maxlength="10" value="<?php echo $premiumLev[$i]['pWatchTime']?>"/> (minutes/period)
6186
6187<h4>Video Stream Bandwidth</h4>
6188<input name="pCamBandwidth<?php echo $i ?>" type="text" id="pCamBandwidth<?php echo $i ?>" size="7" maxlength="7" value="<?php echo $premiumLev[$i]['pCamBandwidth']?>"/> (bytes/s)
6189<br>Default stream size for web broadcasting interface.
6190
6191<h4>Maximum Video Stream Bandwidth (at runtime)</h4>
6192<input name="pCamMaxBandwidth<?php echo $i ?>" type="text" id="pCamMaxBandwidth<?php echo $i ?>" size="7" maxlength="7" value="<?php echo $premiumLev[$i]['pCamMaxBandwidth']?>"/> (bytes/s)
6193<br>Maximum stream size for web broadcasting interface.
6194<?php
6195 }
6196
6197
6198
6199 $options['premiumLevels'] = serialize($premiumLev);
6200 update_option('VWliveStreamingOptions', $options);
6201
6202 /*
6203<h4>Show Floating Logo/Watermark</h4>
6204<select name="pLogo" id="pLogo">
6205 <option value="0" <?php echo $options['pLogo']?"":"selected"?>>No</option>
6206 <option value="1" <?php echo $options['pLogo']?"selected":""?>>Yes</option>
6207</select>
6208
6209<h4>Always do RTMP Streaming (required for Transcoding)</h4>
6210<p>Enable this if you want all streams to be published to server, no matter if there are registered subscribers or not. Stream on server is required for transcoding to start.</p>
6211<select name="alwaysRTMP" id="alwaysRTMP">
6212 <option value="0" <?php echo $options['alwaysRTMP']?"":"selected"?>>No</option>
6213 <option value="1" <?php echo $options['alwaysRTMP']?"selected":""?>>Yes</option>
6214</select>
6215*/
6216?>
6217
6218<h3>Common Settings</h3>
6219
6220<h4>Usage Period Reset (same as for regular channels, 0 = never)</h4>
6221<input name="timeReset" type="text" id="timeReset" size="4" maxlength="4" value="<?php echo $options['timeReset']?>"/> (days)
6222<?php
6223 break;
6224 case 'features':
6225
6226 //! Channel Features
6227?>
6228<h3>Channel Features</h3>
6229Enable channel features, accessible by owner (broadcaster).
6230<br>Specify comma separated list of user roles, emails, logins able to setup these features for their channels.
6231<br>Use All to enable for everybody and None or blank to disable.
6232<?php
6233
6234 $features = VWliveStreaming::roomFeatures();
6235
6236 foreach ($features as $key=>$feature) if ($feature['installed'])
6237 {
6238 echo '<h3>' . $feature['name'] . '</h3>';
6239 echo '<textarea name="'.$key.'" cols="64" rows="2" id="'.$key.'">' . trim($options[$key]) . '</textarea>';
6240 echo '<br>' . $feature['description'];
6241 }
6242
6243
6244 break;
6245
6246 case 'watcher':
6247 $options['parameters'] = htmlentities(stripslashes($options['parameters']));
6248 $options['layoutCode'] = htmlentities(stripslashes($options['layoutCode']));
6249 $options['watchStyle'] = htmlentities(stripslashes($options['watchStyle']));
6250
6251
6252?>
6253<h3>Video Watcher</h3>
6254Settings for video subscribers that watch the live channels using watch or plain video interface.
6255<h4>Who can watch video</h4>
6256<select name="canWatch" id="canWatch">
6257 <option value="all" <?php echo $options['canWatch']=='all'?"selected":""?>>Anybody</option>
6258 <option value="members" <?php echo $options['canWatch']=='members'?"selected":""?>>All Members</option>
6259 <option value="list" <?php echo $options['canWatch']=='list'?"selected":""?>>Members in List</option>
6260</select>
6261<h4>Members allowed to watch video (comma separated usernames, roles, IDs)</h4>
6262<textarea name="watchList" cols="100" rows="3" id="watchList"><?php echo $options['watchList']?>
6263</textarea>
6264
6265<h4>Parameters for Watch and Video Interfaces</h4>
6266<textarea name="parameters" id="parameters" cols="100" rows="4"><?php echo $options['parameters']?></textarea>
6267<br>For more details see <a href="https://videowhisper.com/?p=php+live+streaming#integrate">PHP Live Streaming documentation</a>.
6268<br>Ex: &externalInterval=360000&statusInterval=30000
6269 Default:<br><textarea readonly cols="100" rows="3"><?php echo $optionsDefault['parameters']?></textarea>
6270<br>Warning: Some parameters are controlled by plugin integration (user and room name, chat and participants panel) and should not be defined here again.
6271
6272<h4>Online Expiration</h4>
6273<p>How long to consider viewer online if no web status update occurs.</p>
6274<input name="onlineExpiration0" type="text" id="onlineExpiration0" size="5" maxlength="6" value="<?php echo $options['onlineExpiration0']?>"/>s
6275<br>Should be 10s higher than maximum statusInterval (ms) configured in parameters. A higher statusInterval decreases web server load caused by status updates.
6276
6277<h4>Custom Layout Code</h4>
6278<textarea name="layoutCode" id="layoutCode" cols="100" rows="4"><?php echo $options['layoutCode']?></textarea>
6279<br>Generate by writing and sending "/videowhisper layout" in chat (contains panel positions, sizes, move and resize toggles). Copy and paste code here.
6280 Default:<br><textarea readonly cols="100" rows="3"><?php echo $optionsDefault['layoutCode']?></textarea>
6281
6282<h4>Container Style</h4>
6283<textarea name="watchStyle" id="watchStyle" cols="100" rows="4"><?php echo $options['watchStyle']?></textarea>
6284<br>Ex: width:100%; height:400px;
6285 Default:<br><textarea readonly cols="100" rows="3"><?php echo $optionsDefault['watchStyle']?></textarea>
6286
6287<?php
6288 break;
6289
6290 case 'billing':
6291?>
6292<h3>Billing Settings</h3>
6293
6294<h4>Enable myCRED Integration</h4>
6295<select name="mycred" id="mycred">
6296 <option value="0" <?php echo $options['mycred']?"":"selected"?>>No</option>
6297 <option value="1" <?php echo $options['mycred']?"selected":""?>>Yes</option>
6298</select>
6299<br>Enables interface for channel owners to setup a price and sell access to channels (as configured in Features section). Requires myCRED plugin (see below).
6300
6301
6302<h3>Setup and Configure myCRED</h3>
6303Follow steps below to make sure myCRED is setup and configured to manage channel access sales.
6304
6305<h4>1) myCRED</h4>
6306<?php
6307 if (is_plugin_active('mycred/mycred.php')) echo 'Detected'; else echo 'Not detected. Please install and activate <a target="_mycred" href="https://wordpress.org/plugins/mycred/">myCRED</a>!';
6308
6309 if (function_exists( 'mycred_get_users_cred')) echo '<br>Testing balance: You have ' . mycred_get_users_cred() . ' points.';
6310?>
6311
6312<p><a target="_mycred" href="https://wordpress.org/plugins/mycred/">myCRED</a> is an adaptive points management system that lets you award / charge your users for interacting with your WordPress powered website. The Buy Content add-on allows you to sell any publicly available post types, including video presentation posts created by this plugin. You can select to either charge users to view the content or pay the post's author either the whole sum or a percentage.<p>
6313<h4>2) myCRED buyCRED Module</h4>
6314 <?php
6315 if (class_exists( 'myCRED_buyCRED_Module' ) )
6316 {
6317 echo 'Detected';
6318?>
6319 <ul>
6320 <li>* <a href="edit.php?post_type=buycred_payment">Pending Payments</a></li>
6321 </ul>
6322 <?php
6323 } else echo 'Not detected. Please install and activate myCRED with <a href="admin.php?page=mycred-addons">buyCRED addon</a>!';
6324?>
6325<p>
6326myCRED <a href="admin.php?page=mycred-addons">buyCRED addon</a> should be enabled and at least 1 <a href="admin.php?page=mycred-gateways">payment gateway</a> configured for users to be able to buy credits.
6327<br>Setup a page for users to buy credits with shortcode <a target="mycred" href="http://codex.mycred.me/shortcodes/mycred_buy_form/">[mycred_buy_form]</a>.
6328<br>Also "Thank You Page" should be set to "Channels" and "Cancellation Page" to "Buy Credits" from <a href="admin.php?page=mycred-settings">buyCred settings</a>.</p>
6329<h4>3) myCRED Sell Content Module</h4>
6330 <?php
6331 if (class_exists( 'myCRED_Sell_Content_Module' ) ) echo 'Detected'; else echo 'Not detected. Please install and activate myCRED with <a href="admin.php?page=mycred-addons">Sell Content addon</a>!';
6332?>
6333<p>
6334myCRED <a href="admin.php?page=mycred-addons">Sell Content addon</a> should be enabled as it's required to enable certain stat shortcodes. Optionally select "<?php echo ucwords($options['custom_post'])?>" - I Manually Select as Post Types you want to sell in <a href="admin.php?page=mycred-settings">Sell Content settings tab</a> so access to channels can be sold. You can also configure payout to content author from there (Profit Share) and expiration, if necessary.
6335<?php
6336 break;
6337
6338 case 'tips':
6339 //! Pay Per View Settings
6340?>
6341<h3>Tips</h3>
6342Allows viewers to send tips from watch interface. Requires billing setup.
6343
6344<h4>Enable Tips</h4>
6345<select name="tips" id="tips">
6346 <option value="1" <?php echo $options['tips']?"selected":""?>>Yes</option>
6347 <option value="0" <?php echo $options['tips']?"":"selected"?>>No</option>
6348</select>
6349<br>Allows clients to tip performers.
6350
6351<h4>Tip Options</h4>
6352<?php
6353 $options['tipOptions'] = htmlentities(stripslashes($options['tipOptions']));
6354?>
6355<textarea name="tipOptions" id="tipOptions" cols="100" rows="8"><?php echo $options['tipOptions']?></textarea>
6356<br>List of tip options as XML. Sounds must be deployed in videowhisper/templates/live/tips folder.
6357
6358<h4>Broadcaster Earning Ratio</h4>
6359<input name="tipRatio" type="text" id="tipRatio" size="10" maxlength="16" value="<?php echo $options['tipRatio']?>"/>
6360<br>Performer receives this ratio from client tip.
6361<br>Ex: 0.9; Set 0 to disable (performer receives nothing). Set 1 for performer to get full amount paid by client.
6362
6363
6364 <?php
6365 break;
6366
6367 }
6368
6369 if (!in_array($active_tab, array('live','stats', 'shortcodes', 'support')) ) submit_button(); ?>
6370
6371</form>
6372</div>
6373 <?php
6374 }
6375
6376
6377 //! App Calls / integration, auxiliary
6378
6379 function editParameters($default = '', $update = array(), $remove = array())
6380 {
6381 //adjust parameters string by update(add)/remove
6382
6383 parse_str(substr($default,1), $params);
6384
6385 //remove
6386
6387 if (count($update)) foreach ($params as $key => $value)
6388 if (in_array($key, $update)) unset($params[$key]);
6389
6390 if (count($remove)) foreach ($params as $key => $value)
6391 if (in_array($key, $remove)) unset($params[$key]);
6392
6393
6394 //add updated
6395 if (count($update)) foreach ($update as $key => $value) $params[$key] = $value;
6396
6397 return '&' . http_build_query($params);
6398 }
6399
6400
6401
6402 function webSessionSave($username, $canKick=0, $debug = "0")
6403 {
6404 //this fc generates a session file record for rtmp login check
6405
6406 $username = sanitize_file_name($username);
6407
6408 if ($username)
6409 {
6410
6411 $options = get_option('VWliveStreamingOptions');
6412 $webKey = $options['webKey'];
6413 $ztime = time();
6414
6415 $ztime=time();
6416 $info = "VideoWhisper=1&login=1&webKey=$webKey&start=$ztime&canKick=$canKick&debug=$debug";
6417
6418 $dir=$options['uploadsPath'];
6419 if (!file_exists($dir)) mkdir($dir);
6420 @chmod($dir, 0777);
6421 $dir.="/_sessions";
6422 if (!file_exists($dir)) mkdir($dir);
6423 @chmod($dir, 0777);
6424
6425 $dfile = fopen($dir."/$username","w");
6426 fputs($dfile,$info);
6427 fclose($dfile);
6428 }
6429
6430 }
6431
6432 function sessionUpdate($username='', $room='', $broadcaster=0, $type=1, $strict=1)
6433 {
6434
6435 //type 1=http, 2=rtmp
6436 //strict = create new if not that type
6437
6438 if (!$username) return;
6439 $ztime = time();
6440
6441 global $wpdb;
6442 if ($broadcaster) $table_name = $wpdb->prefix . "vw_sessions";
6443 else $table_name = $wpdb->prefix . "vw_lwsessions";
6444
6445 $cnd = '';
6446 if ($strict) $cnd = " AND `type`='$type'";
6447
6448 //online broadcasting session
6449 $sqlS = "SELECT * FROM $table_name where session='$username' and status='1' $cnd ORDER BY edate DESC LIMIT 0,1";
6450 $session = $wpdb->get_row($sqlS);
6451
6452 if (!$session)
6453 $sql="INSERT INTO `$table_name` ( `session`, `username`, `room`, `message`, `sdate`, `edate`, `status`, `type`) VALUES ('$username', '$username', '$room', '', $ztime, $ztime, 1, $type)";
6454 else $sql="UPDATE `$table_name` set edate=$ztime, room='$room', username='$username' where id ='".$session->id."'";
6455 $wpdb->query($sql);
6456
6457
6458 if ($broadcaster)
6459 {
6460 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $room . "' and post_type='channel' LIMIT 0,1" );
6461 if ($postID) update_post_meta($postID, 'edate', $ztime);
6462 }
6463
6464 VWliveStreaming::cleanSessions($broadcaster);
6465
6466 $session = $wpdb->get_row($sqlS);
6467 return $session;
6468 }
6469
6470 function cleanSessions($broadcaster=0)
6471 {
6472
6473 $options = get_option('VWliveStreamingOptions');
6474
6475 if (!VWliveStreaming::timeTo('cleanSessions'.$broadcaster, 25, $options)) return;
6476
6477 $ztime = time();
6478 global $wpdb;
6479
6480 if ($broadcaster) $table_name = $wpdb->prefix . "vw_sessions";
6481 else $table_name = $wpdb->prefix . "vw_lwsessions";
6482
6483 if (!$options['onlineExpiration' . $broadcaster]) $options['onlineExpiration' . $broadcaster] = 310;
6484 $exptime=$ztime-$options['onlineExpiration' . $broadcaster];
6485 $sql="DELETE FROM `$table_name` WHERE edate < $exptime";
6486 $wpdb->query($sql);
6487
6488 }
6489
6490 function streamSnapshot($stream, $ipcam = false)
6491 {
6492 $stream = sanitize_file_name($stream);
6493 if (strstr($stream,'.php')) return;
6494 if (!$stream) return;
6495
6496 $options = get_option('VWliveStreamingOptions');
6497
6498 $dir = $options['uploadsPath'];
6499 if (!file_exists($dir)) mkdir($dir);
6500 $dir .= "/_snapshots";
6501 if (!file_exists($dir)) mkdir($dir);
6502
6503 if (!file_exists($dir))
6504 {
6505 $error = error_get_last();
6506 echo 'Error - Folder does not exist and could not be created: ' . $dir . ' - '. $error['message'];
6507
6508 }
6509
6510 $filename = "$dir/$stream.jpg";
6511 if (file_exists($filename)) if (time()-filemtime($filename) < 15) return; //do not update if fresh (15s)
6512
6513 $log_file = $filename . '.txt';
6514
6515 global $wpdb;
6516 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $stream . "' and post_type='channel' LIMIT 0,1" );
6517
6518 if ($options['externalKeysTranscoder'])
6519 {
6520 $keyView = md5('vw' . $options['webKey']. $postID);
6521 $rtmpAddressView = $options['rtmp_server'] . '?'. urlencode('ffmpegSnap_' . $stream) .'&'. urlencode($stream) .'&'. $keyView . '&0&videowhisper';
6522 }
6523 else $rtmpAddressView = $options['rtmp_server'];
6524
6525 $cmd = $options['ffmpegPath'] . " -f image2 -vframes 1 \"$filename\" -y -i \"" . $rtmpAddressView ."/". $stream . "\" >&$log_file & ";
6526
6527 //echo $cmd;
6528 exec($cmd, $output, $returnvalue);
6529 exec("echo '$cmd' >> $log_file.cmd", $output, $returnvalue);
6530
6531 //failed
6532 if (!file_exists($filename)) return;
6533
6534 //if snapshot successful update edate
6535 if ($ipcam) update_post_meta($postID, 'edate', time());
6536
6537 //generate thumb
6538 $thumbWidth = $options['thumbWidth'];
6539 $thumbHeight = $options['thumbHeight'];
6540
6541 $src = imagecreatefromjpeg($filename);
6542 list($width, $height) = getimagesize($filename);
6543 $tmp = imagecreatetruecolor($thumbWidth, $thumbHeight);
6544
6545 $dir = $options['uploadsPath']. "/_thumbs";
6546 if (!file_exists($dir)) mkdir($dir);
6547
6548 $thumbFilename = "$dir/$stream.jpg";
6549 imagecopyresampled($tmp, $src, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $width, $height);
6550 imagejpeg($tmp, $thumbFilename, 95);
6551
6552 //update room status to 1 or 2
6553 $table_name3 = $wpdb->prefix . "vw_lsrooms";
6554
6555 //detect tiny images without info
6556 if (filesize($thumbFilename)>5000) $picType = 1;
6557 else $picType = 2;
6558
6559 $sql="UPDATE `$table_name3` set status='$picType' where name ='$stream'";
6560 $wpdb->query($sql);
6561
6562 //update post meta
6563 if ($postID) update_post_meta($postID, 'hasSnapshot', $picType);
6564
6565 }
6566
6567 function rtmpSnapshot($session)
6568 {
6569
6570 VWliveStreaming::streamSnapshot($session->session);
6571 }
6572
6573 function premiumOptions($userkeys, $options)
6574 {
6575
6576 $premiumLev = unserialize($options['premiumLevels']);
6577
6578 if ($options['premiumLevelsNumber'])
6579 for ($i= ($options['premiumLevelsNumber']-1) ; $i >= 0 ; $i--)
6580 if ($premiumLev[$i]['premiumList'])
6581 if (VWliveStreaming::inList($userkeys, $premiumLev[$i]['premiumList'])) return $premiumLev[$i];
6582
6583 //not found
6584 return false;
6585 }
6586
6587 function channelOptions($type, $options)
6588 {
6589 $premiumLev = unserialize($options['premiumLevels']);
6590
6591 $i = $type-2;
6592 if ($premiumLev[$i]) return $premiumLev[$i];
6593
6594 //regular channel
6595 return $options;
6596 }
6597
6598 /*
6599 function premiumLevel($userkeys, $options)
6600 {
6601
6602 $premiumLev = unserialize($options['premiumLevels']);
6603
6604 if ($options['premiumLevelsNumber'])
6605 for ($i=$options['premiumLevelsNumber'] - 1 ; $i >= 0 ; $i--)
6606 if ($premiumLev[$i]['premiumList'])
6607 if (!VWliveStreaming::inList($userkeys, $premiumLev[$i]['premiumList'])) return ($i+1);
6608
6609 return 0;
6610 }
6611*/
6612
6613 //! Online user functions
6614
6615
6616 function updateViewers($postID, $room, $options)
6617 {
6618 if (!VWliveStreaming::timeTo($room . '/updateViewers', 30, $options)) return;
6619
6620 if (!$options) $options = get_option('VWliveStreamingOptions');
6621
6622 global $wpdb;
6623 $table_name = $wpdb->prefix . "vw_vmls_sessions";
6624
6625 VWliveStreaming::cleanSessions(1);
6626
6627 //update viewers
6628
6629 $table_name2 = $wpdb->prefix . "vw_lwsessions";
6630 $viewers = $wpdb->get_results("SELECT count(id) as no FROM `$table_name2` where status='1' and type='1' and room='" . $r . "'");
6631
6632 update_post_meta($postID, 'viewers', $viewers);
6633 $maxViewers = get_post_meta($postID, 'maxViewers', true);
6634 if ($viewers >= $maxViewers)
6635 {
6636 update_post_meta($postID, 'maxViewers', $viewers);
6637 update_post_meta($postID, 'maxDate', $ztime);
6638 }
6639
6640
6641 }
6642
6643 function timeTo($action, $expire = 60, $options='')
6644 {
6645 //if $action was already done in last $expire, return false
6646
6647 if (!$options) $options = get_option('VWliveStreamingOptions');
6648
6649 $cleanNow = false;
6650
6651
6652 $ztime = time();
6653
6654 $lastClean = 0;
6655 $lastCleanFile = $options['uploadsPath'] . '/' . $action . '.txt';
6656
6657 if (!file_exists($dir = dirname($lastCleanFile))) mkdir($dir);
6658 elseif (file_exists($lastCleanFile)) $lastClean = file_get_contents($lastCleanFile);
6659
6660 if (!$lastClean) $cleanNow = true;
6661 else if ($ztime - $lastClean > $expire) $cleanNow = true;
6662
6663 if ($cleanNow)
6664 file_put_contents($lastCleanFile, $ztime);
6665
6666
6667 return $cleanNow;
6668
6669 }
6670
6671
6672
6673 function userWatchLimit($user, $options)
6674 {
6675 $userLimit = $options['userWatchLimitDefault'];
6676
6677 foreach ($options['userWatchLimits'] as $role => $limit)
6678 if (in_array(strtolower($role), $user->roles))
6679 {
6680 if (!$limit) //unlimited
6681 {
6682 $userLimit = 0;
6683 break; //no more search
6684 }
6685
6686 if ($limit > $userLimit) $userLimit = $limit; //upgrade limit (best applies)
6687
6688 }
6689
6690 return $userLimit;
6691 }
6692
6693 function updateUserWatchtime($user, $dS, $options)
6694 {
6695 if (!$user) return;
6696 if (!$user->ID) return;
6697
6698 if (!$options) $options = get_option('VWliveStreamingOptions');
6699
6700 //update watch time
6701 //check if new interval
6702 $lastUpdate = get_user_meta( $user->ID, 'vwls_watch_update', true );
6703
6704 if ($lastUpdate < time() - $options['userWatchInterval']) //older that interval refresh
6705 {
6706 update_user_meta($user->ID, 'vwls_watch_update', time());
6707 update_user_meta($user->ID, 'vwls_watch', $dS);
6708 $currentWatch = $dS;
6709
6710 }else
6711 {
6712 $currentWatch = get_user_meta( $user->ID, 'vwls_watch', true );
6713 $currentWatch += $dS;
6714 update_user_meta($user->ID, 'vwls_watch', $currentWatch);
6715 }
6716
6717 $userLimit = VWliveStreaming::userWatchLimit($user, $options);
6718
6719 if (!$userLimit) return; //unlimited
6720
6721 if ($currentWatch > $userLimit) return 1; //return 1 if exceeded
6722
6723 return; //limit not reached
6724
6725
6726 }
6727
6728
6729 function userParameters($user, $config)
6730 {
6731 if (!$user) return;
6732 if (!$user->ID) return;
6733
6734 $parameters = array();
6735
6736 if (is_array($config))
6737 foreach ($config as $parameter => $roleValue)
6738 foreach ($roleValue as $role => $value)
6739 if (in_array(strtolower($role), $user->roles)) $parameters[$parameter] = $value;
6740
6741 return $parameters;
6742
6743 }
6744 function rexit($output)
6745 {
6746 echo $output;
6747 exit;
6748 }
6749
6750 /**
6751 * Retrieves the best guess of the client's actual IP address.
6752 * Takes into account numerous HTTP proxy headers due to variations
6753 * in how different ISPs handle IP addresses in headers between hops.
6754 */
6755 function get_ip_address() {
6756 $ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');
6757 foreach ($ip_keys as $key) {
6758 if (array_key_exists($key, $_SERVER) === true) {
6759 foreach (explode(',', $_SERVER[$key]) as $ip) {
6760 // trim for safety measures
6761 $ip = trim($ip);
6762 // attempt to validate IP
6763 if (VWliveStreaming::validate_ip($ip)) {
6764 return $ip;
6765 }
6766 }
6767 }
6768 }
6769 return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : false;
6770 }
6771
6772 /**
6773 * Ensures an ip address is both a valid IP and does not fall within
6774 * a private network range.
6775 */
6776 function validate_ip($ip)
6777 {
6778 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
6779 return false;
6780 }
6781 return true;
6782 }
6783
6784
6785 //! Ajax App Calls
6786
6787 static function vwls_calls()
6788 {
6789 function sanV(&$var, $file=1, $html=1, $mysql=1) //sanitize variable depending on use
6790 {
6791 if (!$var) return;
6792
6793 if (get_magic_quotes_gpc()) $var = stripslashes($var);
6794
6795 if ($file) $var = sanitize_file_name($var);
6796
6797 if ($html&&!$file)
6798 {
6799 $var=strip_tags($var);
6800 }
6801
6802 if ($mysql&&!$file)
6803 {
6804 $forbidden=array("'", "\"", "´", "`", "\\", "%");
6805 foreach ($forbidden as $search) $var=str_replace($search,"",$var);
6806 $var=mysql_real_escape_string($var);
6807 }
6808 }
6809
6810 global $wpdb;
6811 global $current_user;
6812
6813 ob_clean();
6814
6815 switch ($_GET['task'])
6816 {
6817 //! vw_snapshots
6818 case 'vw_snapshots':
6819 $options = get_option('VWliveStreamingOptions');
6820
6821 $dir=$options['uploadsPath'];
6822 if (!file_exists($dir)) mkdir($dir);
6823 $dir .= "/_snapshots";
6824 if (!file_exists($dir)) mkdir($dir);
6825
6826 //get jpg bytearray
6827 $jpg = $GLOBALS["HTTP_RAW_POST_DATA"];
6828 if (!$jpg) $jpg = file_get_contents("php://input");
6829
6830 if ($jpg)
6831 {
6832 $stream = $_GET['name'];
6833 sanV($stream);
6834 if (strstr($stream,'.php')) exit;
6835 if (!$stream) exit;
6836
6837 // get bytearray
6838 $jpg = $GLOBALS["HTTP_RAW_POST_DATA"];
6839
6840 // save file
6841 $filename = "$dir/$stream.jpg";
6842 $fp=fopen($filename ,"w");
6843 if ($fp)
6844 {
6845 fwrite($fp,$jpg);
6846 fclose($fp);
6847 }
6848
6849 //generate thumb
6850 $thumbWidth = $options['thumbWidth'];
6851 $thumbHeight = $options['thumbHeight'];
6852
6853 $src = imagecreatefromjpeg($filename);
6854 list($width, $height) = getimagesize($filename);
6855 $tmp = imagecreatetruecolor($thumbWidth, $thumbHeight);
6856
6857 $dir = $options['uploadsPath']. "/_thumbs";
6858 if (!file_exists($dir)) mkdir($dir);
6859
6860 $thumbFilename = "$dir/$stream.jpg";
6861 imagecopyresampled($tmp, $src, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $width, $height);
6862 imagejpeg($tmp, $thumbFilename, 95);
6863
6864 //update room status to 1 or 2
6865 $table_name3 = $wpdb->prefix . "vw_lsrooms";
6866
6867 //detect tiny images without info
6868 if (filesize($thumbFilename)>2000) $picType = 1;
6869 else $picType = 2;
6870
6871 $sql="UPDATE `$table_name3` set status='$picType' where name ='$stream'";
6872 $wpdb->query($sql);
6873
6874 //update post meta
6875 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . sanitize_file_name($stream) . "' and post_type='channel' LIMIT 0,1" );
6876 if ($postID) update_post_meta($postID, 'hasSnapshot', $picType);
6877
6878 }else echo 'missingJpgData=1&';
6879
6880 ?>loadstatus=1<?php
6881 break;
6882
6883 //! lb_logout
6884 case 'lb_logout':
6885 wp_redirect( get_home_url() .'?msg='. urlencode($_GET['message']) );
6886 break;
6887
6888 //! vw_logout
6889 case 'vw_logout':
6890 ?>loggedout=1<?php
6891 break;
6892
6893 //! vw_extregister
6894 case 'vw_extregister':
6895
6896 $options = get_option('VWliveStreamingOptions');
6897
6898 $user_name = base64_decode($_GET['u']);
6899 $password = base64_decode($_GET['p']);
6900 $user_email = base64_decode($_GET['e']);
6901 if (!$_GET['videowhisper']) exit;
6902
6903 $msg = '';
6904
6905 $user_name = sanitize_file_name($user_name);
6906
6907 $loggedin=0;
6908 if (username_exists($user_name)) $msg .= __('Username is not available. Choose another!');
6909 if (email_exists($user_email)) $msg .= __('Email is already registered.');
6910
6911 if (!is_email( $user_email )) $msg .= __('Email is not valid.');
6912
6913
6914 if ($msg=='' && $user_name && $user_email && $password)
6915 {
6916 $user_id = wp_create_user( $user_name, $password, $user_email );
6917 $loggedin = 1;
6918
6919 //create channel
6920 $post = array(
6921 'post_content' => sanitize_text_field($_POST['description']),
6922 'post_name' => $user_name,
6923 'post_title' => $user_name,
6924 'post_author' => $user_id,
6925 'post_type' => $options['custom_post'],
6926 'post_status' => 'publish',
6927 );
6928
6929 $postID = wp_insert_post($post);
6930
6931 $msg .= __('Username and channel created: ') . $user_name ;
6932 } else $msg .= __('Could not register account.');
6933
6934 ?>firstParameter=fix&msg=<?php echo urlencode($msg); ?>&loggedin=<?php echo $loggedin;?><?php
6935
6936 break;
6937
6938 //! vw_extlogin
6939 case 'vw_extlogin':
6940
6941 //external login GET u=user, p=password
6942
6943 $options = get_option('VWliveStreamingOptions');
6944 $rtmp_server = $options['rtmp_server'];
6945 $rtmp_amf = $options['rtmp_amf'];
6946 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
6947
6948 $camRes = explode('x',$options['camResolutionMobile']);
6949
6950 $canBroadcast = $options['canBroadcast'];
6951 $broadcastList = $options['broadcastList'];
6952
6953 $tokenKey = $options['tokenKey'];
6954 $webKey = $options['webKey'];
6955
6956 $loggedin=0;
6957 $msg="";
6958
6959 $creds = array();
6960 $creds['user_login'] = base64_decode($_GET['u']);
6961 $creds['user_password'] = base64_decode($_GET['p']);
6962 $creds['remember'] = true;
6963 if (!$_GET['videowhisper']) exit;
6964
6965
6966 remove_all_actions('wp_login'); //disable redirects or other output
6967 $current_user = wp_signon( $creds, false );
6968
6969 if( is_wp_error($current_user))
6970 {
6971 $msg = urlencode($current_user->get_error_message()) ;
6972 $debug = $msg;
6973 }
6974 else
6975 {
6976 //logged in
6977 }
6978
6979 $current_user = wp_get_current_user();
6980
6981
6982 //username
6983 if ($current_user->$userName) $username=urlencode($current_user->$userName);
6984 sanV($username);
6985
6986
6987 if ($username)
6988 {
6989 switch ($canBroadcast)
6990 {
6991
6992 case "members":
6993 $loggedin=1;
6994 break;
6995
6996 case "list";
6997 if (VWliveStreaming::inList($username, $broadcastList)) $loggedin=1;
6998 else $msg .= urlencode("$username, you are not in the broadcasters list.");
6999 break;
7000 }
7001
7002 }else $msg .= urlencode("Login required to broadcast.");
7003
7004 if ($loggedin)
7005 {
7006
7007 $args = array(
7008 'author' => $current_user->ID,
7009 'orderby' => 'post_date',
7010 'order' => 'DESC',
7011 'post_type' => 'channel',
7012 );
7013
7014 $channels = get_posts( $args );
7015 if (count($channels))
7016 {
7017
7018 foreach ($channels as $channel)
7019 {
7020 $username = $room = sanitize_file_name(get_the_title($channel->ID));
7021 $rtmp_server = VWliveStreaming::rtmp_address($current_user->ID, $channel->ID, true, $room, $room);
7022 break;
7023 }
7024
7025 $canKick = 1;
7026 VWliveStreaming::webSessionSave($username, $canKick);
7027 VWliveStreaming::sessionUpdate($username, $room, 1, 2, 1);
7028 }
7029 else
7030 {
7031 $msg .= urlencode("You don't have a channel to broadcast.");
7032 $loggedin = 0;
7033 }
7034
7035
7036 }
7037
7038
7039
7040 ?>firstParameter=fix&server=<?php echo urlencode($rtmp_server); ?>&serverAMF=<?php echo $rtmp_amf?>&tokenKey=<?php echo $tokenKey?>&room=<?php echo $room?>&welcome=Welcome!&username=<?php echo $username?>&userlabel=<?php echo $userlabel?>&overLogo=<?php echo urlencode($options['overLogo'])?>&overLink=<?php echo urlencode($options['overLink'])?>&camWidth=<?php echo $camRes[0];?>&camHeight=<?php echo $camRes[1];?>&camFPS=<?php echo
7041 $options['camFPSMobile']?>&camBandwidth=<?php echo $options['camBandwidthMobile']?>&videoCodec=<?php echo $options['videoCodecMobile']?>&codecProfile=<?php echo $options['codecProfileMobile']?>&codecLevel=<?php echo
7042 $options['codecLevelMobile']?>&soundCodec=<?php echo $options['soundCodecMobile']?>&soundQuality=<?php echo $options['soundQualityMobile']?>&micRate=<?php echo
7043 $options['micRateMobile']?>&userType=3&msg=<?php echo $msg?>&loggedin=<?php echo $loggedin?>&loadstatus=1&debug=<?php echo $debug?><?php
7044 break;
7045
7046
7047 //! vw_extchat
7048 case 'vw_extchat':
7049 $options = get_option('VWliveStreamingOptions');
7050
7051 $updated = $_POST['t'];
7052 $room = $_POST['r'];
7053
7054 //do not allow uploads to other folders
7055 sanV($room);
7056 sanV($updated);
7057
7058 if (!$room) exit;
7059
7060 if ($room!="null")
7061 {
7062 $dir=$options['uploadsPath'];
7063 if (!file_exists($dir)) @mkdir($dir);
7064 @chmod($dir, 0755);
7065 $dir .= "/".$room;
7066 if (!file_exists($dir)) @mkdir($dir);
7067 @chmod($dir, 0755);
7068 $dir .= "/external";
7069 if (!file_exists($dir)) @mkdir($dir);
7070 @chmod($dir, 0755);
7071
7072 $day=date("y-M-j",time());
7073 $fname="$dir/$day.html";
7074
7075
7076 $chatText="";
7077
7078 if (file_exists($fname))
7079 {
7080 $chatData = implode('', file($fname));
7081
7082 $chatLines=explode(";;\r\n",$chatData);
7083
7084 foreach ($chatLines as $line)
7085 {
7086 $items = explode("\",\"", $line);
7087 if (trim($items[0], " \"") > $updated) $chatText .= trim($items[1], " \"");
7088 }
7089
7090 }
7091 $ztime = time();
7092 }
7093 ?>chatText=<?php echo urlencode($chatText)?>&updateTime=<?php echo $ztime?><?php
7094 break;
7095
7096 case 'vv_login':
7097
7098 //! vv_login - live_video.swf
7099 //live_video.swf - plain video interface login
7100
7101 $options = get_option('VWliveStreamingOptions');
7102 $rtmp_server = $options['rtmp_server'];
7103 $rtmp_amf = $options['rtmp_amf'];
7104 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
7105 $canWatch = $options['canWatch'];
7106 $watchList = $options['watchList'];
7107
7108 $tokenKey = $options['tokenKey'];
7109 $serverRTMFP = $options['serverRTMFP'];
7110 $p2pGroup = $options['p2pGroup'];
7111 $supportRTMP = $options['supportRTMP'];
7112 $supportP2P = $options['supportP2P'];
7113 $alwaysRTMP = $options['alwaysRTMP'];
7114 $alwaysP2P = $options['alwaysP2P'];
7115 $disableBandwidthDetection = $options['disableBandwidthDetection'];
7116
7117 $current_user = wp_get_current_user();
7118
7119 $loggedin=0;
7120 $msg="";
7121 $visitor=0;
7122
7123 //username
7124 if ($current_user->$userName) $username=urlencode($current_user->$userName);
7125 $username=preg_replace("/[^0-9a-zA-Z]/","-",$username);
7126
7127 //access keys
7128 if ($current_user)
7129 {
7130 $userkeys = $current_user->roles;
7131 $userkeys[] = $current_user->user_login;
7132 $userkeys[] = $current_user->ID;
7133 $userkeys[] = $current_user->user_email;
7134 }
7135
7136 $roomName=$_GET['room_name'];
7137 sanV($roomName);
7138 if ($username==$roomName) $username.="_".rand(10,99);//allow viewing own room - session names must be different
7139
7140 //check room
7141 global $wpdb;
7142 $table_name3 = $wpdb->prefix . "vw_lsrooms";
7143 $wpdb->flush();
7144
7145 $sql = "SELECT * FROM $table_name3 where name='$roomName'";
7146 $channel = $wpdb->get_row($sql);
7147 // $wpdb->query($sql);
7148
7149 if (!$channel)
7150 {
7151 $msg = urlencode("Channel $roomName not found. Owner must broadcast first first!");
7152 }
7153 else
7154 {
7155
7156 if ($channel->type>=2) //premium
7157 {
7158
7159 $poptions = VWliveStreaming::channelOptions($channel->type, $options);
7160
7161 $canWatch = $poptions['canWatchPremium'];
7162 $watchList = $poptions['watchListPremium'];
7163 $msgp = urlencode(" This is a premium channel.");
7164 }
7165
7166 switch ($canWatch)
7167 {
7168 case "all":
7169 $loggedin=1;
7170 if (!$username)
7171 {
7172 $username="VW".base_convert((time()-1224350000).rand(0,10),10,36);
7173 $visitor=1; //ask for username
7174 }
7175 break;
7176 case "members":
7177 if ($username) $loggedin=1;
7178 else $msg=urlencode("<a href=\"/\">Please login first or register an account if you don't have one! Click here to return to website.</a>") . $msgp;
7179 break;
7180 case "list";
7181 if ($username)
7182 if (VWliveStreaming::inList($userkeys, $watchList)) $loggedin=1;
7183 else $msg=urlencode("<a href=\"/\">$username, you are not in the allowed watchers list.</a>") . $msgp;
7184 else $msg=urlencode("<a href=\"/\">Please login first or register an account if you don't have one! Click here to return to website.</a>") . $msgp;
7185 break;
7186 }
7187
7188 //channel post
7189
7190 if ($loggedin) $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $roomName . "' and post_type='channel' LIMIT 0,1" );
7191
7192 if ($postID)
7193 {
7194 $accessList = get_post_meta($postID, 'vw_accessList', true);
7195 if ($accessList) if (!VWliveStreaming::inList($userkeys, $accessList))
7196 {
7197 $loggedin = 0;
7198 $msg .= urlencode("<a href=\"/\">You are not in channel access list.</a>");
7199 }
7200
7201 $vw_logo = get_post_meta( $postID, 'vw_logo', true );
7202 if (!$vw_logo) $vw_logo = 'global';
7203
7204 switch ($vw_logo)
7205 {
7206 case 'global':
7207 $overLogo = $options['overLogo'];
7208 $overLink = $options['overLink'];
7209 break;
7210
7211 case 'hide':
7212 $overLogo = '';
7213 $overLink = '';
7214 break;
7215
7216 case 'custom':
7217 $overLogo = get_post_meta( $postID, 'vw_logoImage', true );
7218 $overLink = get_post_meta( $postID, 'vw_logoLink', true );
7219 break;
7220 }
7221 }
7222 else
7223 {
7224 $overLogo = $options['overLogo'];
7225 $overLink = $options['overLink'];
7226 }
7227
7228
7229
7230 }
7231
7232
7233
7234 $s = $username;
7235 $u = $username;
7236 $r = $roomName;
7237 $m = '';
7238 if ($loggedin) VWliveStreaming::sessionUpdate($u, $r, 0, 1, 1);
7239
7240 $userType=0;
7241 if ($loggedin) VWliveStreaming::webSessionSave($username, 0); //approve session for rtmp check
7242
7243 $parameters = html_entity_decode($options['parameters']);
7244
7245 ?>firstParameter=fix&server=<?php echo $rtmp_server?>&serverAMF=<?php echo $rtmp_amf?>&tokenKey=<?php echo $tokenKey?>&serverRTMFP=<?php echo urlencode($serverRTMFP)?>&p2pGroup=<?php echo
7246 $p2pGroup?>&supportRTMP=<?php echo $supportRTMP?>&supportP2P=<?php echo $supportP2P?>&alwaysRTMP=<?php echo $alwaysRTMP?>&alwaysP2P=<?php echo $alwaysP2P?>&disableBandwidthDetection=<?php echo
7247 $disableBandwidthDetection?>&username=<?php echo $username?>&userType=<?php echo $userType?>&msg=<?php echo $msg?>&loggedin=<?php echo
7248 $loggedin?>&visitor=<?php echo $visitor?>&overLogo=<?php echo urlencode($overLogo)?>&overLink=<?php echo
7249 urlencode($overLink); echo $parameters; ?>&loadstatus=1&debug=<?php echo $debug; ?><?php
7250 break;
7251
7252 case 'css':
7253 $options = get_option('VWliveStreamingOptions');
7254 echo html_entity_decode(stripslashes($options['cssCode']));
7255 break;
7256
7257 case 'vs_login':
7258 //! vs_login - live_watch.swf
7259
7260 //vs_login.php controls watch interface (video & chat & user list) login
7261
7262 $options = get_option('VWliveStreamingOptions');
7263 $rtmp_server = $options['rtmp_server'];
7264 $rtmp_amf = $options['rtmp_amf'];
7265 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
7266 $canWatch = $options['canWatch'];
7267 $watchList = $options['watchList'];
7268
7269 $tokenKey = $options['tokenKey'];
7270 $serverRTMFP = $options['serverRTMFP'];
7271 $p2pGroup = $options['p2pGroup'];
7272 $supportRTMP = $options['supportRTMP'];
7273 $supportP2P = $options['supportP2P'];
7274 $alwaysRTMP = $options['alwaysRTMP'];
7275 $alwaysP2P = $options['alwaysP2P'];
7276 $disableBandwidthDetection = $options['disableBandwidthDetection'];
7277
7278 $sendTip = $options['tips'];
7279
7280
7281 $current_user = wp_get_current_user();
7282
7283 $loggedin=0;
7284 $msg="";
7285 $visitor=0;
7286
7287 //username
7288 if ($current_user->$userName) $username=urlencode($current_user->$userName);
7289 $username=preg_replace("/[^0-9a-zA-Z]/","-",$username);
7290
7291 //access keys
7292 if ($current_user)
7293 {
7294 $userkeys = $current_user->roles;
7295 $userkeys[] = $current_user->user_login;
7296 $userkeys[] = $current_user->ID;
7297 $userkeys[] = $current_user->user_email;
7298 $userkeys[] = $current_user->display_name;
7299 }
7300
7301 $roomName=$_GET['room_name'];
7302 sanV($roomName);
7303
7304 if ($username==$roomName) $username.="_".rand(10,99);//allow viewing own room - session names must be different
7305
7306 $ztime=time();
7307
7308 //check room
7309 global $wpdb;
7310 $table_name3 = $wpdb->prefix . "vw_lsrooms";
7311 $wpdb->flush();
7312
7313 $sql = "SELECT * FROM $table_name3 where name='$roomName'";
7314 $channel = $wpdb->get_row($sql);
7315 $wpdb->query($sql);
7316
7317 if (!$channel)
7318 {
7319 $msg = urlencode("Channel $roomName not found!");
7320 }
7321 else
7322 {
7323
7324 if ($channel->type>=2) //premium
7325 {
7326 $poptions = VWliveStreaming::channelOptions($channel->type, $options);
7327
7328 $canWatch = $poptions['canWatchPremium'];
7329 $watchList = $poptions['watchListPremium'];
7330 $msgp = urlencode(" This is a premium channel.");
7331 }
7332
7333
7334 switch ($canWatch)
7335 {
7336 case "all":
7337 $loggedin=1;
7338 if (!$username)
7339 {
7340 $username="VW".base_convert((time()-1224350000).rand(0,10),10,36);
7341 $visitor=1; //ask for username
7342 $sendTip=0;
7343 }
7344 break;
7345 case "members":
7346 if ($username) $loggedin=1;
7347 else $msg=urlencode("<a href=\"/\">Please login first or register an account if you don't have one! Click here to return to website.</a>") . $msgp;
7348 break;
7349 case "list";
7350 if ($username)
7351 if (VWliveStreaming::inList($userkeys, $watchList)) $loggedin=1;
7352 else $msg=urlencode("<a href=\"/\">$username, you are not in the allowed watchers list.</a>") . $msgp;
7353 else $msg=urlencode("<a href=\"/\">Please login first or register an account if you don't have one! Click here to return to website.</a>") . $msgp;
7354 break;
7355 }
7356
7357 //channel features
7358
7359 $disableChat = 0;
7360 $disableUsers = 0;
7361 $writeText = 1;
7362 $privateTextchat = 1;
7363
7364
7365 if ($loggedin) $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $roomName . "' and post_type='channel' LIMIT 0,1" );
7366
7367 if ($postID)
7368 {
7369 $accessList = get_post_meta($postID, 'vw_accessList', true);
7370 if ($accessList) if (!VWliveStreaming::inList($userkeys, $accessList))
7371 {
7372 $loggedin = 0;
7373 $msg .= urlencode("<a href=\"/\">You are not in channel access list.</a>");
7374 }
7375
7376 //reload playlist if updated
7377 $reloadPlaylist = 0;
7378
7379 if ($loggedin)
7380 {
7381 $playlistActive = get_post_meta( $postID, 'vw_playlistActive', true );
7382 $playlistLoaded = get_post_meta( $postID, 'vw_playlistLoaded', true );
7383
7384 //activated or loaded and inactive
7385 if ($playlistActive || $playlistLoaded)
7386 {
7387 $streamsPath = VWliveStreaming::fixPath($options['streamsPath']);
7388 $smilPath = $streamsPath . 'playlist.smil';
7389
7390 if (filemtime($smilPath) > $playlistLoaded)
7391 if (VWliveStreaming::timeTo($roomName . '/playlistReload', 5, $options))
7392 {
7393 $reloadPlaylist = 1;
7394 update_post_meta( $postID, 'vw_playlistLoaded', time() );
7395
7396 }
7397 }
7398 }
7399
7400 //other permissions
7401 foreach (array('chat','write','participants','privateChat') as $field)
7402 {
7403 $value = get_post_meta($postID, 'vw_'.$field.'List', true);
7404 if ($value) if (!VWliveStreaming::inList($userkeys, $value))
7405 switch ($field)
7406 {
7407 case 'chat':
7408 $disableChat = 1;
7409 break;
7410
7411 case 'write':
7412 $writeText = 0;
7413 break;
7414
7415 case 'participants':
7416 $disableUsers = 1;
7417 break;
7418
7419 case 'privateChat':
7420 $privateTextchat = 0;
7421 break;
7422 }
7423 }
7424
7425
7426 $vw_logo = get_post_meta( $postID, 'vw_logo', true );
7427 if (!$vw_logo) $vw_logo = 'global';
7428
7429 switch ($vw_logo)
7430 {
7431 case 'global':
7432 $overLogo = $options['overLogo'];
7433 $overLink = $options['overLink'];
7434 break;
7435
7436 case 'hide':
7437 $overLogo = '';
7438 $overLink = '';
7439 break;
7440
7441 case 'custom':
7442 $overLogo = get_post_meta( $postID, 'vw_logoImage', true );
7443 $overLink = get_post_meta( $postID, 'vw_logoLink', true );
7444 break;
7445 }
7446
7447 $vw_ads = get_post_meta( $postID, 'vw_ads', true );
7448 if (!$vw_ads) $vw_ads = 'global';
7449
7450 switch ($vw_ads)
7451 {
7452 case 'global':
7453 $adsServer =$options['adServer'];
7454 break;
7455
7456 case 'hide':
7457 $adsServer = '';
7458
7459 break;
7460
7461 case 'custom':
7462 $adsServer = get_post_meta( $postID, 'vw_adsServer', true );
7463 break;
7464 }
7465
7466 }
7467 else
7468 {
7469 $overLogo = $options['overLogo'];
7470 $overLink = $options['overLink'];
7471 $adsServer =$options['adServer'];
7472 }
7473
7474
7475 }
7476
7477 if ($loggedin)
7478 {
7479 //user picture and profile link
7480 if ($current_user->ID > 0)
7481 {
7482 if ($options['userPicture'] == 'avatar') $userPicture = urlencode(get_avatar_url($current_user->ID, array('size' => 150) ));
7483 if ($options['profilePrefix']) $userLink = urlencode($options['profilePrefix'] . $username);
7484 }
7485
7486 }
7487
7488 $s = $username;
7489 $u = $username;
7490 $m = '';
7491 $r = $roomName;
7492 if ($loggedin) VWliveStreaming::sessionUpdate($u, $r, 0, 1, 1);
7493
7494
7495 $userType=0;
7496 $canKick = 0;
7497 if ($loggedin) VWliveStreaming::webSessionSave($username, 0); //approve session for rtmp check
7498
7499 //replace bad words or expressions
7500 $filterRegex=urlencode("(?i)(fuck|cunt)(?-i)");
7501 $filterReplace=urlencode(" ** ");
7502
7503 if (!$welcome) $welcome="Welcome on <B>".$roomName."</B> live streaming channel!";
7504
7505 $parameters = html_entity_decode($options['parameters']);
7506 $layoutCode = html_entity_decode($options['layoutCode']);
7507
7508 //user notifications
7509 if ($current_user) if ($current_user->ID)
7510 {
7511
7512 $watchRoleParameters = VWliveStreaming::userParameters($current_user, $options['watchRoleParameters']);
7513 $parametersCode = VWliveStreaming::editParameters($parametersCode, $watchRoleParameters);
7514
7515 if ($sendTip)
7516 {
7517 $balance = VWliveStreaming::balance($current_user->ID);
7518
7519 if ($balance>0) $welcome.= '<BR>* You can send tips. Your starting balance is: ' . $balance;
7520 else
7521 {
7522 $welcome.= '<BR>* You can not send tips because you do not have any credits.';
7523 $sendTip = 0;
7524 }
7525 }
7526
7527 if ($options['userWatchLimit'])
7528 {
7529 $userWatchTime = get_user_meta( $current_user->ID, 'vwls_watch', true );
7530 if ($userWatchTime) $welcome.= '<BR>* You watched ' . number_format($userWatchTime/60,2) . ' minutes since ' . date("F j, Y, g:i a", get_user_meta( $current_user->ID, 'vwls_watch_update', true )) .'.';
7531
7532 }
7533 }
7534
7535 $parametersCode ='&disableChat=' . $disableChat . '&disableUsers=' . $disableUsers . '&writeText=<' . $writeText . '&privateTextchat=' . $privateTextchat . '&overLogo=' . urlencode($overLogo) . '&overLink=' . urlencode($overLink) . '&layoutCode=' . urlencode($layoutCode) . '&filterRegex=' . $filterRegex . '&filterReplace=' .$filterReplace . '&ws_ads=' . urlencode($adsServer) . '&sendTip=' . $sendTip . '&reloadPlaylist=' . $reloadPlaylist . '&loaderImage=' . urlencode($options['loaderImage']) . '&adsInterval=' . $options['adsInterval']. $parameters;
7536
7537 if ($current_user) if ($current_user->ID)
7538 {
7539
7540 $watchRoleParameters = VWliveStreaming::userParameters($current_user, $options['watchRoleParameters']);
7541 $parametersCode = VWliveStreaming::editParameters($parametersCode, $watchRoleParameters);
7542 }
7543
7544 ?>firstParameter=fix&server=<?php echo $rtmp_server?>&serverAMF=<?php echo $rtmp_amf?>&tokenKey=<?php echo $tokenKey?>&serverRTMFP=<?php echo urlencode($serverRTMFP)?>&p2pGroup=<?php echo
7545 $p2pGroup?>&supportRTMP=<?php echo $supportRTMP?>&supportP2P=<?php echo $supportP2P?>&alwaysRTMP=<?php echo $alwaysRTMP?>&alwaysP2P=<?php echo $alwaysP2P?>&disableBandwidthDetection=<?php echo
7546 $disableBandwidthDetection?>&welcome=<?php echo urlencode($welcome)?>&username=<?php echo $username?>&userType=<?php echo $userType?>&userPicture=<?php echo $userPicture?>&userLink=<?php echo $userLink?>&msg=<?php echo $msg?>&loggedin=<?php
7547 echo $loggedin?>&visitor=<?php echo $visitor; echo $parametersCode; ?>&loadstatus=1<?php
7548 break;
7549
7550
7551 case 'tips':
7552 $options = get_option('VWliveStreamingOptions');
7553
7554 echo html_entity_decode(stripslashes($options['tipOptions']));
7555 break;
7556
7557 case 'tip':
7558 $room_name = sanitize_file_name($_POST['r']);
7559 $caller = sanitize_file_name($_POST['s']);
7560 $target = sanitize_file_name($_POST['t']);
7561
7562 $username = sanitize_file_name($_POST['u']);
7563 $private = sanitize_file_name($_POST['p']);
7564 $amount = floatval($_POST['a']);
7565 $label = sanitize_text_field($_POST['l']);
7566 $message = sanitize_text_field($_POST['m']);
7567
7568 $sound = sanitize_file_name($_POST['snd']);
7569
7570 $options = get_option('VWliveStreamingOptions');
7571
7572 $postID = $wpdb->get_var( $sql = 'SELECT ID FROM ' . $wpdb->posts . ' WHERE post_name = \'' . $room_name . '\' and post_type=\'channel\' LIMIT 0,1' );
7573
7574 if (!$postID) VWliveStreaming::rexit('success=0&failed=RoomNotFound-' . urlencode($room_name));
7575 $post = get_post( $postID );
7576
7577 $current_user = wp_get_current_user();
7578
7579
7580 $balance = VWliveStreaming::balance($current_user->ID);
7581 if ($amount > $balance) VWliveStreaming::rexit('success=0&failed=NotEnoughFunds-' . $balance);
7582
7583 $ztime = time();
7584
7585 //client cost
7586 $paid = number_format($amount, 2, '.', '');
7587 VWliveStreaming::transaction('ppv_tip', $current_user->ID, - $paid, 'Tip for <a href="' . VWliveStreaming::roomURL($room_name) . '">' . $room_name.'</a>. (' .$label.')' , $ztime);
7588
7589 //performer earning
7590 $received = number_format($amount * $options['tipRatio'], 2, '.', '');
7591 VWliveStreaming::transaction('ppv_tip_earning', $post->post_author, $received , 'Tip from ' . $caller .' ('.$label.')', $ztime);
7592
7593 //update balance and report
7594 $balance = VWliveStreaming::balance($current_user->ID);
7595
7596 $ownMessage = 'After tip, your balance is: ' . $balance;
7597
7598 if ($sound) $soundCode = "sound://$sound;;";
7599 $publicMessage = $soundCode. '<B>Tip from ' . $username . '</B>: ' . $label . " ($paid)";
7600
7601 $privateMessage = '<B>' . $username . ' (Tip '.$paid.')</B>: ' . $message;
7602
7603 echo 'success=1&amount=' . $paid . '&balance=' . $balance. '&sound=' .urlencode($sound) . '&privateMessage=' .urlencode($privateMessage). '&publicMessage=' .urlencode($publicMessage) . '&ownMessage=' .urlencode($ownMessage);
7604
7605 break;
7606
7607 case 'vc_login':
7608 //! vc_login - live_broadcast.swf
7609 $options = get_option('VWliveStreamingOptions');
7610
7611 $rtmp_server = $options['rtmp_server'];
7612 $rtmp_amf = $options['rtmp_amf'];
7613 $userName = $options['userName']; if (!$userName) $userName='user_nicename';
7614 $canBroadcast = $options['canBroadcast'];
7615 $broadcastList = $options['broadcastList'];
7616
7617 $tokenKey = $options['tokenKey'];
7618 $webKey = $options['webKey'];
7619
7620 $serverRTMFP = $options['serverRTMFP'];
7621 $p2pGroup = $options['p2pGroup'];
7622 $supportRTMP = $options['supportRTMP'];
7623 $supportP2P = $options['supportP2P'];
7624 $alwaysRTMP = $options['alwaysRTMP'];
7625 $alwaysP2P = $options['alwaysP2P'];
7626 $disableBandwidthDetection = $options['disableBandwidthDetection'];
7627
7628 $camRes = explode('x',$options['camResolution']);
7629
7630 $current_user = wp_get_current_user();
7631
7632 $loggedin=0;
7633 $msg="";
7634
7635 //username
7636 if ($current_user->$userName) $username=urlencode($current_user->$userName);
7637 sanV($username);
7638
7639
7640 //broadcaster room
7641 $userlabel="";
7642 $room_name=$_GET['room_name'];
7643 sanV($room_name);
7644
7645 if ($room_name&&$room_name!=$username)
7646 {
7647 $userlabel=$username;
7648 $username=$room_name;
7649 $room=$room_name;
7650 }
7651
7652 if (!$room) $room = $username;
7653
7654 //access keys
7655 if ($current_user)
7656 {
7657 $userkeys = $current_user->roles;
7658 $userkeys[] = $current_user->user_login;
7659 $userkeys[] = $current_user->ID;
7660 $userkeys[] = $current_user->user_email;
7661 $userkeys[] = $current_user->display_name;
7662 }
7663
7664 switch ($canBroadcast)
7665 {
7666 case "members":
7667 if ($username) $loggedin=1;
7668 else $msg=urlencode("<a href=\"/\">Please login first or register an account if you don't have one! Click here to return to website.</a>");
7669 break;
7670 case "list";
7671 if ($username)
7672 if (VWliveStreaming::inList($userkeys, $broadcastList)) $loggedin=1;
7673 else $msg=urlencode("<a href=\"/\">$username, you are not in the broadcasters list.</a>");
7674 else $msg=urlencode("<a href=\"/\">Please login first or register an account if you don't have one! Click here to return to website.</a>");
7675 break;
7676 }
7677
7678 //channel features
7679 if ($loggedin) $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $room . "' and post_type='channel' LIMIT 0,1" );
7680
7681 if ($postID)
7682 {
7683 $vw_logo = get_post_meta( $postID, 'vw_logo', true );
7684 if (!$vw_logo) $vw_logo = 'global';
7685
7686 switch ($vw_logo)
7687 {
7688 case 'global':
7689 $overLogo = $options['overLogo'];
7690 $overLink = $options['overLink'];
7691 break;
7692
7693 case 'hide':
7694 $overLogo = '';
7695 $overLink = '';
7696 break;
7697
7698 case 'custom':
7699 $overLogo = get_post_meta( $postID, 'vw_logoImage', true );
7700 $overLink = get_post_meta( $postID, 'vw_logoLink', true );
7701 break;
7702 }
7703 }
7704 else
7705 {
7706 $overLogo = $options['overLogo'];
7707 $overLink = $options['overLink'];
7708 }
7709
7710
7711 $debug = "$postID-$vw_logo";
7712
7713 if (!$room)
7714 {
7715 $loggedin=0;
7716 $msg=urlencode("<a href=\"/\">Can't enter: Room missing!</a>");
7717 }
7718
7719 if (!$username)
7720 {
7721 $loggedin=0;
7722 $msg=urlencode("<a href=\"/\">Can't enter: Username missing!</a>");
7723 }
7724
7725
7726 //channel name
7727 if ($loggedin)
7728 {
7729 global $wpdb;
7730 $table_name3 = $wpdb->prefix . "vw_lsrooms";
7731
7732 $wpdb->flush();
7733 $ztime=time();
7734
7735 //setup/update channel, premium & time reset
7736
7737 $poptions = VWliveStreaming::premiumOptions($userkeys, $options);
7738
7739 if ($poptions) //premium room
7740 {
7741 $rtype = 1 + $poptions['level'];
7742 $camBandwidth = $poptions['pCamBandwidth'];
7743 $camMaxBandwidth = $poptions['pCamMaxBandwidth'];
7744 //if (!$options['pLogo']) $options['overLogo']=$options['overLink']='';
7745 }else
7746 {
7747 $rtype=1;
7748 $camBandwidth=$options['camBandwidth'];
7749 $camMaxBandwidth=$options['camMaxBandwidth'];
7750 }
7751
7752 $sql = "SELECT * FROM $table_name3 where owner='$username' and name='$room'";
7753 $channel = $wpdb->get_row($sql);
7754
7755 if (!$channel)
7756 $sql="INSERT INTO `$table_name3` ( `owner`, `name`, `sdate`, `edate`, `rdate`,`status`, `type`) VALUES ('$username', '$room', $ztime, $ztime, $ztime, 0, $rtype)";
7757 elseif ($options['timeReset'] && $channel->rdate < $ztime - $options['timeReset']*24*3600) //time to reset in days
7758 $sql="UPDATE `$table_name3` set edate=$ztime, type=$rtype, rdate=$ztime, wtime=0, btime=0 where owner='$username' and name='$room'";
7759 else
7760 $sql="UPDATE `$table_name3` set edate=$ztime, type=$rtype where owner='$username' and name='$room'";
7761
7762 $wpdb->query($sql);
7763 }
7764
7765
7766 if ($loggedin) VWliveStreaming::sessionUpdate($username, $room, 1, 1, 1);
7767
7768 if ($loggedin) VWliveStreaming::webSessionSave($username, 1); //approve session for rtmp check
7769
7770
7771 $uploadsPath = $options['uploadsPath'];
7772 if (!$uploadsPath) { $upload_dir = wp_upload_dir(); $uploadsPath = $upload_dir['basedir'] . '/vwls'; }
7773
7774 $day = date("y-M-j",time());
7775 $chatlog_url = VWliveStreaming::path2url($uploadsPath."/$room/Log$day.html");
7776
7777 $swfurlp = "&prefix=" . urlencode(admin_url() . 'admin-ajax.php?action=vwls&task=');
7778 $swfurlp .= '&extension='.urlencode('_none_');
7779 $swfurlp .= '&ws_res=' . urlencode( plugin_dir_url(__FILE__) . 'ls/');
7780
7781 $linkcode= VWliveStreaming::roomURL($username);
7782
7783 $imagecode=VWliveStreaming::path2url($uploadsPath."/_snapshots/".urlencode($username).".jpg");
7784
7785 $base = plugin_dir_url(__FILE__) . "ls/";
7786 $swfurl= plugin_dir_url(__FILE__) . "ls/live_watch.swf?ssl=1&n=".urlencode($username) . $swfurlp;
7787 $swfurl2=plugin_dir_url(__FILE__) . "ls/live_video.swf?ssl=1&n=".urlencode($username) . $swfurlp;
7788
7789 $embedcode = VWliveStreaming::html_watch($username);
7790 $embedvcode = VWliveStreaming::html_video($username);
7791
7792
7793 if ($options['externalKeys']) $rtmp_server = VWliveStreaming::rtmp_address($current_user->ID, $postID, true, $stream, $stream);
7794
7795
7796 $chatlog="The transcript log of this chat is available at <U><A HREF=\"$chatlog_url\" TARGET=\"_blank\">$chatlog_url</A></U>.";
7797 if (!$welcome) $welcome="Welcome to broadcasting interface for channel '$room'! . $chatlog";
7798
7799 $parameters = html_entity_decode($options['parametersBroadcaster']);
7800
7801 if ($options['manualArchiving'])
7802 {
7803 $manualArchivingStart = $options['manualArchiving'] . '&action=startRecording&streamname=' . urlencode($username);
7804 $manualArchivingStop = $options['manualArchiving'] . '&action=stopRecording&streamname=' . urlencode($username);
7805 }
7806 if ($current_user->ID > 0)
7807 {
7808 $userPicture = urlencode(get_the_post_thumbnail_url($postID));
7809 if ($options['profilePrefixChannel']) $userLink = urlencode($options['profilePrefixChannel'] . $username);
7810 else $userLink = $linkcode;
7811 }
7812
7813 //warn if HTTPS missing
7814 if(empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "off")
7815 $welcome.= '<br><B>Warning: HTTPS not detected. Some browsers like Chrome will not permit webcam access when accessing without SSL!</B>';
7816
7817
7818 ?>firstParameter=fix&server=<?php echo urlencode($rtmp_server)?>&serverAMF=<?php echo $rtmp_amf?>&tokenKey=<?php echo $tokenKey?>&serverRTMFP=<?php echo urlencode($serverRTMFP)?>&p2pGroup=<?php
7819 echo $p2pGroup?>&supportRTMP=<?php echo $supportRTMP?>&supportP2P=<?php echo $supportP2P?>&alwaysRTMP=<?php echo $alwaysRTMP?>&alwaysP2P=<?php echo $alwaysP2P?>&disableBandwidthDetection=<?php echo
7820 $disableBandwidthDetection?>&room=<?php echo $username?>&welcome=<?php echo urlencode($welcome); ?>&username=<?php echo $username?>&userlabel=<?php echo $userlabel?>&userPicture=<?php echo $userPicture?>&userLink=<?php echo $userLink?>&overLogo=<?php echo
7821 urlencode($overLogo)?>&overLink=<?php echo urlencode($overLink)?>&userType=3&webserver=&msg=<?php echo $msg?>&loggedin=<?php echo $loggedin?>&linkcode=<?php echo
7822 urlencode($linkcode)?>&embedcode=<?php echo urlencode($embedcode)?>&embedvcode=<?php echo urlencode($embedvcode)?>&imagecode=<?php echo
7823 urlencode($imagecode)?>&camWidth=<?php echo $camRes[0];?>&camHeight=<?php echo $camRes[1];?>&camFPS=<?php echo
7824 $options['camFPS']?>&camBandwidth=<?php echo $camBandwidth?>&videoCodec=<?php echo $options['videoCodec']?>&codecProfile=<?php echo $options['codecProfile']?>&codecLevel=<?php echo
7825 $options['codecLevel']?>&soundCodec=<?php echo $options['soundCodec']?>&soundQuality=<?php echo $options['soundQuality']?>&micRate=<?php echo
7826 $options['micRate']?>&camMaxBandwidth=<?php echo
7827 $camMaxBandwidth?>&manualArchivingStart=<?php echo urlencode($manualArchivingStart)?>&manualArchivingStop=<?php echo urlencode($manualArchivingStop)?>&onlyVideo=<?php echo $options['onlyVideo']?>&loaderImage=<?php echo urlencode($options['loaderImage'])?>&noEmbeds=<?php echo $options['noEmbeds']; echo $parameters; ?>&loadstatus=1&debug=<?php echo $debug; ?><?php
7828 break;
7829
7830 //! vc_chatlog
7831 case 'vc_chatlog':
7832
7833 //Public and private chat logs
7834 $private=$_POST['private']; //private chat username, blank if public chat
7835 $username=$_POST['u'];
7836 $session=$_POST['s'];
7837 $room=$_POST['r'];
7838 $message=$_POST['msg'];
7839 $time=$_POST['msgtime'];
7840
7841 //do not allow uploads to other folders
7842 sanV($room);
7843 sanV($private);
7844 sanV($session);
7845 if (!$room) exit;
7846
7847 $message = strip_tags($message,'<p><a><img><font><b><i><u>');
7848
7849 //generate same private room folder for both users
7850 if ($private)
7851 {
7852 if ($private>$session) $proom=$session ."_". $private; else $proom=$private ."_". $session;
7853 }
7854
7855 $options = get_option('VWliveStreamingOptions');
7856 $dir=$options['uploadsPath'];
7857 if (!file_exists($dir)) mkdir($dir);
7858 @chmod($dir, 0777);
7859 $dir.="/$room";
7860 if (!file_exists($dir)) mkdir($dir);
7861 @chmod($dir, 0777);
7862 if ($proom) $dir.="/$proom";
7863 if (!file_exists($dir)) mkdir($dir);
7864 @chmod($dir, 0777);
7865
7866 $day=date("y-M-j",time());
7867
7868 $dfile = fopen($dir."/Log$day.html","a");
7869 fputs($dfile,$message."<BR>");
7870 fclose($dfile);
7871 ?>loadstatus=1<?php
7872 break;
7873
7874 case 'v_status':
7875 //watch and video interface
7876
7877 /*
7878POST Variables:
7879u=Username
7880s=Session, usually same as username
7881r=Room
7882ct=session time (in milliseconds)
7883lt=last session time received from this script in (milliseconds)
7884*/
7885
7886 $cam=$_POST['cam'];
7887 $mic=$_POST['mic'];
7888
7889 $timeUsed=$currentTime=$_POST['ct'];
7890 $lastTime=$_POST['lt'];
7891
7892 $s=$_POST['s'];
7893 $u=$_POST['u'];
7894 $r=$_POST['r'];
7895 $m=$_POST['m'];
7896
7897 //sanitize variables
7898 sanV($s);
7899 sanV($u);
7900 sanV($r);
7901 sanV($m,0, 0);
7902
7903 $timeUsed = (int) $timeUsed;
7904 $currentTime = (int) $currentTime;
7905 $lastTime = (int) $lastTime;
7906
7907 //exit if no valid session name or room name
7908 if (!$s) exit;
7909 if (!$r) exit;
7910
7911 global $wpdb;
7912 $table_name = $wpdb->prefix . "vw_lwsessions";
7913 $table_name3 = $wpdb->prefix . "vw_lsrooms";
7914 $wpdb->flush();
7915
7916 $ztime=time();
7917
7918 //room info
7919 $sql = "SELECT * FROM $table_name3 where name='$r'";
7920 $channel = $wpdb->get_row($sql);
7921 $wpdb->query($sql);
7922
7923 if (!$channel) $disconnect = urlencode("Channel $r not found!");
7924 else
7925 {
7926 $ztime=time();
7927
7928 //update viewer online
7929 $sql = "SELECT * FROM $table_name where session='$s' and status='1'";
7930 $session = $wpdb->get_row($sql);
7931 if (!$session)
7932 {
7933 $sql="INSERT INTO `$table_name` ( `session`, `username`, `room`, `message`, `sdate`, `edate`, `status`, `type`) VALUES ('$s', '$u', '$r', '$m', $ztime, $ztime, 1, 1)";
7934 $wpdb->query($sql);
7935 $session = $wpdb->get_row($sql);
7936 }
7937 else
7938 {
7939 $sql="UPDATE `$table_name` set edate=$ztime, room='$r', username='$u', message='$m' where session='$s' and status='1' and `type`='1'";
7940 $wpdb->query($sql);
7941 }
7942
7943 VWliveStreaming::cleanSessions(0);
7944
7945 //room usage
7946 // options in minutes
7947 // mysql in s
7948 // flash in ms (minimise latency errors)
7949
7950 $options = get_option('VWliveStreamingOptions');
7951
7952 if ($channel->type>=2) //premium
7953 {
7954 $poptions = VWliveStreaming::channelOptions($channel->type, $options);
7955
7956 $maximumBroadcastTime = 60 * $poptions['pBroadcastTime'];
7957 $maximumWatchTime = 60 * $poptions['pWatchTime'];
7958 }
7959 else
7960 {
7961 $maximumBroadcastTime = 60 * $options['broadcastTime'];
7962 $maximumWatchTime = 60 * $options['watchTime'];
7963 }
7964
7965 $maximumSessionTime = $maximumWatchTime;
7966
7967
7968 //update time
7969 $expTime = $options['onlineExpiration0']+60;
7970 $dS = floor(($currentTime-$lastTime)/1000);
7971
7972 if ($dS > $expTime || $dS<0) $disconnect = urlencode("Web server out of sync compared to online expiration setting: $dS/$expTime"); //Updates should be faster; fraud attempt?
7973 else
7974 {
7975 $channel->wtime += $dS;
7976 $timeUsed = $channel->wtime * 1000;
7977
7978 if ($maximumBroadcastTime && $maximumBroadcastTime < $channel->btime ) $disconnect = urlencode("Allocated broadcasting time ended!");
7979 if ($maximumWatchTime && $maximumWatchTime < $channel->wtime ) $disconnect = urlencode("Allocated watch time ended!");
7980
7981 $maximumSessionTime *=1000;
7982
7983 //update
7984 $sql="UPDATE `$table_name3` set wtime = " . $channel->wtime . " where name='$r'";
7985 $wpdb->query($sql);
7986
7987 //update post
7988 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $r . "' and post_type='".$options['custom_post']."' LIMIT 0,1" );
7989 if ($postID)
7990 {
7991 update_post_meta($postID, 'wtime', $channel->wtime);
7992 }
7993
7994 //update user watch time, disconnect if exceeded limit
7995 $current_user = wp_get_current_user();
7996 if ($current_user)
7997 if (VWliveStreaming::updateUserWatchtime($current_user, $dS, $options))
7998 $disconnect = urlencode('Your user watch time limit was exceeded!');
7999
8000 }
8001
8002
8003
8004 }
8005
8006 ?>timeTotal=<?php echo $maximumSessionTime?>&timeUsed=<?php echo $timeUsed?>&lastTime=<?php echo $currentTime?>&disconnect=<?php echo $disconnect?>&dS=<?php echo $dS?>&loadstatus=1<?php
8007 break;
8008
8009 //! rtmp_status
8010 case 'rtmp_status':
8011
8012 $options = get_option('VWliveStreamingOptions');
8013
8014 //allow such requests only if feature is enabled (by default is not)
8015 if ($options['webStatus'] != 'enabled') VWliveStreaming::rexit('denied=webStatusNotEnabled-' . $options['webStatus']);
8016
8017 //allow only status updates from configured server IP
8018 if ($options['rtmp_restrict_ip'])
8019 {
8020 if (VWliveStreaming::get_ip_address() != trim($options['rtmp_restrict_ip'])) VWliveStreaming::rexit('denied=NotFromAllowedIP');
8021 } else VWliveStreaming::rexit('denied=StatusServerIPnotConfigured');
8022
8023 $userdata = stripslashes($_POST['users']);
8024
8025 if (version_compare(phpversion(), '7.0', '<'))
8026 $users = unserialize($userdata); //request is from trusted server
8027 else $users = unserialize($userdata, false);
8028
8029
8030 global $wpdb;
8031 $table_name3 = $wpdb->prefix . "vw_lsrooms";
8032 $wpdb->flush();
8033
8034 $ztime=time();
8035
8036 $controlUsers = array();
8037
8038 if (is_array($users))
8039 foreach ($users as $user)
8040 {
8041 //$rooms = explode(',',$user['rooms']); $r = $rooms[0];
8042 $r = $user['rooms'];
8043 $s = $user['session'];
8044 $u = $user['username'];
8045
8046 $ztime=time();
8047 $disconnect = "";
8048
8049 if ($ban = VWliveStreaming::containsAny($s, $options['bannedNames'])) $disconnect = "Name banned ($s,$ban)!";
8050
8051
8052 if ($user['role'] == '1') //channel broadcaster
8053 {
8054
8055 $table_name = $wpdb->prefix . "vw_sessions";
8056
8057 //user online
8058 $sqlS = "SELECT * FROM $table_name WHERE session='$s' AND status='1' ORDER BY type DESC, edate DESC LIMIT 0,1";
8059 $session = $wpdb->get_row($sqlS);
8060
8061 if (!$session) //insert as external type=2
8062 {
8063 $sql="INSERT INTO `$table_name` ( `session`, `username`, `room`, `message`, `sdate`, `edate`, `status`, `type`) VALUES ('$s', '$u', '$r', '$m', $ztime, $ztime, 1, 2)";
8064 $wpdb->query($sql);
8065 $session = $wpdb->get_row($sqlS);
8066 }
8067
8068
8069 if ($session->type == 2) //external broadcaster: update here
8070 {
8071 //generate external snapshot for external broadcaster
8072 VWliveStreaming::rtmpSnapshot($session);
8073
8074 $sqlC = "SELECT * FROM $table_name3 WHERE name='" . $session->room . "' LIMIT 0,1";
8075 $channel = $wpdb->get_row($sqlC);
8076
8077 //update session
8078 $sql="UPDATE `$table_name` set edate=$ztime where id='".$session->id."'";
8079 $wpdb->query($sql);
8080
8081 if ($ban = VWliveStreaming::containsAny($channel->name,$options['bannedNames'])) $disconnect = "Room banned ($ban)!";
8082
8083 //calculate time in ms based on previous request
8084 $lastTime = $session->edate * 1000;
8085 $currentTime = $ztime * 1000;
8086
8087 //update time
8088 $expTime = $options['onlineExpiration1']+30;
8089 $dS = floor(($currentTime-$lastTime)/1000);
8090 if ($dS > $expTime || $dS<0) $disconnect = "Web server out of sync for broadcaster ($dS > $expTime) !"; //Updates should be faster; fraud attempt?
8091
8092 $channel->btime += $dS;
8093
8094 //update room
8095 $sql="UPDATE `$table_name3` set edate=$ztime, btime = " . $channel->btime . " where id = '" . $channel->id. "'";
8096 $wpdb->query($sql);
8097
8098 //update post
8099 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $r . "' and post_type='channel' LIMIT 0,1" );
8100 if ($postID)
8101 {
8102 update_post_meta($postID, 'edate', $ztime);
8103 update_post_meta($postID, 'btime', $channel->btime);
8104
8105 VWliveStreaming::updateViewers($postID, $r, $options);
8106 }
8107
8108 //transcode stream (if necessary)
8109 if (!$disconnect) if ($options['transcodingAuto']>=2) VWliveStreaming::transcodeStream($session->room);
8110 }
8111
8112 // room usage
8113 // options in minutes
8114 // mysql in s
8115 // flash in ms (minimise latency errors)
8116
8117 if ($channel->type>=2) //premium
8118 {
8119 $poptions = VWliveStreaming::channelOptions($channel->type, $options);
8120
8121 $maximumBroadcastTime = 60 * $poptions['pBroadcastTime'];
8122 $maximumWatchTime = 60 * $poptions['pWatchTime'];
8123 }
8124 else
8125 {
8126 $maximumBroadcastTime = 60 * $options['broadcastTime'];
8127 $maximumWatchTime = 60 * $options['watchTime'];
8128 }
8129
8130 $maximumSessionTime = $maximumBroadcastTime; //broadcaster
8131
8132 $timeUsed = $channel->btime * 1000;
8133
8134 if ($maximumBroadcastTime && $maximumBroadcastTime < $channel->btime ) $disconnect = "Allocated broadcasting time ended!";
8135 if ($maximumWatchTime && $maximumWatchTime < $channel->wtime ) $disconnect = "Allocated watch time ended!";
8136
8137 $maximumSessionTime *=1000;
8138
8139
8140 }
8141 else //subscriber viewer
8142 {
8143 $table_name = $wpdb->prefix . "vw_lwsessions";
8144
8145 //update viewer online
8146 $sqlS = "SELECT * FROM $table_name WHERE session='$s' AND status='1' ORDER BY type DESC, edate DESC LIMIT 0,1";
8147
8148 $session = $wpdb->get_row($sqlS);
8149 if (!$session) //insert external viewer type=2
8150 {
8151 $sql="INSERT INTO `$table_name` ( `session`, `username`, `room`, `message`, `sdate`, `edate`, `status`, `type`) VALUES ('$s', '$u', '$r', '', $ztime, $ztime, 1, 2)";
8152 $wpdb->query($sql);
8153 $session = $wpdb->get_row($sqlS);
8154 };
8155
8156
8157 if ($session->type == '2') //external viewer session: update here
8158 {
8159
8160 $sqlC = "SELECT * FROM $table_name3 WHERE name='" . $session->room . "' LIMIT 0,1";
8161 $channel = $wpdb->get_row($sqlC);
8162
8163
8164 $sql="UPDATE `$table_name` set edate=$ztime where id='".$session->id."'";
8165 $wpdb->query($sql);
8166
8167 //calculate time in ms based on previous request
8168 $lastTime = $session->edate * 1000;
8169 $currentTime = $ztime * 1000;
8170
8171 //update room time
8172 $expTime = $options['onlineExpiration0']+30;
8173
8174 $dS = floor(($currentTime-$lastTime)/1000);
8175 if ($dS > $expTime || $dS<0) $disconnect = "Web server out of sync ($dS > $expTime)!"; //Updates should be faster than 3 minutes; fraud attempt?
8176
8177 $channel->wtime += $dS;
8178
8179 //update
8180 $sql="UPDATE `$table_name3` set wtime = " . $channel->wtime . " where id = '" . $channel->id. "'";
8181 $wpdb->query($sql);
8182
8183 //update post
8184 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $r . "' and post_type='channel' LIMIT 0,1" );
8185 if ($postID)
8186 {
8187 update_post_meta($postID, 'wtime', $channel->wtime);
8188 }
8189
8190 //update user watch time, disconnect if exceeded limit
8191 $user = get_user_by('login', $u);
8192 if ($user)
8193 if (VWliveStreaming::updateUserWatchtime($user, $dS, $options))
8194 $disconnect = urlencode('User watch time limit exceeded!');
8195
8196
8197 }
8198 // room usage
8199 // options in minutes
8200 // mysql in s
8201 // flash in ms (minimise latency errors)
8202
8203 if ($channel->type>=2) //premium
8204 {
8205 $poptions = VWliveStreaming::channelOptions($channel->type, $options);
8206
8207 $maximumBroadcastTime = 60 * $poptions['pBroadcastTime'];
8208 $maximumWatchTime = 60 * $poptions['pWatchTime'];
8209 }
8210 else
8211 {
8212 $maximumBroadcastTime = 60 * $options['broadcastTime'];
8213 $maximumWatchTime = 60 * $options['watchTime'];
8214 }
8215
8216 $maximumSessionTime = $maximumWatchTime;
8217
8218 $timeUsed = $channel->wtime * 1000;
8219
8220 if ($maximumBroadcastTime && $maximumBroadcastTime < $channel->btime ) $disconnect = "Allocated broadcasting time ended!";
8221 if ($maximumWatchTime && $maximumWatchTime < $channel->wtime ) $disconnect = "Allocated watch time ended!";
8222
8223 $maximumSessionTime *=1000;
8224
8225
8226 }
8227
8228 $controlUser['disconnect'] = $disconnect;
8229 $controlUser['dS'] = $dS;
8230 $controlUser['type'] = $session->type;
8231 $controlUser['room'] = $session->room;
8232 $controlUser['username'] = $session->username;
8233
8234 $controlUsers[$user['session']] = $controlUser;
8235
8236 }
8237
8238 $controlUsersS = serialize($controlUsers);
8239
8240 $dir = $options['uploadsPath'];
8241 $filename1 = $dir ."/_sessions/_rtmpStatus.txt";
8242 $dfile = fopen($filename1,"w");
8243 fputs($dfile, $_POST['users'] . "\r\n".count($users)."\r\n");
8244 fputs($dfile, $controlUsersS);
8245 fclose($dfile);
8246
8247 echo "VideoWhisper=1&usersCount=".count($users)."&controlUsers=$controlUsersS";
8248
8249 break;
8250 //! rtmp_logout
8251 case 'rtmp_logout':
8252
8253 //rtmp server notifies client disconnect here
8254 $session = $_GET['s'];
8255 sanV($session);
8256 if (!$session) exit;
8257
8258 $options = get_option('VWliveStreamingOptions');
8259 $dir=$options['uploadsPath'];
8260
8261 echo "logout=";
8262 $filename1 = $dir ."/_sessions/$session";
8263 if (file_exists($filename1))
8264 {
8265 echo unlink($filename1);
8266 }
8267 ?><?php
8268 break;
8269 //! rtmp_login
8270 case 'rtmp_login':
8271
8272
8273 //rtmp server should check login like rtmp_login.php?s=$session&p[]=..
8274 //p[] = params sent with rtmp address (key, channel)
8275
8276 $session = $_GET['s'];
8277 sanV($session);
8278 if (!$session) exit;
8279
8280 $p = $_GET['p'];
8281
8282 if (count($p))
8283 {
8284 $username = $p[0];
8285 $room = $channel = $p[1];
8286 $key = $p[2];
8287 $broadcaster = $p[3];
8288 $broadcasterID = $p[4];
8289 }
8290
8291 $postID = 0;
8292 $ztime = time();
8293
8294 global $wpdb;
8295 $wpdb->flush();
8296 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . sanitize_file_name($channel) . "' and post_type='channel' LIMIT 0,1" );
8297
8298 $options = get_option('VWliveStreamingOptions');
8299
8300 //global $current_user;
8301 //get_currentuserinfo();
8302
8303 $verified = 0;
8304
8305 //rtmp key login for external apps
8306 if ($broadcaster=='1') //external broadcaster
8307 {
8308 $validKey = md5('vw' . $options['webKey'] . $broadcasterID . $postID);
8309 if ($key == $validKey)
8310 {
8311 $verified = 1;
8312
8313 VWliveStreaming::webSessionSave($session, 1, $key);
8314
8315 //setup/update channel in sql
8316 global $wpdb;
8317 $table_name3 = $wpdb->prefix . "vw_lsrooms";
8318 $wpdb->flush();
8319
8320 $sql = "SELECT * FROM $table_name3 where owner='$username' and name='$room'";
8321 $channelR = $wpdb->get_row($sql);
8322
8323 if (!$channelR)
8324 $sql="INSERT INTO `$table_name3` ( `owner`, `name`, `sdate`, `edate`, `rdate`,`status`, `type`) VALUES ('$username', '$room', $ztime, $ztime, $ztime, 0, 1)";
8325 elseif ($options['timeReset'] && $channelR->rdate < $ztime - $options['timeReset']*24*3600) //time to reset in days
8326 $sql="UPDATE `$table_name3` set edate=$ztime, type=1, rdate=$ztime, wtime=0, btime=0 where owner='$username' and name='$room'";
8327 else
8328 $sql="UPDATE `$table_name3` set edate=$ztime where owner='$username' and name='$room'";
8329
8330 $wpdb->query($sql);
8331
8332 VWliveStreaming::sessionUpdate($username, $room, 1, 2, 1);
8333 }
8334
8335 }
8336 elseif ($broadcaster=='0') //external watcher
8337 {
8338 $validKeyView = md5('vw' . $options['webKey']. $postID);
8339 if ($key == $validKeyView)
8340 {
8341 //$verified = 1;
8342
8343 VWliveStreaming::webSessionSave($session, 0, $key);
8344 VWliveStreaming::sessionUpdate($username, $room, 0, 2, 1);
8345 }
8346 //VWliveStreaming::webSessionSave('error-'.$session, 0, "$channel-$session-$key-$postID-$validKeyView-".sanitize_file_name($channel) );
8347
8348 }
8349
8350 //validate web login to rtmp
8351 $dir = $options['uploadsPath'];
8352 $filename1 = $dir ."/_sessions/$session";
8353 if (file_exists($filename1)) //web login
8354 {
8355 echo implode('', file($filename1));
8356 if ($broadcaster) echo '&role=' . $broadcaster;
8357 }
8358 else
8359 {
8360 echo "VideoWhisper=1&login=0";
8361 }
8362
8363 //also update RTMP server IP in settings after authentication
8364 if ($verified)
8365 {
8366
8367 //if IP restriction not defined: configure it
8368 if (!$options['rtmp_restrict_ip'])
8369 {
8370 $options['rtmp_restrict_ip'] = VWliveStreaming::get_ip_address();
8371 $updateOptions=1;
8372 echo '&rtmp_restrict_ip=' . $options['rtmp_restrict_ip'];
8373 }
8374
8375 //also enable webStatus if on auto (now secure with IP restriction enabled)
8376 if ($options['webStatus'] == 'auto')
8377 {
8378 $options['webStatus'] = 'enabled';
8379 $updateOptions=1;
8380 echo '&webStatus=' . $options['webStatus'];
8381 }
8382
8383 if ($updateOptions) update_option('VWliveStreamingOptions', $options);
8384
8385 }
8386
8387
8388 ?><?php
8389 break;
8390
8391 case 'lb_status':
8392 //! lb_status
8393 /*
8394Broadcaster status updates.
8395
8396POST Variables:
8397u=Username
8398s=Session, usually same as username
8399r=Room
8400ct=session time (in milliseconds)
8401lt=last session time received from this script in (milliseconds)
8402cam, mic = 0 none, 1 disabled, 2 enabled
8403*/
8404
8405 $cam=$_POST['cam'];
8406 $mic=$_POST['mic'];
8407
8408 $timeUsed=$currentTime=$_POST['ct'];
8409 $lastTime=$_POST['lt'];
8410
8411 $s=$_POST['s'];
8412 $u=$_POST['u'];
8413 $r=$_POST['r'];
8414 $m=$_POST['m'];
8415
8416 //sanitize variables
8417 sanV($s);
8418 sanV($u);
8419 sanV($r);
8420 sanV($m,0);
8421
8422 $timeUsed = (int) $timeUsed;
8423 $currentTime = (int) $currentTime;
8424 $lastTime = (int) $lastTime;
8425
8426 //exit if no valid session name or room name
8427 if (!$s) exit;
8428 if (!$r) exit;
8429
8430 //only registered users can broadcast
8431 if (!is_user_logged_in()) exit;
8432
8433 $table_name = $wpdb->prefix . "vw_sessions";
8434 $table_name3 = $wpdb->prefix . "vw_lsrooms";
8435 $wpdb->flush();
8436
8437 $ztime=time();
8438
8439 //room info
8440 $sql = "SELECT * FROM $table_name3 where owner='$u' and name='$r'";
8441 $channel = $wpdb->get_row($sql);
8442 $wpdb->query($sql);
8443
8444 if (!$channel) $disconnect = urlencode("Channel $r not found!");
8445 else
8446 {
8447 //user online
8448 $sql = "SELECT * FROM $table_name where session='$s' AND status='1' AND `type`='1'";
8449 $session = $wpdb->get_row($sql);
8450 if (!$session)
8451 {
8452 $sql="INSERT INTO `$table_name` ( `session`, `username`, `room`, `message`, `sdate`, `edate`, `status`, `type`) VALUES ('$s', '$u', '$r', '$m', $ztime, $ztime, 1, 1)";
8453 $wpdb->query($sql);
8454 }
8455 else
8456 {
8457 $sql="UPDATE `$table_name` set edate=$ztime, room='$r', username='$u', message='$m' where session='$s' AND status='1' AND `type`='1'";
8458 $wpdb->query($sql);
8459 }
8460
8461 VWliveStreaming::cleanSessions(1);
8462
8463 //room usage
8464 // options in minutes
8465 // mysql in s
8466 // flash in ms (minimise latency errors)
8467
8468 $options = get_option('VWliveStreamingOptions');
8469 if ($ban = VWliveStreaming::containsAny($s, $options['bannedNames'])) $disconnect = "Name banned ($s, $ban)!";
8470 if ($ban = VWliveStreaming::containsAny($r, $options['bannedNames'])) $disconnect = "Room banned ($r, $ban)!";
8471
8472 if ($channel->type>=2) //premium
8473 {
8474 $poptions = VWliveStreaming::channelOptions($channel->type, $options);
8475
8476 $maximumBroadcastTime = 60 * $poptions['pBroadcastTime'];
8477 $maximumWatchTime = 60 * $poptions['pWatchTime'];
8478 }
8479 else
8480 {
8481 $maximumBroadcastTime = 60 * $options['broadcastTime'];
8482 $maximumWatchTime = 60 * $options['watchTime'];
8483 }
8484
8485 $maximumSessionTime = $maximumBroadcastTime; //broadcaster
8486
8487 //update time
8488 $expTime = $options['onlineExpiration1']+30;
8489 $dS = floor(($currentTime-$lastTime)/1000);
8490
8491 if ($dS>$expTime || $dS<0) $disconnect = urlencode("Web server out of sync! ($dS>$expTime)" ); //Updates should be faster than 3 minutes; fraud attempt?
8492 else
8493 {
8494 $channel->btime += $dS;
8495 $timeUsed = $channel->btime * 1000;
8496
8497 if ($maximumBroadcastTime && $maximumBroadcastTime < $channel->btime ) $disconnect = urlencode("Allocated broadcasting time ended!");
8498 if ($maximumWatchTime && $maximumWatchTime < $channel->wtime ) $disconnect = urlencode("Allocated watch time ended!");
8499
8500 $maximumSessionTime *=1000;
8501
8502 //update
8503 $sql="UPDATE `$table_name3` set edate=$ztime, btime = " . $channel->btime . " where owner='$u' and name='$r'";
8504 $wpdb->query($sql);
8505
8506 //transcode if necessary
8507 if (!$disconnect) if ($options['transcodingAuto']>=2) VWliveStreaming::transcodeStream($r);
8508
8509 //update post
8510 $postID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = '" . $r . "' and post_type='channel' LIMIT 0,1" );
8511 if ($postID)
8512 {
8513 update_post_meta($postID, 'edate', $ztime);
8514 update_post_meta($postID, 'btime', $channel->btime);
8515
8516 VWliveStreaming::updateViewers($postID, $r, $options);
8517
8518 }
8519
8520 }
8521
8522 }
8523
8524
8525 ?>timeTotal=<?php echo $maximumSessionTime?>&timeUsed=<?php echo $timeUsed?>&lastTime=<?php echo $currentTime?>&disconnect=<?php echo $disconnect?>&loadstatus=1<?php
8526 break;
8527 //! translation
8528 case 'translation':
8529?>
8530
8531 <translations>
8532<?php
8533 $options = get_option('VWliveStreamingOptions');
8534 echo html_entity_decode(stripslashes($options['translationCode']));
8535?>
8536</translations>
8537 <?php
8538 break;
8539 //! ads
8540 case 'ads':
8541
8542 /* Sample local ads serving script ; Or use http://adinchat.com compatible ads server to setup http://adinchat.com/v/your-campaign-id
8543
8544POST Variables:
8545u=Username
8546s=Session, usually same as username
8547r=Room
8548ct=session time (in milliseconds)
8549lt=last session time received (from web status script)
8550
8551*/
8552
8553 $room=$_POST[r];
8554 $session=$_POST[s];
8555 $username=$_POST[u];
8556
8557 $currentTime=$_POST[ct];
8558 $lastTime=$_POST[lt];
8559
8560 $ztime=time();
8561
8562 $options = get_option('VWliveStreamingOptions');
8563
8564 global $wpdb;
8565 $table_name3 = $wpdb->prefix . "vw_lsrooms";
8566
8567 $sql = "SELECT * FROM $table_name3 where name='$room'";
8568 $channel = $wpdb->get_row($sql);
8569 // $wpdb->query($sql);
8570
8571 if ($channel)
8572 if ($channel->type>=2)
8573 {
8574 $ad = '';
8575 $debug='premiumChannel';
8576 }
8577 else $ad = urlencode(html_entity_decode(stripslashes($options['adsCode'])));
8578 else $debug='noChannel';
8579
8580
8581 ?>x=1&ad=<?php echo $ad; ?>&loadstatus=1<?php echo '&debug=' . $debug;
8582 break;
8583 } //end case
8584 die();
8585 }
8586 }
8587
8588}
8589
8590//instantiate
8591if (class_exists("VWliveStreaming")) {
8592 $liveStreaming = new VWliveStreaming();
8593}
8594
8595//Actions and Filters
8596if (isset($liveStreaming)) {
8597
8598 register_deactivation_hook( __FILE__, 'flush_rewrite_rules' );
8599 register_activation_hook( __FILE__, array(&$liveStreaming, 'install' ) );
8600
8601 add_action( 'init', array(&$liveStreaming, 'init'));
8602 add_action( 'parse_request', array(&$liveStreaming, 'parse_request'));
8603
8604 add_action("plugins_loaded", array(&$liveStreaming, 'plugins_loaded'));
8605 add_action('admin_menu', array(&$liveStreaming, 'admin_menu'));
8606 add_action('admin_head', array(&$liveStreaming, 'admin_head'));
8607 add_action( 'admin_init', array(&$liveStreaming, 'admin_init'));
8608
8609 add_action( 'login_enqueue_scripts', array('VWliveStreaming','login_enqueue_scripts') );
8610 add_filter( 'login_headerurl', array('VWliveStreaming','login_headerurl'));
8611
8612
8613 /* Only load code that needs BuddyPress to run once BP is loaded and initialized. */
8614 function liveStreamingBP_init()
8615 {
8616 if (class_exists('BP_Group_Extension')) require( dirname( __FILE__ ) . '/bp.php' );
8617 }
8618
8619 add_action( 'bp_init', 'liveStreamingBP_init' );
8620
8621 add_filter( "single_template", array(&$liveStreaming,'single_template') );
8622
8623}
8624?>