The Broadcast Scheduler will let you automatically change your programming during the week providing a greater range
of content for your audience and in turn, a more interesting station. Your listeners can also see what your broadcast
will be doing, be it a playlist rotation, or an upcoming Live show, for up to a week in advance using the new
schedule/calendar feature accessable from the station page.
Broadcast Scheduler is primarily for "Basic Mode" broadcasters or broadcasters that
switch back and forth between Live and Basic Modes.
Sample one-week schedule...
Scheduler is included in the Premium and PRO Broadcaster Packages. Need an upgrade? (more details)
%} else {
% if ($is_oda && $allow_edit_mode) {
Broadcast Scheduler is primarily for "Basic Mode" broadcasters or broadcasters that switch back and forth
between Live and Basic Modes. This station is an "On-Demand Audio (ODA)" station. ODA tracks are available
all the time, on-demand. They do not need to be scheduled.
% } elsif ($allow_edit_mode) {
To create a new scheduled playlist event, click the "New Event" button. To edit or delete an existing event,
click (edit)(delete) associated with the particular event below.
Note: Please allow 5-10 minutes for your changes to appear in the directory.
% }
Sun.
Mon.
Tue.
Wed.
Thur.
Fri.
Sat.
% ##DEFAULT EVENT START
% if ($default[0]->{'EVENT_NAME'}) {
<% CGI::unescape($default[0]->{'EVENT_NAME'}) %>
% if ($allow_edit_mode) {
(edit)
% }
<% CGI::unescape($default[0]->{'DESCRIPTION'})%>
% if (!$psuedo_default) {
(Default program playing in rotation when there are no other scheduled events)
% }
% } elsif ($nodata && $nodefaultdata) {
There are no scheduled calendar events.
% }
% ## DEFAULT EVENT END
% if ($psuedo_default && $on_air eq 'On') {
On The Air
There are no scheduled calendar events.
% }
<& .drawEvent, rday=> \@sun , editmode=>$allow_edit_mode, clocktype=> $clocktype &>
Default Broadcast (plays in rotation when there are no other scheduled events)
Recurring event (daily or weekly)
One-time event
[Live]
Live or Relay Broadcast
%} ## END OF UPSELL MESSAGE IF-BLOCK
% if (($site ne '..' && $customSkins eq 'N') || $site eq '..') {
% }
% if (($site ne '..' && $customSkins eq 'N') || ($site eq '..')) {
% }
%#########################################
%# arguments passed to this page
%#########################################
<%args>
$stationname => ''
$console => '0' ## FOR PRO ADMIN PANEL? (NOT IMPLEMENTED)
$site => '..' ## FOR PRO SKINNING
$edit => 0 ## SWITCHES BROADCASTER EDIT-MODE
$delete => '' ## EVENT TO DELETE
$action => '' ## FOR START/STOP
$confirm => '' ## FOR SUCCESS MESSAGING FROM THE EVENT-EDIT PAGE
$delta => 0 ## time zone shift value
# these are for debugging
$debug=> '0'
$tables => '0'
$weeks => '0'
%args>
%##############################################
%# initialization routine
%##############################################
<%init>
use LiveLib;
use LiveSched;
use LiveACL;
use CGI ':standard';
use CGI::Cookie;
use Broadcast;
use LiveConf;
use Time::gmtime;
## hack to fix skinning within the new station page template system
$site = '..' if ($site eq 'live365' || !$site);
my $q = new CGI('');
my $ds = 0; #DAYLIGHT SAVINGS FOR START/STOP -- THIS IS NOT BEING USED CURRENTLY, AND WILL BE HARD-CODED TO ZERO
my $customSkins = '';
my $member_name = '';
my $station_name = $stationname;
my $session_key = '';
my $access_level = 0;
my $netcaster = '';
my $calendarClass = 'calendar-body';
my $is_oda = 0;
my $station_type = '';
my $tm = time;
my $station_ID = '';
my $station_title = '';
my $show_page = '1';
my $premium_broadcaster = 0;
my $validated = '';
my $b_info;
my $orderform_link = "https://$LIVECONF{'Billing::server_billmax'}/orders/orderform.live?tm=$tm";
# DETERMINES LISTENER VIEW VS. BROADCASTER-EDIT MODE, IN CONJUNCTION WITH 'edit' PARAM
my $allow_edit_mode = 0;
my $show_edit_link = 0;
#FOR SCHEDULED EVENTS
my ($rc, $msg, $response);
my @data;
my $size_data;
#FOR DEFAULT EVENT
my ($rc2, $msg2, $response2);
my @data2;
my $size_data2;
my @events;
my @default;
my $sched_active = 0;
my ($delete_rc, $delete_msg);
my $run_rc = 0;
my $run_msg = 'Success';
my $nodata = 0;
my $nodefaultdata = 0;
# MESSAGE BOX
my $error_severity = 0;
my $error_title = '';
my $error_message = '';
#WEEKDAY ARRAYS
my @mon;
my @tues;
my @weds;
my @thurs;
my @fri;
my @sat;
my @sun;
my $RECURS_ONCE = 0;
my $RECURS_DAILY = 1;
my $RECURS_WEEKLY = 2;
# Skinning
my $skin_color;
my $on_air = 'Off';
my $ecast_server;
my $psuedo_default = 0;
#
# Read cookie for timezone gmt offset for date munging
#
my $tzcookie = &LiveLib::get_cookie_ex('box_mc', 'tz');
my $localtz_offset = -5;
my $clocktype = 12;
my $has_ds;
if ($tzcookie) {
($localtz_offset, $clocktype, $has_ds) = split(/:/, $tzcookie);
}
$localtz_offset = CGI::unescape($localtz_offset) * 3600; ##convert to seconds
#
# Cleanup input
#
$station_name = lc CGI::unescape($station_name);
$delete = CGI::unescape($delete); ## cleans up extra escapes needed for NS4.7x BLECH.
my %stream;
my %station;
my %active;
my $dbh = &LiveLib::open_database();
#
# Now confirm username and password (but you don't have to be logged in).
#
($rc, $msg, $member_name) = &LiveLib::verify_member($q, $dbh);
#
# If you are logged in, see if you're a staff member of another station.
#
if ($rc == 0) {
my $sn;
my $lvl;
($rc, $msg, $member_name, $sn, $session_key, $lvl) = &LiveACL::get_member_and_station($dbh, 2, 'schedule_event');
if ($rc == 0 && $sn) { # update station_name if ACL call successful
unless ($station_name) { # caller didn't specify a station; assume he wants to edit
$station_name = $sn;
}
$show_edit_link = ($sn eq $station_name);
$access_level = $lvl;
}
elsif ($member_name) { # logged-in user is editing if he's viewing his own station
if (!$station_name) {
$station_name = $member_name;
}
$show_edit_link = ($member_name eq $station_name);
}
}
unless ($station_name) {
print $q->redirect("/listen/index.live");
exit;
}
$b_info = &Broadcast::init_broadcast_info($dbh, $station_name, 'STA|STR|ACT|MEM|PRO');
unless ($b_info) {
print $q->redirect("/listen/index.live");
exit;
}
%stream = &Broadcast::get_broadcast_info($b_info, 'STR');
%station = &Broadcast::get_broadcast_info($b_info, 'STA');
%active = &Broadcast::get_broadcast_info($b_info, 'ACT');
if (%active) {
$on_air = 'On';
}
if (%stream) {
$customSkins = $stream{'CUSTOM_SKINS'}; # CUSTOM SKINS (N) (B) OR (P)
}
#
# THIS NEEDS TO BE FIXED FOR STATION PAGE TEMPLATE SYSTEM!!!!
#
$site = '..' if ($site eq 'wmp'); ## DON'T TRY TO PARSE 'wmp' AS PRO SKIN
if ($site ne '..') { ## USE FLAG VS. '..'
if ($customSkins eq 'P' || $customSkins eq 'B') {
$skin_color = "/scp/plr/station.css"; ## UPDATE AND USE /scp/pro/$site/local.css
}
else {
$skin_color = "/scp/station.css"; ## UPDATE AND USE /scp/live365/local.css
}
}
$netcaster = &Broadcast::netcaster($b_info);
if (!$netcaster) {
$show_edit_link = 0;
}
my %profile = &Broadcast::get_broadcast_info($b_info, 'PRO');
my $profile_status = $profile{'STATUS'};
$station_type = &Broadcast::station_type($b_info); #(PER)sonal or (PRO)fessional
$premium_broadcaster = &Broadcast::premium_broadcaster($b_info);
$station_title = $station{'TITLE'};
$station_ID = $station{'STATION_ID'}; # reverse lookup to link back to the station page, etc.
$is_oda = ($stream{'SERVER_MODE'} eq 'OD');
my $pool = $stream{'ASSIGNED_SERVER_POOL'};
$ecast_server = $LIVECONF{"Easycast::server_$pool"};
#
# User has requested to edit. Only allowed if he's proven he has rights.
#
if ($edit) {
$edit = $show_edit_link;
}
if ($show_edit_link) {
#
# Station status flag
#
($error_title, $error_message, $show_page, $error_severity) = &Broadcast::disallow_broadcaster($b_info, 0);
unless ($error_title) {
$allow_edit_mode = $edit; # this obfuscates the $edit param so only bcasters can actually edit stuff
}
}
#
# Broadcaster control functions
#
if ($allow_edit_mode) {
#
# Delete event if any is passed in
#
if ($delete ne '') {
($delete_rc, $delete_msg) = &LiveSched::delete_event($dbh, $station_name, $delete);
if ($delete_rc == 2) {
$error_severity = 'error';
$error_title = 'Error Deleting Event!';
$error_message = $delete_msg . " Please refresh your browser, and try again. ($delete_msg)";
}
else {
$error_severity = 'success';
$error_title = 'Event Deleted';
$delete_msg =~ s/deleting (.+)/Deleting "$1"/g; # make pretty the raw api message
$error_message = CGI::unescape($delete_msg);
}
}
#
# Start the scheduler
#
elsif ($action =~ /on|delay|set_station_tz/) {
#
# DST shifts - use given TZ and offset to update all of a station's events before
# restarting scheduler.
#
if ($action eq 'set_station_tz') {
my $time_zone = -$localtz_offset + $delta;
if ($time_zone > 43200) { # past the Int'l Date Line, add/subtract 25 hours to keep in range
$time_zone -= 25*3600;
}
elsif ($time_zone < -43200) {
$time_zone += 25*3600;
}
($run_rc, $run_msg) = &LiveSched::update_station_time_zone($dbh, $station_name, $time_zone);
if ($run_rc == 0) {
$action = 'on';
}
}
if ($run_rc == 0) {
($run_rc, $run_msg) = &LiveSched::start($station_name, $action, $ds);
}
if ($run_rc != 0) {
$error_severity = 'error';
$error_title = 'Error';
$error_message = "There was an error starting the scheduler. Please try stopping your schedule, and then attempt to restart it. ($run_msg)";
}
else {
$error_severity = 'success';
$error_title = 'Success';
$error_message = 'Your Schedule has been successfully updated. Please allow 5-10 minutes for this change to appear in the directory.
Your broadcast is currently "'.$on_air.' The Air" (change) ';
}
}
#
# Stop the scheduler
#
elsif ($action eq 'off') {
($run_rc, $run_msg) = &LiveSched::start($station_name, $action, $ds);
if ($run_rc != 0) {
$error_severity = 'error';
$error_title = 'Error';
$error_message = "There was an error stopping the scheduler. Please refresh your browser, and try again. ($run_msg)";
}
else{
$error_severity = 'success';
$error_title = 'Success';
$error_message = 'Your Schedule was stopped successfully. Please allow 5-10 minutes for this change to appear in the directory.';
}
}
}
#
# Get scheduler event data, either for listener's view or broadcaster's edit mode
#
if (!$is_oda) { ##ODA's CAN'T USE THE SCHEDULER, SO DON'T BOTHER WITH THE DB HIT
if ($allow_edit_mode) {
#
# Gets programmed data from gui table
#
($rc, $msg, $response) = &LiveSched::get_broadcaster_events('NOHEADER', $station_name);
}
else {
#
# gets "live" data from daemon table
#
($rc, $msg, $response) = &LiveSched::get_listener_events('NOHEADER', $station_name);
}
}
if ($response =~/Generic error/) {
$nodata = 1;
}
elsif ($rc != 0) {
$error_severity = 'error';
$error_title = 'Error Getting Scheduler Data';
$error_message = "There was an error getting data from the scheduler. Please refresh your browser, and try again. (". CGI::unescape($msg).")";
}
else {
$response=~ s/'/'/g;
@data = split(/<\/EVENT>/, $response); ## split up into individual events
pop @data;
$size_data = @data;
my $count = 0;
#
# Parse content out of each data element
#
foreach my $data_chunk (@data) {
my $station_name;
my $status;
my $start_time;
my $time_zone;
my $recurrence;
my $description;
my $priority;
my $duration;
my $event_name;
my $event_type;
my $playlist_name;
my $recurrence_info;
my $next_activation;
if ($data_chunk=~ /<\/STATION_NAME>/) {
$station_name = $1;
}
if ($data_chunk=~/(.*)<\/STATUS>/) {
$status = $1;
}
if ($data_chunk=~/(.*)<\/START_TIME>/) {
$start_time = $1;
}
if ($data_chunk=~/(.*)<\/TIME_ZONE>/) {
$time_zone = $1;
}
if ($data_chunk=~/(.*)<\/RECURRENCE>/) {
$recurrence = $1;
}
if ($data_chunk=~/<\/DESCRIPTION>/) {
$description = $1;
}
if ($data_chunk=~/(.*)<\/PRIORITY>/) {
$priority = $1;
}
if ($data_chunk=~/(.*)<\/DURATION>/) {
$duration = $1;
}
if ($data_chunk=~/<\/EVENT_NAME>/) {
$event_name = $1;
}
if ($data_chunk=~/(.*)<\/EVENT_TYPE>/) {
$event_type = $1;
}
if ($data_chunk=~/<\/PLAYLIST_NAME>/) {
$playlist_name = $1;
}
if ($data_chunk=~/(.*)<\/RECURRENCE_INFO>/) {
$recurrence_info = $1;
}
if ($data_chunk=~/(.*)<\/NEXT_ACTIVATION>/) {
$next_activation = $1;
}
my $key = $count++;
$events[$key] = {
'STATION_NAME' => $station_name,
'STATUS' => $status,
'START_TIME' => $start_time,
'TIME_ZONE' => $time_zone,
'RECURRENCE' => $recurrence,
'DESCRIPTION' => $description,
'PRIORITY' => $priority,
'DURATION' => $duration,
'EVENT_NAME' => $event_name,
'EVENT_TYPE' => $event_type,
'PLAYLIST_NAME' => $playlist_name,
'RECURRENCE_INFO' => $recurrence_info,
'LOCAL_START_TIME' => $start_time,
'NEXT_ACTIVATION' => $next_activation,
};
#
# For non-edit situations, the data coming out of the DAEMON table is in London time (GMT).
# This means we need to adjust the time-of-day and, in fact, the day-of-week to account for
# the viewer's local timezone settings.
#
if (!$edit) {
my $tm = gmtime($next_activation + $localtz_offset);
$events[$key]{'RECURRENCE_INFO'} = ('su','mo','tu','we','th','fr','sa')[$tm->wday];
$events[$key]{'LOCAL_START_TIME'} = ($tm->hour*3600 + $tm->min*60 + $tm->sec);
}
##PARSE SCHEDULER EVENT DATA INTO WEEKDAY ARRAYS
if ($events[$key]{'RECURRENCE'} eq $RECURS_DAILY || lc($events[$key]{'RECURRENCE_INFO'}) eq 'su') {
push(@sun, $events[$key]);
}
if ($events[$key]{'RECURRENCE'} eq $RECURS_DAILY || lc($events[$key]{'RECURRENCE_INFO'}) eq 'mo') {
push(@mon, $events[$key]);
}
if ($events[$key]{'RECURRENCE'} eq $RECURS_DAILY || lc($events[$key]{'RECURRENCE_INFO'}) eq 'tu') {
push(@tues, $events[$key]);
}
if ($events[$key]{'RECURRENCE'} eq $RECURS_DAILY || lc($events[$key]{'RECURRENCE_INFO'}) eq 'we') {
push(@weds, $events[$key]);
}
if ($events[$key]{'RECURRENCE'} eq $RECURS_DAILY || lc($events[$key]{'RECURRENCE_INFO'}) eq 'th') {
push(@thurs, $events[$key]);
}
if ($events[$key]{'RECURRENCE'} eq $RECURS_DAILY || lc($events[$key]{'RECURRENCE_INFO'}) eq 'fr') {
push(@fri, $events[$key]);
}
if ($events[$key]{'RECURRENCE'} eq $RECURS_DAILY || lc($events[$key]{'RECURRENCE_INFO'}) eq 'sa') {
push(@sat, $events[$key]);
}
}#end of foreach loop
}#end of if block
### GET SCHEDULER DEFAULT DATA
my $use_daemon_table = 1;
if (!$is_oda) { ##ODA's CAN'T USE THE SCHEDULER, SO DON'T BOTHER WITH THE DB HIT
if ($allow_edit_mode) {
#GETS PROGRAMMED DATA FROM GUI TABLE
$use_daemon_table = 0;
}
else {
#GETS "LIVE" DATA FROM DAEMON TABLE
$use_daemon_table = 1;
}
}
($rc2, $msg2, $response2) = &LiveSched::get_default('NOHEADER', $station_name, $use_daemon_table);
if ($response2 =~/Generic error/) {
$nodefaultdata = 1;
##PLUG CURRENT PLAYLIST FROM ACTIVE_STREAMS HERE IF EXISTS
if (!$edit) {
$psuedo_default = 1;
$default[0] = {
'DESCRIPTION' => $active{'DESCRIPTION'},
'EVENT_NAME' => $active{'TITLE'},
};
}
}
elsif ($rc2 != 0) {
$error_severity = 'error';
$error_title = 'Error Getting Scheduler Data';
$error_message = "There was an error getting data from the scheduler. Please refresh your browser, and try again. (". CGI::unescape($msg2).")";
}
else {
$response2=~ s/'/'/g;
$data2[0] = $response2;
$size_data2 = @data2;
my $count = 0;
### PARSE CONTENT OUT OF EACH DATA ELEMENT
foreach my $data_chunk (@data2) {
$data_chunk=~ /<\/STATION_NAME>/;
my $station_name = $1;
$data_chunk=~/(.+)<\/STATUS>/;
my $status = $1;
$data_chunk =~/(.+)<\/START_TIME>/;
my $start_time = $1;
$data_chunk =~/(.+)<\/TIME_ZONE>/;
my $timezone = $1;
$data_chunk =~/(.+)<\/RECURRENCE>/;
my $recurrence = $1;
$data_chunk =~/<\/DESCRIPTION>/;
my $description = $1;
$data_chunk=~/(.+)<\/PRIORITY>/;
my $priority = $1;
my $event_name;
if ($edit) {
## FORMAT THE REGEXP FOR THE GUI DATA
$data_chunk=~/<\/EVENT_NAME>/;
$event_name = $1;
}
else {
## FORMAT THE REGEXP FOR THE DAEMON DATA -- THIS HANDLES THE DEFAULT-EVENT 'CLONING'
$data_chunk=~/<\/EVENT_NAME>/;
$event_name = $1;
}
$data_chunk=~/(.+)<\/EVENT_TYPE>/;
my $event_type = $1;
$data_chunk=~/(.+)<\/PLAYLIST_NAME>/;
my $playlist_name = $1;
$data_chunk=~/(.+)<\/RETURN_CODE>/;
my $return_code = $1;
my $key = $count++;
$default[$key] = {
'STATION_NAME' => $station_name,
'STATUS' => $status,
'START_TIME' => $start_time,
'TIME_ZONE' => $timezone,
'RECURRENCE' => $recurrence,
'DESCRIPTION' => $description,
'PRIORITY' => $priority,
'EVENT_NAME' => $event_name,
'EVENT_TYPE' => $event_type,
'PLAYLIST_NAME' => $playlist_name,
'RETURN_CODE' => $return_code
};
} #end of foreach block
} #end of rc2 if block
if ($nodata && $nodefaultdata) {
$calendarClass = 'table-body';
}
#
# Confirmation messages triggered from the event-edit page upon successful update
#
if ($confirm == 1) {
$error_severity = 'success';
$error_title = 'Success ';
$error_message = 'Your scheduled event has successfully been added or updated.';
}
%init>
<%cleanup>
if ($dbh) {
&LiveLib::close_database($dbh);
}
%cleanup>
<%def .drawEvent>
<%args>
$rday=>''
$editmode => 0
$clocktype => 12
%args>
% my @day = @$rday;
% my $event_color = "calendar-recurring";
% my $icon_name = '';
% my $alt = '';
% if ($editmode) {
% @day = sort { $a->{'START_TIME'} <=> $b->{'START_TIME'} || $b->{'PRIORITY'} <=> $a->{'PRIORITY'} } @day;
% } else {
% @day = sort { $a->{'LOCAL_START_TIME'} <=> $b->{'LOCAL_START_TIME'} || $b->{'PRIORITY'} <=> $a->{'PRIORITY'} } @day;
% }
% foreach my $d (@day) {
% if ($d->{'RECURRENCE'} == 0) { ## 0=ONCE, 1=DAILY, 2=WEEKLY
% $icon_name = "icon-onetime";
% $alt = "One-time Event";
% $event_color = "calendar-onetime";
% } else {
% $icon_name = 'icon-recurring';
% $alt = "Recurring Event";
% $event_color = "calendar-recurring";
% }