Warning: chmod(): Operation not permitted in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [0] in function chmod in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [1] in function include_once in /var/www/hopeinstoughton_www/wp-settings.php on line 560 [2] in function require_once in /var/www/hopeinstoughton_www/wp-config.php on line 85 [3] in function require_once in /var/www/hopeinstoughton_www/wp-load.php on line 50 [4] in function require_once in /var/www/hopeinstoughton_www/wp-blog-header.php on line 13 [5] in function require in /var/www/hopeinstoughton_www/index.php on line 17
| Server IP : 94.177.8.99 / Your IP : 216.73.217.165 Web Server : Apache/2.4.58 (Ubuntu) System : Linux aries 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 User : www-data ( 33) PHP Version : 8.1.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/hopeinstoughton_www/wp-content/plugins/youtube-schedule/ |
Upload File : |
<?php
/*
Plugin Name: Live Video and Youtube
Plugin URI: http://hostz.org/
Description: Manage Live Youtube Videos. Notify when streaming started.
Version: 1.0.0
Author: Phil Young
Author URI: http://hostz.org/
License: Whatever
*/
// Admin: * Set Current URL, and Event Type (default to last "up next" event
// * up next is: Type / Date
// Add following tag to youtube: yt:stretch=16:9
// THIS HAS A HARDCODED ZOOM SECRET
/*
To do: Sign up for email notifications
- store email address, events, level
- to do: SMS or IM??
Change preferences
Send Email when event goes live
* Watch at HopeInStoughton
* Watch on Youtube
* contact info if something goes wrong
* Change preferences
*/
class scheduler_class {
const ZOOM_BC_ID = '85676868884';
const ZOOM_BC_LINK = 'https://us06web.zoom.us/j/85676868884?pwd=ejE1cUxqWkdwS2I5V2w2VFlXaXE3dz09';
const ZOOM_SUN_ID = '83443024657';
const ZOOM_SUN_LINK = 'https://us06web.zoom.us/j/83443024657?pwd=WDB2Y2MzTDhOMkl3R1AzalJjUFYvdz09';
const ZOOM_SUN_PIN = '5629';
const ZOOM_XTRA_ID = '87282475532';
const ZOOM_XTRA_LINK = 'https://us06web.zoom.us/j/87282475532?pwd=OTZuWTNIYXJNZTNWWHNXeDU3MnJNUT09';
const ZOOM_ECBS_ID = '89110222817';
const ZOOM_ECBS_PIN = '9933';
const ZOOM_ECBS_LINK = 'https://us06web.zoom.us/j/89110222817?pwd=llziKaUZb7M2kzGGxVXzbXXcRMpxr2.1';
function __construct() {
// an abbreviated version of this is in media-manager
$this->EVENTS = array(
0 => array('(unknown)', 0), // no future event
1 => array('Sunday Morning Class and Memorial Service', 0),
2 => array('Sunday Memorial Service', 0),
3 => array('Bible Class', 0),
4 => array('Brother\'s Class', 1),
5 => array('Sister\'s Class', 1),
6 => array('Arranging Board Meeting', 2),
7 => array('Business Meeting', 2),
8 => array('CYC', 1),
9 => array('Public Event', 0),
10 => array('Special Event', 1),
11 => array('Special Event - Baptism', 1),
99 => array('Test Event', 0) // - no email will be sent
);
// use prepare_timezone.php to create the TIMEZONE data
$this->TIMEZONE = array (
'base' =>
array (
'display' => '(UTC-05:00) Eastern Time (US & Canada)',
'dlt' => 'Eastern Daylight Time',
'std' => 'Eastern Standard Time',
),
0 =>
array (
'bias' => 300,
'bias_dls' => -60,
'dls' =>
array (
'yy' => 0,
'mm' => 3,
'dow' => 0,
'dd' => 2,
'hh' => 2,
'nn' => 0,
),
'std' =>
array (
'yy' => 0,
'mm' => 11,
'dow' => 0,
'dd' => 1,
'hh' => 2,
'nn' => 0,
),
),
2006 =>
array (
'bias' => 300,
'bias_dls' => -60,
'dls' =>
array (
'yy' => 0,
'mm' => 4,
'dow' => 0,
'dd' => 1,
'hh' => 2,
'nn' => 0,
),
'std' =>
array (
'yy' => 0,
'mm' => 10,
'dow' => 0,
'dd' => 5,
'hh' => 2,
'nn' => 0,
),
),
2007 =>
array (
'bias' => 300,
'bias_dls' => -60,
'dls' =>
array (
'yy' => 0,
'mm' => 3,
'dow' => 0,
'dd' => 2,
'hh' => 2,
'nn' => 0,
),
'std' =>
array (
'yy' => 0,
'mm' => 11,
'dow' => 0,
'dd' => 1,
'hh' => 2,
'nn' => 0,
),
),
);
$this->URL = plugin_dir_url(__FILE__);
add_action('admin_menu', array($this, 'main_menu'), 1 );
add_action('admin_init', array($this, '__register_settings'));
add_action('wp_enqueue_scripts', array($this, 'add_css' ));
add_action('admin_enqueue_scripts', array($this, 'add_css' ));
add_shortcode('youtubeplayer', array($this, '_shortcode_handler' ));
add_shortcode('quicklink', array($this, '_quicklink_handler' ));
add_shortcode('zoom', array($this, '_zoom_handler' ));
add_action('wp_dashboard_setup', array($this, 'dashboard_widgets'));
add_action( 'wp_ajax_nopriv_youtube', array($this, 'ajax_callback')); // when not logged in
add_action( 'wp_ajax_youtube', array($this, 'ajax_callback')); // when logged in
add_action( 'wp_loaded', [$this, 'post_form'], 49 ); // custom urls
$this->siteurl = get_option( 'siteurl' );
$this->adminurl = admin_url('admin-ajax.php?action=youtube'); // ajax callback to see if live streaming is running
add_filter( 'youtubeschedule-active', [$this, '__is_active'], 50, 1 ); // is youtube active, and do we have permission to access it?
add_filter( 'youtubeschedule-zoom', [$this, '__is_active_zoom'], 50, 1 ); // is zoom active?
//update_option( 'youtubeschedule-link', 'https://www.youtube.com/watch?v=U9CGvuRts5E');
}
function dashboard_widgets() {
wp_add_dashboard_widget('widget_livevideo', 'Live Video', array($this, 'widget_dashboard'));
// updated every 15s
wp_add_dashboard_widget('widget_watching', 'Live Video — Who is Watching?', array($this, 'widget_watching'));
}
function __register_settings() {
add_option( 'youtubeschedule-link', '');
add_option( 'youtubeschedule-event', '1');
add_option( 'youtubeschedule-nextdate', '');
add_option( 'youtubeschedule-nexttime', '');
add_option( 'youtubeschedule-link-wed', '');
add_option( 'youtubeschedule-link-sun', '');
register_setting( 'default', 'youtubeschedule-link' );
register_setting( 'default', 'youtubeschedule-event' );
register_setting( 'default', 'youtubeschedule-nextdate' );
register_setting( 'default', 'youtubeschedule-nexttime' );
register_setting( 'default', 'youtubeschedule-link-wed' );
register_setting( 'default', 'youtubeschedule-link-sun' );
}
function main_menu() {
global $_registered_pages;
// this is added to dashboard page, admin_page also needed - otherwise Editors cannot update settings
add_submenu_page(NULL, __('Youtube-Schedule - update settings'), __('xxxx'), // non-menu page
'publish_pages', 'livevideo-schedule-update', array($this, '_updateyoutube'));
if (!empty($_registered_pages['dashboard_page_livevideo-schedule-update']))
$_registered_pages['admin_page_livevideo-schedule-update'] = TRUE;
}
function _updateyoutube() {
// Check nonce and capabilities
$nonce = $_REQUEST['_wpnonce'];
$error_msg = false;
if ( ! wp_verify_nonce( $nonce, 'update-links' ) )
$error_msg = __( 'Unable to submit this form, please refresh and try again.' );
if ( $error_msg ) {
echo $error_msg;
return;
}
update_option('youtubeschedule-link', $_REQUEST['livelink']);
update_option('youtubeschedule-event', $_REQUEST['eventtype']);
update_option('youtubeschedule-nextdate', $_REQUEST['e_date']);
update_option('youtubeschedule-nexttime', $_REQUEST['e_time']);
if ($_REQUEST['livelink'] != '') { // save the link under the current day of week. This is used by the chatbot
$dow = strtolower(date('D'));
switch($dow) {
case 'wed':
case 'sun':
update_option('youtubeschedule-link-' . $dow, $_REQUEST['livelink']);
break;
}
}
$url = admin_url();
echo <<<BLOCK
<p>Options have been updated</p>
<ul>
<li>View the <a href="/video">Public</a> live video page (no password required)</li>
<li>View the <a href="/members/live-video">Christadelphian Community</a> live video page (general password required)</li>
<li>View the <a href="/members/private">Stoughton Member</a> Live Video page</li>
<li><a href="$url">Back to the Dashboard</a></li>
BLOCK;
}
function _javascript() {
return <<<BLOCK
function elephant(domain, user, display, linkclass) {
if (!display) display = user + '@' + domain;
if (!linkclass) linkclass = 'link';
document.write('<a href="mailto:' + user + '@' + domain + '" class="' + linkclass + '">' + display + '</a>');
}
BLOCK;
}
// options - show email, show skype, refresh
function ShowMessage($title, $body, $isOffline = 0) {
$js = $this->_javascript();
// Display next event, if there is one
$current_event = intval(get_option( 'youtubeschedule-event', ''));
if ($isOffline && $current_event) {
$desc = $this->EVENTS[$current_event][0];
$current_date = intval(get_option( 'youtubeschedule-nextdate', '')) * 86400 + 43200;
list($yy, $mm, $dd) = explode(',', gmdate('Y,n,j', $current_date));
$current_time = intval(get_option( 'youtubeschedule-nexttime', ''));
$hh = intval($current_time / 60);
$nn = $current_time % 60;
$exp = gmmktime($hh, $nn, 0, $mm, $dd, $yy); // this is 9:30am UTC, not 9:30am Boston Time (EST/EDT)
$date = gmdate('D, F j', $exp);
$time = gmdate('g:i a', $exp);
$estart = gmdate('Y-m-d H:i', $exp);
$efinish = gmdate('Y-m-d H:i', $exp + 2 * 3600);
list($d_std, $d_dls, $data) = $this->GetTimeZoneData(time());
// convert to local time - as unixtime, and also store current time
$bias = 0;
$dls = $this->GetTZinfo($exp, $bias);
$exp += $bias;
$utc = gmdate('Y-m-d H:i:s', $exp);
$body .= ' The next event to be streamed live is: “' . $desc . "” on $date at $time (Eastern). ";
list($current_level, $link) = $this->_GetVideoLink($current_event);
$link = $this->siteurl . $link;
$msg = <<<BLOCK
<div class="next" id="nextevent"></div>
<div id="addevent">
<a href="$link" title="Add to Calendar" class="addthisevent">
Add to Calendar
<span class="_start">$estart</span>
<span class="_end">$efinish</span>
<span class="_zonecode">15</span>
<span class="_summary">$desc</span>
<span class="_location">$link</span>
<span class="_organizer">Boston Christadelphians</span>
<span class="_all_day_event">false</span>
<span class="_date_format">YYYY-MM-DD</span></a>
</div>
BLOCK;
$current = time();
$js .= <<<BLOCK
jQuery(document).ready(function() {
jQuery('#nextevent').countdown({fmt: 'dd hh:mm:ss', current: $current, dest: $exp});
});
BLOCK;
} else {
$msg = '';
}
// do an ajax call to get state of streaming - refresh only when streaming has started
return <<<BLOCK
<script type="text/javascript">
$js
// Reload page when streaming starts
jQuery(document).ready(function() {
let $ = jQuery;
$.getJSON('{$this->adminurl}&status=0');
setInterval(function() {
// if Details page is being displayed, don't refresh
if ($('form.no-auto-refresh').length) return;
$.getJSON('{$this->adminurl}&status=0', function(data) {
if (data.live) window.location.reload();
});
}, 30 * 1000);
$('.bind-localtime').each(function() {
let \$this = $(this);
let dt = parseInt(\$this.data('date'));
\$this.html(new Date(dt * 1000).toLocaleString([], { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric" }));
});
});
</script>
<style type="text/css">
#ys_frame {
border-radius: 10px;
-o-border-radius: 10px;
-ms-border-radius: 10px;
-webkit-border-radius: 10px;
box-shadow: 0 1px 5px 3px #dfdfdf;
-o-box-shadow: 0 1px 5px 3px #dfdfdf;
-ms-box-shadow: 0 1px 5px 3px #dfdfdf;
-webkit-box-shadow: 0 1px 5px 3px #dfdfdf;
width: 680px;
height: 360px;
margin: 25px auto;
background-image: url({$this->URL}clouds2.jpg);
padding: 20px;
position: relative;
}
#ys_frame h2 {
font-family: Georgia,serif;
font-size: 34px;
padding-bottom: 30px;
color: #000;
}
#ys_frame p {
font-family: Georgia,serif;
font-size: 20px;
line-height: auto;
}
#ys_frame div.footnote {
position: absolute;
display: block;
width: 680px;
top: 340px;
font-weight: bold;
}
#ys_frame a, #ys_frame a:visited {
color: #1C777D;
}
#ys_frame div.next {
position: absolute;
display: block;
width: 680px;
top: 170px;
font-weight: bold;
}
#ys_frame div#addevent {
position: absolute;
display: block;
width: 680px;
top: 295px;
text-align: center;
}
</style>
<div id="ys_frame">
<h2>$title</h2>
<p>$body</p>$msg
<div class="footnote">Archived copies of previously streamed content are available for viewing from the <a href="/members">Member Area</a>. If you
need assistance, or wish to request access, please contact <script type="text/javascript">elephant('hopeinstoughton.org', 'phil');</script></div>
</div>
<div style="width: 680px;margin:10px auto;padding:0 20px;">Local Time: <span class="bind-localtime" data-date="$exp"></span></div>
BLOCK;
}
function _generatelist($array, $current) {
$list = '';
foreach($array as $id => $data) {
if (is_array($data)) {
$caption = $data[0];
} else {
$caption = $data;
}
$sel = $current == $id ? ' selected' : '';
$list .= "<option value=\"$id\"$sel>" . htmlspecialchars($caption) . "</option>\n";
}
return $list;
}
function _generatelistDates($array, $current) {
$list = '';
foreach($array as $data) {
$caption = $data['date'];
$id = $data['m'];
$sel = $current == $id ? ' selected' : '';
$extra = '';
if (isset($data['tp'])) $extra .= " data-type=\"{$data['tp']}\"";
if (isset($data['start'])) $extra .= " data-start=\"{$data['start']}\"";
$list .= "<option value=\"$id\"$sel$extra>" . htmlspecialchars($caption) . "</option>\n";
}
return $list;
}
function MinutesToTime($mm) {
$hh = intval($mm / 60);
$mm = $mm % 60;
$h2 = ($hh < 10) ? "0$hh" : $hh;
$m2 = ($mm < 10) ? "0$mm" : $mm;
$ampm = ($hh < 12) ? 'am' : 'pm';
if ($hh > 12) $hh -= 12;
if (!$hh) $hh = 12;
return "$h2:$m2 ($hh:$m2 $ampm)";
}
public function widget_watching() {
echo <<<BLOCK
<script type="text/javascript">
function escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
}
function generateOutput(timestamp, isstreaming, userdata) {
var dname = escapeHtml(userdata.co_username);
var dloc = escapeHtml(userdata.co_location);
if (isstreaming) {
if (userdata.co_lastseen < timestamp - 60) userdata.co_status = 0;
if (!userdata.co_status) {
var t = parseInt((timestamp - userdata.co_lastseen) / 60);
dname = '<i title="offline, last seen ' + t + ' minutes ago">(' + dname + ')</i>';
} else {
var t = parseInt((timestamp - userdata.co_firstseen) / 60);
dname = '<span title="online for ' + t + ' minutes">' + dname + '</span>';
}
}
var entry = '<td>' + dname + '</td><td>' + dloc + '</td><td width="107">' + userdata.co_ipaddress + '</td>';
return entry;
}
function updateDisplay(data) {
if (data.time) {
var output = data.live ? '<p>The following are <span style="font-weight:bold;color:#00e000">watching</span> the Live Streaming</p>' : '<p>The following are <span style="font-weight:bold;color:#e00000">waiting</span> for the Live Streaming to start</p>';
if (!data.online.length) {
output = '<tr><td>No Users</td></tr>';
} else {
for(var i = 0; i < data.online.length; i++) {
output += '<tr>' + generateOutput(data.time, data.live, data.online[i]) + '</tr>';
}
}
jQuery('#nowwatching').html('<table id="watchingtable" cellspacing="0" width="445">' + output + '</table>');
}
}
jQuery.getJSON('{$this->adminurl}&status=9876543', updateDisplay);
setInterval(function() {
jQuery.getJSON('{$this->adminurl}&status=9876543', updateDisplay);
}, 15 * 1000);
</script>
<div id="nowwatching">
<p>Loading, please wait...</p>
</div>
<p style="font-size:10px">This list is updated every 15 seconds. <a href="https://cygnus.hopeinstoughton.org/cygnus/online-now" target="_blank">Show Details</a></p>
BLOCK;
}
private function asSeconds($x) {
[$hh, $mm, $ss] = explode(':', $x);
return intval($hh, 10) * 60 + intval($mm, 10);
}
private function getServiceInfo($dt) {
global $wpdb;
$ddate = '"' . gmdate('Y-m-d', $dt) . '"';
$service_time = FALSE;
$class_time = FALSE;
$events = $wpdb->get_results("select event_category,event_time from `{$wpdb->prefix}spiffy_calendar` where event_begin=$ddate");
foreach($events as $event) {
switch($event->event_category) {
case 2:
$service_time = $event->event_time;
break;
case 3:
$class_time = $event->event_time;
break;
}
}
if ($class_time) return [1, $this->asSeconds($class_time)];
if ($service_time) return [2, $this->asSeconds($service_time)];
return [1, 570];
}
// set up nonce, select list
public function widget_dashboard() {
$list = '';
$current_event = get_option( 'youtubeschedule-event', '');
$current_link = get_option( 'youtubeschedule-link', '');
$current_date = get_option( 'youtubeschedule-nextdate', '');
$current_time = get_option( 'youtubeschedule-nexttime', '');
$dcurrent_link = htmlspecialchars($current_link);
$list = $this->_generatelist($this->EVENTS, $current_event);
$days = array();
[ $yy, $mm, $dd ] = explode(',', date('Y,n,j'));
$n = mktime(12, 0, 0, $mm, $dd, $yy);
// $n = time() - 43200;
for($i = 0; $i < 21; $i++) {
$m = intval($n / 86400);
$node = [
'm' => $m,
'dow' => gmdate('w', $n),
'date' => gmdate('l, F j, Y', $n),
];
switch($node['dow']) {
case 0: // sunday
// service / noservice / startdate
[$service_type, $service_start] = $this->getServiceInfo($n);
$node['tp'] = $service_type;
$node['start'] = $service_start;
break;
case 3: // wednesday
$node['tp'] = 3;
$node['start'] = 1170;
break;
}
$days[] = $node;
$n = strtotime('+1day', $n);
}
$list2 = $this->_generatelistDates($days, $current_date);
$times = [540, 570, 600, 630, 780, 810, 840, 1020, 1080, 1140, 1170, 1200];
$minutes = [];
// for($i = 360; $i <= 1260; $i += 15) { // 6am to 9pm
foreach($times as $i) { // 6am to 9pm
$minutes[$i] = $this->MinutesToTime($i);
}
$list3 = $this->_generatelist($minutes, $current_time);
$dls = '';
$n = time();
list($d_std, $d_dls, $data) = $this->GetTimeZoneData($n);
if ($n < $d_std) {
$dls = ($n < $d_dls) ? 'Daylight Saving starts at ' . gmdate('Y-m-d H:i', $d_dls) : 'Daylight Saving finishes at ' . gmdate('Y-m-d H:i', $d_std);
$dls = '<span style="font-size: 10px">' . $dls . '</span>';
}
echo <<<BLOCK
<p>Use the white-on-gray "<b>Schedule Stream</b>" button at <a href="https://studio.youtube.com/channel/UCIi20hlVjzrt04G3YPNRTgw/livestreaming/manage" target="youtubes">YouTube</a>
to create the YouTube video, then copy the link from "<b>View on Watch Page</b>" to the box below. Clear the link when the event has finished.</p>
<form name="post" action="?page=livevideo-schedule-update" method="post" id="schedule-update" class="initial-form hide-if-no-js">
<p>Youtube Watch Link:<br>
<input type="text" name="livelink" id="livelink" value="$dcurrent_link" placeholder="https://youtube.com/live/..." style="width:360px"></p>
<p>Next Scheduled Event:<br>
<select class="bind-scheduled-event" name="e_date" id="e_date">{$list2}</select>
<p>Event Type:<br>
<select name="eventtype" id="eventtype">
<option value="">(please select an event type)</option>
$list</select></p>
<p>Start Time:<br>
<select name="e_time" id="e_time">{$list3}</select><br>
$dls
</p>
<p class="submit">
<input type="hidden" name="action" id="unknown" value="livevideo-schedule-update" />
BLOCK;
wp_nonce_field( 'update-links' );
submit_button( __( 'Update Links' ), 'primary', 'save', false, array( 'id' => 'update-links' ) );
echo <<<BLOCK
<br class="clear" />
</p>
</form>
BLOCK;
}
function add_css() {
// add .js file
// wp_enqueue_script('skype', '//www.skypeassets.com/i/scom/js/skype-uri.js', array(), '' );
wp_enqueue_script('addthisevent', '//js.addthisevent.com/atemay.js', array(), '' );
wp_enqueue_script('youtubesch', plugins_url('countdown.js', __FILE__), array(), '1.2' );
wp_enqueue_style('youtubesch', plugins_url('countdown.css', __FILE__), array(), '1.1');
wp_enqueue_style('fontawesomes', '//use.fontawesome.com/releases/v5.6.3/css/all.css' );
}
// Retrieve the level for the current event
function _GetVideoLink($current_event) {
$current_level = isset($this->EVENTS[$current_event]) ? $this->EVENTS[$current_event][1] : 0;
switch($current_level) {
case 0:
$link = '/video/';
break;
case 1:
$link = '/members/live-video';
break;
case 2:
$link = '/members/private';
break;
default:
$link = '';
}
return array($current_level, $link);
}
function _register_for_video() {
$firsttime = !isset($_COOKIE['watching']);
if ($firsttime) {
$name = $location = '';
} else {
list($name, $location) = explode('.', $_COOKIE['watching']);
$name = base64_decode($name);
$location = base64_decode($location);
}
$dname = htmlspecialchars($name);
$dlocation = htmlspecialchars($location);
$topic = $firsttime ? 'Please Register' : 'Please Update your Details';
$msg = <<<BLOCK
This optional information is used to let us who is watching. You don’t have to fill it in, but we would really love it if you did.<br/>
<form method="post" class="no-auto-refresh">
<label for="username">Your name</label><br>
<input class="userinput" type="text" name="username" id="username" value="{$dname}" style="width:400px"><br>
<label for="username">Location (Town, State, Country if not US)</label><br>
<input class="userinput" type="text" name="userloc" id="userloc" value="{$dlocation}" style="width:400px"><br><br>
<input type="hidden" name="fn" value="register">
<input type="submit" value=" Continue to Live Video >>> ">
</form>
BLOCK;
return $this->ShowMessage($topic, $msg);
}
function post_form() {
$isPost = $_SERVER['REQUEST_METHOD'] == 'POST';
$fn = isset($_GET['fn']) ? $_GET['fn'] : '';
$this->request_change = ($fn == 'change_details');
$cache = $_SERVER['REQUEST_URI'];
if (($p = strpos($cache, '?')) !== FALSE) {
$cache = substr($cache, 0, $p);
}
$admin = current_user_can('editor') || current_user_can('administrator');
if (preg_match('#/~/youtubeschedule-zoom$#', $cache, $matches)) {
$txt = file_get_contents('php://input');
$post = json_decode($txt, TRUE);
$this->_zoom_event($post);
header('Content-type: text/plain');
echo 1;
exit;
} elseif (preg_match('#/~/youtubeschedule-fb$#', $cache, $matches)) {
$txt = file_get_contents('php://input');
$post = json_decode($txt, TRUE);
header('Content-type: text/plain');
$this->_facebook_event($post);
echo 1;
exit;
} elseif (preg_match('#/~/youtubeschedule-wed$#', $cache, $matches)) {
header('Content-type: text/plain');
die(json_encode($this->_chatbot_wed(), JSON_UNESCAPED_SLASHES));
} elseif (preg_match('#/~/youtubeschedule-sun$#', $cache, $matches)) { // just retrieve the date of the service at /members/current
header('Content-type: text/plain');
die(json_encode($this->_chatbot_sun(), JSON_UNESCAPED_SLASHES));
}
$fn = isset($_POST['fn']) ? $_POST['fn'] : '';
if ($isPost && $fn == 'register') {
$name = trim(stripslashes_deep($_POST['username']));
$loc = trim(stripslashes_deep($_POST['userloc']));
$url = $this->CreateuserCookie($name, $loc);
header('Content-type: text/plain');
header('Location: ' . $url);
echo "Redirecting to $url\n";
exit;
}
}
function CreateUserCookie($name, $location) {
$data = base64_encode($name) . '.' . base64_encode($location);
// SetCookie($data
SetCookie('watching', $data, time() + 365 * 86400, '/');
if (isset($_SERVER['HTTPS']) &&
($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$protocol = 'https://';
} else {
$protocol = 'http://';
}
$url = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REDIRECT_URL'];
if (!empty($_SERVER['REDIRECT_QUERY_STRING']) && !$this->request_change) $url .= '?' . $_SERVER['REDIRECT_QUERY_STRING'];
return $url;
}
function GetWatchingName() {
list($name, $location) = explode('.', $_COOKIE['watching']);
$name = base64_decode($name);
if ($name == '') $name = 'Unknown';
$location = base64_decode($location);
if ($location != '') $location = ' from ' . $location;
$location .= '</span><span> <a class="changeuser" href="?fn=change_details" title="change name"></a>';
return "<span style=\"vertical-align:bottom;font-size:14pt\">Watching as <strong>$name</strong>$location</span>";
}
function _quicklink_handler($atts) {
$a = shortcode_atts( array(
'pg' => 'welcome',
), $atts);
$frame = plugins_url('frame.jpg', __FILE__);
$current_link = get_option( 'youtubeschedule-link', '');
$ok = $current_link != ''; // currently streaming? display link
if (!$ok) { // streaming expected in next hour?
$current_date = intval(get_option( 'youtubeschedule-nextdate', '')) * 86400 + 43200;
list($yy, $mm, $dd) = explode(',', gmdate('Y,n,j', $current_date));
$current_time = intval(get_option( 'youtubeschedule-nexttime', ''));
$hh = intval($current_time / 60);
$nn = $current_time % 60;
$exp = gmmktime($hh, $nn, 0, $mm, $dd, $yy); // this is 9:30am UTC, not 9:30am Boston Time (EST/EDT)
list($d_std, $d_dls, $data) = $this->GetTimeZoneData( time() ); // $systemtime?
// convert to local time - as unixtime, and also store current time
$bias = 0;
$dls = $this->GetTZinfo($exp, $bias);
$exp += $bias;
$remaining = $exp - time(); // are we within an hour of it starting, or 1/2 after it has supposed to start?
if ($remaining < 3600 && $remaining > -1800) {
$ok = TRUE;
}
}
if ($ok) {
$streaming = '<div><a href="/video"><i class="fas fa-video"></i><span class="caption"><strong>Join us via live streaming</strong></span></a></div>';
} else {
$streaming = '';
}
if ($a['pg'] == 'who') {
$welcome = '<div><a href="/filecabinet/The%20Christadelphians%20in%20Stoughton%20welcome%20pack.pdf"><i class="far fa-file-pdf"></i><span class="caption">What to expect when visiting our church</a></span></div>';
} else {
$welcome = '<div><a href="/request"><i class="far fa-file-pdf"></i><span class="caption">Request your Free Bible Study Guide</a></span></div>';
$welcome = ''; // we don't have anything to send :(
}
$nefg = '';
$specialdate = mktime(12, 0, 0, 10, 14, 2024);
if (time() < $specialdate) {
$nefg = '<div><a href="/nefg2024"><i class="fas fa-school"></i><span class="caption">NEFG 2024 Details</a></span></div>';
}
// <span><img class="img-frame" src="$frame"></span>
// <div><a href="/study-weekend-2023"><i class="fa fa-video-camera" style="color:#900"></i><span class="caption" style="color:#900">April Study Weekend 2023</span></a></div>
$output = <<<BLOCK
<div class="navguide">
<span class="overlay" style="background-color: #eee; padding:10px">
<div><h4>Quick Links</h4></div>
$welcome
$nefg
$streaming
<div><a href="https://www.facebook.com/hopeinstoughton/"><i class="fab fa-facebook-square"></i><span class="caption">Join us on Facebook</span></a></div>
<div><a href="https://www.youtube.com/c/HopeInStoughton"><i class="fab fa-youtube"></i><span class="caption">YouTube channel</span></a></div>
<div><a href="mailto:info@hopeinstoughton.org?subject=Hope%20In%20Stoughton%20website"><i class="far fa-comments"></i><span class="caption">Contact us</span></a></div>
<div><a href="https://www.google.com/maps?oe=UTF-8&ie=UTF8&q=Christadelphian+stoughton&fb=1&gl=us&hq=Christadelphian&hnear=stoughton&ei=vkK_S4fDN5ewMr3rrPoL&ved=0CBsQ_wY&hl=en&view=map&f=d&daddr=48+Freeman+Street,+Stoughton,+MA+02072-2642&geocode=CeI1q9kxN-luFejJggIdSBfD-yEI5GBu7RjnuQ&sa=X"><i class="fas fa-map-signs"></i><span class="caption">Get directions</span></a></div>
<div><a href="/members/"><i class="fas fa-book-reader"></i><span class="caption">Member Resources</span></a></div>
</span>
</div>
BLOCK;
return $output;
/* old:
<p><a href="/request"><img title="Get your FREE e-booklet" src="/index_70_868951780.jpg" height="60" hspace="7" alt="Get your FREE e-booklet" width="55" />
Request your FREE Bible Study Guide</a></p>
<p><a href="http://www.facebook.com/home.php?#!/pages/Stoughton-MA/Christadelphians-in-Stoughton-MA/104892219549479?ref=ts" target="_blank"><img title="Join us on Facebook" src="/index_57_2163477941.jpg" height="30" hspace="7" alt="Join us on Facebook" width="30" /></a><a href="http://www.facebook.com/home.php?#!/pages/Stoughton-MA/Christadelphians-in-Stoughton-MA/104892219549479?ref=ts" target="_blank">Join us on Facebook</a></p>
<p><a href="mailto:info@hopeinstoughton.org?subject=Hope%20In%20Stoughton%20website"><img title="Contact Us" src="/index_66_1530557255.jpg" height="30" hspace="7" alt="Contact Us" width="30" />Contact us </a>
<p><a href="http://maps.google.com/maps?oe=UTF-8&ie=UTF8&q=Christadelphian+stoughton&fb=1&gl=us&hq=Christadelphian&hnear=stoughton&ei=vkK_S4fDN5ewMr3rrPoL&ved=0CBsQ_wY&hl=en&view=map&f=d&daddr=48+Freeman+Street,+Stoughton,+MA+02072-2642&geocode=CeI1q9kxN-luFejJggIdSBfD-yEI5GBu7RjnuQ&sa=X" target="_blank"><img title="Get Directions" src="/index_78_3754377.jpg" height="34" hspace="7" alt="Get Directions" width="35" />Get Directions</a></p>
<p><a href="https://plus.google.com/116228988344400509693" rel="publisher">Google+</a></p>
<p style="margin-left: 40px"><a href="/filecabinet/The%20Christadelphians%20in%20Stoughton%20welcome%20pack.pdf"><img title="You're welcome here!" src="/aboutus_50_3434251273.gif" height="31" hspace="7" alt="You're welcome here!" width="50" align="left" />
Here's what you can expect when you visit our church.</a></p>
*/
}
function _shortcode_handler($atts) {
$output = '';
$level = isset($atts['level']) ? intval($atts['level']) : 0;
// 0 Free to air - no password required
// 1 Christo Community page - low-level password required
// 2 Member-Only page - Stoughton Members only
$current_link = get_option( 'youtubeschedule-link', '');
if (empty($current_link)) {
// TO DO: automatically reload this page when event starts
return $this->ShowMessage('Streaming Offline', 'Live video streaming is currently unavailable. If this is an error, please contact us.', 1);
}
$current_event = intval(get_option( 'youtubeschedule-event', ''));
list($current_level, $link) = $this->_GetVideoLink($current_event);
if ($current_level > $level) { // not permitted to view it on this page - suggest the new link
return $this->ShowMessage('Authentication Required', "Live Streaming is currently running, however, it cannot be accessed from this page. If you have the appropriate password, please continue to the <a href=\"$link\">live event</a>.<br><br>");
}
// allowed to access it: create youtube code
// https://www.youtube.com/watch?v=oQR2tTQO4BI
if (preg_match('~v=(.*?)&~', $current_link, $match)) {
$video_id = $match[1];
} elseif (preg_match('~v=(.*?)$~', $current_link, $match)) {
$video_id = $match[1];
} elseif (preg_match('~youtu\.be/(.*?)$~', $current_link, $match)) { // https://youtu.be/IZWxJ5p3GVU
$video_id = $match[1];
} elseif (preg_match('~youtube\.com/live/(.*?)$~', $current_link, $match)) { // from 2022-12-14 https://youtube.com/live/An_FDJM0Dl0?feature=share
$video_id = $match[1];
if (($p = strpos($video_id, '?')) !== FALSE) $video_id = substr($video_id, 0, $p);
} else {
return $this->ShowMessage('Streaming Error', "Live Streaming is currently running, but there is a problem with the YouTube link for this event. Please contact us!");
}
$width = isset($atts['width']) ? intval($atts['width']) : 0;
$height = isset($atts['height']) ? intval($atts['height']) : 0;
if (!$width) $width = 854;
if (!$height) $height = 480;
// reload when streaming has finished
$output = <<<BLOCK
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery.getJSON('{$this->adminurl}&status=1');
setInterval(function() {
jQuery.getJSON('{$this->adminurl}&status=1', function(data) {
if (!data.live) window.location.reload();
});
}, 30 * 1000);
});
</script>
BLOCK;
$watching = '';
$x = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
// if we are logged into wordpress, use the loggedin name, and continue to the video
$user = wp_get_current_user();
if ($user->ID) {
} elseif (strpos($x, 'WordPress/') !== FALSE) {
// WordPress/4.4.2; http://christadelphian.video
} elseif (!isset($_COOKIE['watching']) || $this->request_change) {
return $this->_register_for_video();
} else {
$watching = $this->GetWatchingName();
}
$output .= <<<BLOCK
<p><iframe src="//www.youtube.com/embed/$video_id?rel=0&w=$width&h=$height" height="$height" width="$width" frameborder="0" allowfullscreen></iframe></p>
{$watching}
<p>When operational, this live broadcast is delayed by about a minute. So if you wish communicate with the speaker, don't send a SMS, but instead use Zoom - it's real-time. <a href="mailto:phil@hopeinstoughton.org">Email</a> if you encounter any problems</p>
BLOCK;
return $output;
}
private function DayOfWeek($day) {
return 1 + gmdate('w', $day);
}
private function DaysInMonth($year, $month) {
$day = gmmktime(0,0,0, $month, 15, $year);
return gmdate('t', $day);
}
function DayOfMonth2Date($year, $month, $weekinmonth, $dayinweek) {
if ($weekinmonth >= 1 && $weekinmonth <= 4) {
$day = $this->DayOfWeek(gmmktime(0,0,0, $month, 1, $year)); // get first day in month
$day = 1 + $dayinweek - $day; // get first dayInWeek in month
if ($day <= 0) $day += 7;
$day += 7 * ($weekinmonth-1); // get weekInMonth-th dayInWeek in month
return gmmktime(0,0,0, $month, $day, $year);
} elseif ($weekinmonth == 5) { // last week, calculate from end of month
$days = $this->DaysInMonth($year,$month);
$day = $this->DayOfWeek(gmmktime(0,0,0, $month, $days, $year)); // get last day in month
$day = $days + ($dayinweek - $day);
if ($day > $days) $day -= 7 ; // get last dayInWeek in month
return gmmktime(0,0,0, $month, $day, $year);
} else {
return 0;
}
}
function DSTDate2Date($dateinfo, $year) {
if (!$dateinfo['mm']) {
return 0;
} elseif (!$dateinfo['yy']) {
return $this->DayOfMonth2Date($year, $dateinfo['mm'], $dateinfo['dd'], $dateinfo['dow'] + 1)
+ ($dateinfo['hh'] * 3600 + $dateinfo['nn'] * 60);
} elseif ($yy == $year) {
return mktime($dateinfo['hh'], $dateinfo['nn'], 0, $dateinfo['mm'], $dateinfo['dd'], $dateinfo['yy'], 0);
} else {
return 0;
}
}
function GetTZinfo($systemtime, &$bias) { // returns 1 if using DLS; returned bias is in minutes
list($d_std, $d_dls, $data) = $this->GetTimeZoneData($systemtime);
if (!$d_std) { // no daylight saving
$dls = 0;
} elseif ($d_std < $d_dls) { // southern hemisphere
$dls = ($systemtime >= $d_dls || $systemtime < $d_std) ? 1 : 0;
} else {
$dls = ($systemtime >= $d_dls && $systemtime < $d_std) ? 1 : 0;
}
$bias = $data['bias'];
if ($dls) $bias += $data['bias_dls'];
$bias *= 60;
return $dls;
}
function GetTimeZoneData($systemtime) {
$yy = intval(date('Y', $systemtime));
$node = &$this->TIMEZONE;
if (isset($node[$yy])) {
$data = $node[$yy];
} else {
$data = $node[0];
}
$d_std = $this->DSTDate2Date($data['std'], $yy);
$d_dls = $this->DSTDate2Date($data['dls'], $yy);
return array($d_std, $d_dls, $data);
}
function TZInfoAsText($systemtime) {
list($d_std, $d_dls, $data) = $this->GetTimeZoneData($systemtime);
return 'Daylight Savings is from <b>' . gmdate('Y-m-d H:i', $d_dls) . '</b> to <b>'. gmdate('Y-m-d H:i', $d_std) . '</b>';
}
function updateStatus($name, $location, $ipaddress, $status) {
global $wpdb;
$types = array('%s', '%s', '%s', '%d', '%d');
if ($name == '') $name = $ipaddress;
$values = array(
'co_username' => $name,
'co_location' => $location,
'co_ipaddress' => $ipaddress,
'co_lastseen' => time(),
'co_status' => $status,
);
$dname = "'" . esc_sql($name) . "'";
$prior = $wpdb->get_row("select co_lastseen,co_status from cd_online where co_username=$dname");
if ($prior == NULL) { // New Record
$result = $wpdb->insert('cd_online', $values, $types);
} else { // Update
unset($values['co_username']);
array_shift($types);
$j = isset($prior->co_lastseen) ? $prior->co_lastseen : time() - 86400;
if ($status && empty($prior->co_status) || ($j < time() - 7200)) { // just changed from offline to online
$values['co_firstseen'] = $values['co_lastseen'];
$types[] = '%d';
}
$result = $wpdb->update('cd_online', $values, array('co_username' => $name), $types);
}
}
function GetCurrentStatus() {
global $wpdb;
$cutoff = time() - 30 * 60;
$online = $wpdb->get_results("select co_username,co_location,co_ipaddress,co_status,co_firstseen,co_lastseen from cd_online where co_lastseen>$cutoff order by co_username", ARRAY_A );
$zoom = $wpdb->get_results("select cz_userid,cz_username,cz_timeon,cz_timeoff,cz_friendly from cd_zoom where (cz_timeoff = 0) or (cz_timeoff > $cutoff)", ARRAY_A );
// add in zoom results
foreach($zoom as $user) {
$node = [
'co_username' => empty($user['cz_friendly']) ? $user['cz_username'] : $user['cz_friendly'],
'co_location' => '',
'co_ipaddress' => 'Zoom',
'co_status' => (int)$user['cz_timeoff'] ? 0 : 1,
'co_firstseen' => $user['cz_timeon'],
'co_lastseen' => $user['cz_timeoff'],
];
if (empty($node['co_lastseen'])) $node['co_lastseen'] = time();
$online[] = $node;
}
// sort again
return $online;
}
// Is live streaming available?
// have we heard from someone?
function ajax_callback() {
global $wpdb;
$status = isset($_GET['status']) ? intval($_GET['status']) : 0;
$result = array();
if ($status == 9876543) {
$result['online'] = $this->GetCurrentStatus();
$result['time'] = time();
} else {
$hascookie = isset($_COOKIE['watching']);
if ($hascookie) {
list($name, $location) = explode('.', $_COOKIE['watching']);
$name = substr(trim(base64_decode($name)), 0, 80);
$location = substr(trim(base64_decode($location)), 0, 250);
$this->updateStatus($name, $location, $_SERVER['REMOTE_ADDR'], $status);
} else { // unregistered waiting to be able to fill in form
$user = wp_get_current_user();
if ($user->ID > 0) {
$name = $user->display_name;
$this->updateStatus($name, '', $_SERVER['REMOTE_ADDR'], $status);
} else {
$this->updateStatus($_SERVER['REMOTE_ADDR'], '', $_SERVER['REMOTE_ADDR'], $status);
}
}
}
$current_link = trim(get_option( 'youtubeschedule-link', ''));
$result['live'] = $current_link != '' ? 1 : 0;
$zoomactive = intval(get_option( 'youtubeschedule-active', '0'));
$result['zoom'] = $zoomactive;
$result = json_encode($result);
echo $result;
exit;
}
function _zoom_handler($atts) {
$level = isset($atts['level']) ? intval($atts['level']) : 0;
$current_event = intval(get_option( 'youtubeschedule-event', ''));
if ($current_event) {
$current_date = intval(get_option( 'youtubeschedule-nextdate', '')) * 86400 + 43200;
list($yy, $mm, $dd) = explode('-', gmdate('Y-m-d', $current_date));
$current_time = intval(get_option( 'youtubeschedule-nexttime', ''));
$hh = intval($current_time / 60);
$nn = $current_time % 60;
$exp = gmmktime($hh, $nn, 0, intval($mm, 10), intval($dd, 10), $yy); // this is 9:30am UTC, not 9:30am Boston Time (EST/EDT)
$efinish = gmdate('Y-m-d H:i', $exp + 2 * 3600);
$now = time();
$bias = 0;
$dls = $this->GetTZinfo($now, $bias);
$now -= $bias;
$currentdate = gmdate('Y-m-d', $now);
$caption = '';
$footer = '';
// if day is not streaming day - return nothing
/* if (substr($efinish, 0, 10) != $currentdate) {
//return "<!-- $efinish $currentdate $now $bias $dls -->";
return '';
} */
// special event?
if ($currentdate >= '2026-07-18' && $currentdate < '2026-07-25') {
$caption = 'ECBS 2026';
switch($level) {
case 0:
$link = '/members/live-video';
$footer = '';
break;
case 1:
$pin = static::ZOOM_ECBS_PIN;
$meeting = static::ZOOM_ECBS_ID;
$link = static::ZOOM_ECBS_LINK;
$footer = <<<BLOCK
<p>Dial in to Zoom: <b>646 558 8656</b> (New York) or 438 809 7799 (Canada), Meeting ID: {$meeting}, Passcode: {$pin}</p>
BLOCK;
}
}
if ($caption == '') {
$dow = gmdate('N', $now);
switch($dow) {
case 3: // Wednesday
$caption = 'Wednesday Night from 7:30pm';
switch($level) {
case 0:
$link = '/members/live-video';
$footer = '';
break;
case 1:
$link = static::ZOOM_BC_LINK;
$footer = <<<BLOCK
<p>Dial in to Zoom: <b>646 558 8656</b> (New York) or 438 809 7799 (Canada), Meeting ID: 856 7686 8884, Passcode: 2311</p>
BLOCK;
}
break;
/* case 6: // Saturday
$caption = 'Celebration of life: Janice Baines';
switch($level) {
case 0:
$link = '/members/live-video';
break;
case 1:
$link = static::ZOOM_XTRA_LINK;
$footer = <<<BLOCK
<p>Dial in to Zoom: <b>646 558 8656</b> (New York) or +1 438 809 7799 (Canada), Meeting ID: 872 8247 5532, Passcode: 276938</p>
BLOCK;
}
break;
*/
case 7: // Sunday
$caption = 'Sunday Morning from 9:30am';
switch($level) {
case 0:
$link = '/members/live-video';
break;
case 1:
$link = static::ZOOM_SUN_LINK;
$id = static::ZOOM_SUN_ID;
$passcode = static::ZOOM_SUN_PIN;
$footer = <<<BLOCK
<p>Please use this <a href="$link" rel="nofollow" style="font-weight:bold">Zoom link</a> for the Sunday Morning Class if you wish to interact with the speaker. The YouTube link (above video) is delayed by about a minute.</p>
<p>Dial in to Zoom: <b>646 558 8656</b> (New York) or 438 809 7799 (Canada), Meeting ID: $id, Passcode: $passcode</p>
BLOCK;
}
// <p>Please use this <a href="$link" rel="nofollow" style="font-weight:bold">Zoom link</a> for the Sunday Morning Class if you wish to interact with the speaker, or participate in the Breakout classes. The YouTube link (above video) is delayed by about a minute.</p>
break;
}
}
if ($caption != '') {
$icon = '<img src="/wp-content/plugins/youtube-schedule/zoomus-ar21.svg" style="height:70px !important; vertical-align:middle">';
// <p>Join us via Zoom:</p>
return <<<BLOCK
<div style="width:680px;margin:0px auto;">
<div>
<a href="$link" rel="nofollow">$icon<span style="font-size:30px;vertical-align:middle;padding-left:5px;color:#4a8cff">$caption</span></a>
$footer
<p><b>Streaming Problems?</b> Please contact the A/V operator directly on <b>339-235-9838</b> (phone or text) instead of the hall phone.</p>
</div>
</div>
BLOCK;
}
}
return '';
}
public function __is_active($value) {
$current_link = get_option( 'youtubeschedule-link', '');
if ($current_link == '') {
$value['active'] = 0;
} else {
$current_event = intval(get_option( 'youtubeschedule-event', ''));
$current_level = isset($this->EVENTS[$current_event]) ? $this->EVENTS[$current_event][1] : 0;
$user_level = apply_filters('get_member_level', 0); // which password did we use?
$value['active'] = $user_level >= $current_level ? 1 : 0;
$value['link'] = $current_link;
$value['desc'] = isset($this->EVENTS[$current_event]) ? $this->EVENTS[$current_event][0] : '';
}
return $value;
}
public function __is_active_zoom($value) {
$active = intval(get_option( 'youtubeschedule-active', '0'));
$value['active'] = $active;
if ($active) {
$value['id'] = get_option( 'youtubeschedule-zoom-id', '');
if ($value['id'] == static::ZOOM_BC_ID) {
$value['desc'] = 'Bible Class';
$value['link'] = static::ZOOM_BC_LINK;
} elseif ($value['id'] == static::ZOOM_SUN_ID) {
$value['desc'] = 'Sunday Morning';
$value['link'] = static::ZOOM_SUN_LINK;
} elseif ($value['id'] == static::ZOOM_XTRA_ID) {
$value['desc'] = 'Special Event';
$value['link'] = static::ZOOM_XTRA_LINK;
} elseif ($value['id'] == static::ZOOM_ECBS_ID) {
$value['desc'] = 'ECBS';
$value['link'] = static::ZOOM_ECBS_LINK;
}
}
return $value;
}
// use the start-and-stop app at https://marketplace.zoom.us/user/build
public function _zoom_event($post) {
switch($post['event'] ?? '') {
case 'endpoint.url_validation':
$payload = $post['payload'];
$plainToken = $payload['plainToken'];
$secret = "3_RgGun-TXSBMY_bd3JT1g";
$sig = hash_hmac('sha256', $plainToken, $secret);
$result = [
'plainToken' => $plainToken,
'encryptedToken' => $sig,
];
header('Content-type: application/json');
die(json_encode($result, JSON_UNESCAPED_SLASHES));
case 'meeting.started':
update_option( 'youtubeschedule-zoom-id', $post['payload']['object']['id']);
update_option( 'youtubeschedule-active', '1');
// clear out attendance
break;
case 'meeting.ended':
// clear active. It make take a few minutes for this event to arrive after the meeting has ended
update_option( 'youtubeschedule-active', '0');
break;
case 'meeting.participant_joined':
// add to attendance
$info = $this->_zoom_participant($post['payload']['object'], 'join_time');
$this->_zoom_save($info, 'cz_timeon');
break;
case 'meeting.participant_left':
$info = $this->_zoom_participant($post['payload']['object'], 'leave_time');
// remove from attendance
$this->_zoom_save($info, 'cz_timeoff');
break;
}
/* $fp = fopen('/phil/zoomzoom.txt', 'a');
fwrite($fp, var_export($post, 1) . "\n\n");
fclose($fp); */
}
// '2021-12-14T23:35:47Z
private function _zoom_participant($object, $timefield) {
$info = [
'id' => (int) $object['participant']['user_id'],
'name' => $object['participant']['user_name'],
'time' => strtotime(str_replace('T', ' ', $object['participant'][$timefield])),
'meeting' => $object['id'],
];
return $info;
}
private function _facebook_event($post) {
$challenge = $_REQUEST['hub_challenge'];
$verify_token = $_REQUEST['hub_verify_token'];
$mode = $_REQUEST['hub.mode']; //=subscribe
if ($verify_token == 'JPf>v}D?`8q!$4H<uXv7') {
echo $challenge;
}
// $fp = fopen('/phil/fb.txt', 'a');
// fwrite($fp, var_export($post, 1) . "\n\n");
// fclose($fp);
}
private function _zoom_save($info, $targetfield) {
global $wpdb;
$types = [ '%d', '%s', '%s', '%s' ];
$values = [
'cz_userid' => $info['id'],
'cz_username' => $info['name'],
$targetfield => $info['time'],
'cz_meeting' => $info['meeting'],
];
if ($targetfield == 'cz_timeon') {
$values['cz_timeoff'] = 0;
}
$prior = $wpdb->get_row("select cz_userid from cd_zoom where cz_userid={$info['id']}");
if ($prior == NULL) { // New Record
$result = $wpdb->insert('cd_zoom', $values, $types);
} else { // Update
unset($values['cz_userid']);
array_shift($types);
$result = $wpdb->update('cd_zoom', $values, ['cz_userid' => $info['id'] ], $types);
}
}
private function _chatbot_getEventInfo($event) {
global $wpdb;
$date = $event->event_begin;
$topic = $slug = $youtube = $speaker = '';
$page = 1;
$p = strpos($event->event_desc, ':');
$speaker = trim(substr($event->event_desc, $p + 1));
$sql = <<<BLOCK
select i.*, ms_firstname, ms_lastname, option_value
from mm_item as i
left join mm_speaker as s on mi_speaker=ms_id
left join wp_options as o on option_name="youtubeschedule-link-wed"
where mi_date="$date"
and mi_type="bc"
BLOCK;
// echo "$sql\n";
$row = $wpdb->get_row($sql);
// now get list of events (list of links)
if (!is_null($row)) {
$sql = <<<BLOCK
select e.*, mixe_event, mixe_sequence
from mm_item_x_event
left join mm_event as e on e.me_id=mixe_event
where mixe_item="{$row->mi_id}"
BLOCK;
$rows = $wpdb->get_results($sql);
$param = json_decode($row->mi_other, TRUE);
$topic = $rows[0]->me_topic ?? '';
$slug = $rows[0]->me_slug ?? '';
$page = intval($rows[0]->mixe_sequence ?? '1');
$youtube = $param['youtube'] ?? '';
$speaker = trim($row->ms_firstname . ' ' . $row->ms_lastname);
} else {
}
// class starts at 19:30
$timezone = new DateTimeZone('America/New_York');
$datetime = new DateTime("$date 19:30", $timezone);
$dt = $datetime->getTimestamp();
// if live link is the same as the active link - zap it
return [
'date' => $date,
'dt' => $dt,
'abbr' => $datetime->format('T'),
'speaker' => $speaker,
'live' => $row->option_value ?? '', // live link to youtube
'youtube' => $youtube, // youtube edited video
'slug' => $slug,
'page' => $page,
'topic' => $topic,
'internal' => $row->mi_id ?? '', // our internal version
];
}
// return all the info required for the bot
private function _chatbot_wed() {
global $wpdb;
$result = [
'ct' => time(),
];
// determine date/time of last class from the calendar
$today = date('Y-m-d');
$sql = <<<BLOCK
select *
from wp_spiffy_calendar
where event_begin<"$today"
and event_title="Bible Class"
order by event_begin desc
limit 1
BLOCK;
$event = $wpdb->get_row($sql);
$result['prev'] = $this->_chatbot_getEventInfo($event); // get class info
$current_link = get_option( 'youtubeschedule-link', '');
$dow = strtolower(date('D'));
if ($dow != 'wed') $current_link = '';
if ($result['prev']['live'] == $current_link) {
$result['prev']['live'] = '';
} else {
$result['youtube'] = $current_link;
}
$sql = <<<BLOCK
select *
from wp_spiffy_calendar
where event_begin>="$today"
and event_title="Bible Class"
order by event_begin
limit 1
BLOCK;
$event = $wpdb->get_row($sql);
$info = $this->_chatbot_getEventInfo($event);
if ($current_link != '') {
// we are live
$result['now'] = $info;
} else {
$result['next'] = $info;
$result['next']['live'] = '';
}
return $result;
}
private function _chatbot_sun() {
$data = [];
// last service
$current_link = get_option( 'youtubeschedule-link', '');
$stored_link = get_option( 'youtubeschedule-link-sun', '');
// youtubeschedule-link-sun -- active youtube
if ($current_link != '' && $current_link == $stored_link) {
// current service -
$data['current'] = $stored_link;
} elseif ($stored_link != '') {
$data['last'] = $stored_link;
}
// "/members/current" page
$current = get_option('media_current');
$title = date('F j', $current['date']) . ': ' . $current['speaker'];
$data['active'] = [
'title' => $title,
'date' => gmdate('Y.m.d', $current['date']), // filename
];
return $data;
}
}
new scheduler_class();