Files
racalmas/website/agenda/planung/calendar.cgi
Milan fd952dadfa events.pm: load recordings for params
in the past all recordings have been loaded. At some point this has been
changed to load only active recordings. Now there are params supported
for both forms

all_recordings - all recordings for a broadcast
active_recording - add path of active recordings to broadcast
only_active_recording - show only broadcasts with active recordings
2024-04-18 23:19:54 +02:00

2031 lines
68 KiB
Perl
Executable File

#!/usr/bin/perl
use strict;
use warnings;
no warnings 'redefine';
use utf8;
use Data::Dumper;
use URI::Escape();
use DateTime();
use utf8();
use params();
use config();
use entry();
use log();
use entry();
use template();
use calendar();
use auth();
use uac();
use project();
use studios();
use events();
use series();
use series_dates();
use markup();
use localization();
use studio_timeslot_dates();
use work_dates();
use playout();
use user_settings();
use audio_recordings();
use audio();
use user_day_start();
binmode STDOUT, ":utf8";
my $r = shift;
( my $cgi, my $params, my $error ) = params::get($r);
my $config = config::get('../config/config.cgi');
my ( $user, $expires ) = auth::get_user( $config, $params, $cgi );
return if ( !defined $user ) || ( $user eq '' );
$config->{user} = $user;
my $user_presets = uac::get_user_presets(
$config,
{
user => $user,
project_id => $params->{project_id},
studio_id => $params->{studio_id}
}
);
$params->{default_studio_id} = $user_presets->{studio_id};
$params = uac::setDefaultStudio( $params, $user_presets );
$params->{expires} = $expires;
my $scriptName = 'calendar.cgi';
#add "all" studio to select box
unshift @{ $user_presets->{studios} },
{
id => -1,
name => '-all-'
};
# select studios, TODO: do in JS
if ( $params->{studio_id} eq '-1' ) {
for my $studio ( @{ $user_presets->{studios} } ) {
delete $studio->{selected};
$studio->{selected} = 1 if $params->{studio_id} eq $studio->{id};
}
}
my $request = {
url => $ENV{QUERY_STRING} || '',
params => {
original => $params,
checked => check_params( $config, $params ),
},
};
$request = uac::prepare_request( $request, $user_presets );
$params = $request->{params}->{checked};
if (
(
( defined $params->{action} ) && ( ( $params->{action} eq 'show' )
|| ( $params->{action} eq 'edit_event' ) )
)
|| ( $params->{part} == 1 )
)
{
print "Content-type:text/html; charset=UTF-8;\n\n";
} else {
#process header
my $headerParams = uac::set_template_permissions( $request->{permissions}, $params );
$headerParams->{loc} = localization::get( $config, { user => $user, file => 'menu' } );
template::process( $config, 'print', template::check( $config, 'calendar-header.html' ),
$headerParams );
if ( $params->{list} eq '1' ) {
print q{
<script src="js/jquery.tablesorter.min.js"></script>
<style>#content{ top:5rem; position:relative; }</style>
};
}
}
if ( defined $user_presets->{error} ) {
print "<br><br>";
uac::print_error( $user_presets->{error} );
return;
}
$config->{access}->{write} = 0;
unless ( defined $params->{project_id} ) {
uac::print_error("Please select a project");
return;
}
if ( $params->{project_id} ne '-1' ) {
if ( project::check( $config, { project_id => $params->{project_id} } ) ne '1' ) {
uac::print_error("invalid project");
return;
}
}
unless ( defined $params->{studio_id} ) {
uac::print_error("Please select a studio");
return;
}
if ( $params->{studio_id} ne '-1' ) {
if ( studios::check( $config, { studio_id => $params->{studio_id} } ) ne '1' ) {
uac::print_error("invalid studio");
return;
}
}
my $start_of_day = $params->{day_start};
my $end_of_day = $start_of_day;
$end_of_day += 24 if ( $end_of_day <= $start_of_day );
our $hour_height = 60;
our $yzoom = 1.5;
showCalendar(
$config, $request,
{
hour_height => $hour_height,
yzoom => $yzoom,
start_of_day => $start_of_day,
end_of_day => $end_of_day,
}
);
sub showCalendar {
my $config = shift;
my $request = shift;
my $cal_options = shift;
my $hour_height = $cal_options->{hour_height};
my $yzoom = $cal_options->{yzoom};
my $start_of_day = $cal_options->{start_of_day};
my $end_of_day = $cal_options->{end_of_day};
my $params = $request->{params}->{checked};
my $permissions = $request->{permissions} || {};
unless ( $permissions->{read_series} == 1 ) {
uac::permissions_denied('read_series');
return;
}
#get range from user settings
my $user_settings = user_settings::get( $config, { user => $params->{presets}->{user} } );
$params->{range} = $user_settings->{range} unless defined $params->{range};
$params->{range} = 28 unless defined $params->{range};
#get colors from user settings
print user_settings::getColorCss( $config, { user => $params->{presets}->{user} } )
if $params->{part} == 0;
$params->{loc} =
localization::get( $config, { user => $params->{presets}->{user}, file => 'all,calendar' } );
my $language = $user_settings->{language} || 'en';
$params->{language} = $language;
print localization::getJavascript( $params->{loc} ) if $params->{part} == 0;
my $calendar = getCalendar( $config, $params, $language );
my $options = {};
my $events = [];
if ( ( $params->{part} == 1 ) || ( $params->{list} == 1 ) ) {
#set date range
my $from = $calendar->{from_date};
my $till = $calendar->{till_date};
my $project_id = $params->{project_id};
my $studio_id = $params->{studio_id};
#build event filter
$options = {
project_id => $project_id,
template => 'html',
limit => 600,
#get => 'no_content',
from_date => $from,
till_date => $till,
date_range_include => 1,
archive => 'all',
};
# set options depending on switches
if ( $params->{studio_id} ne '-1' ) {
$options->{studio_id} = $studio_id;
my $location = $params->{presets}->{studio}->{location};
$options->{location} = $location if $location =~ /\S/;
}
if ( $params->{project_id} ne '-1' ) {
$options->{project_id} = $project_id;
my $project = $params->{presets}->{project}->{name};
$options->{project} = $project if $project =~ /\S/;
}
if ( defined $params->{series_id} ) {
$options->{series_id} = $params->{series_id};
delete $options->{from_date};
delete $options->{till_date};
delete $options->{date_range_include};
}
if ( $params->{search} =~ /\S/ ) {
if ( $params->{list} == 1 ) {
$options->{search} = $params->{search};
delete $options->{from_date};
delete $options->{till_date};
delete $options->{date_range_include};
}
}
$options->{from_time} = '00:00' if defined $options->{from_date};
$options->{draft} = 0 unless $params->{list} == 1;
#get events sorted by date
$events = getSeriesEvents( $config, $request, $options, $params );
unless ( $params->{list} == 1 ) {
for my $event (@$events) {
$event->{origStart} = $event->{start};
$event->{origContent} = $event->{origContent};
}
$events = break_dates( $events, $start_of_day );
}
# recalc after break (for list only?)
for my $event (@$events) {
delete $event->{day};
delete $event->{start_date};
delete $event->{end_date};
$event = events::calc_dates( $config, $event );
}
my $events_by_start = {};
for my $event (@$events) {
$events_by_start->{ $event->{start} } = $event;
}
#build series filter
$options = {
project_id => $project_id,
studio_id => $studio_id,
from => $from,
till => $till,
date_range_include => 1,
exclude => 0
};
if ( defined $params->{series_id} ) {
$options->{series_id} = $params->{series_id};
delete $options->{from};
delete $options->{till};
delete $options->{date_range_include};
}
if ( $params->{search} =~ /\S/ ) {
$options->{search} = $params->{search};
if ( $params->{list} == 1 ) {
delete $options->{from};
delete $options->{till};
delete $options->{date_range_include};
}
}
#get all series dates
my $series_dates = series_dates::get_series( $config, $options );
my $id = 0;
for my $date (@$series_dates) {
$date->{schedule} = 1;
#$date->{event_id}=-1;
$date->{event_id} = $id;
$date->{origStart} = $date->{start};
delete $date->{day};
delete $date->{start_date};
delete $date->{end_date};
$id++;
}
unless ( $params->{list} == 1 ) {
$series_dates = break_dates( $series_dates, $start_of_day );
}
#merge series and events
for my $date (@$series_dates) {
$date = events::calc_dates( $config, $date );
push @$events, $date;
}
#get timeslot_dates
my $studio_dates = studio_timeslot_dates::get( $config, $options );
$id = 0;
for my $date (@$studio_dates) {
$date->{grid} = 1;
$date->{series_id} = -1;
#$date->{event_id}=-1;
$date->{event_id} = $id;
$date->{origStart} = $date->{start};
delete $date->{day};
delete $date->{start_date};
delete $date->{end_date};
$id++;
}
unless ( $params->{list} == 1 ) {
$studio_dates = break_dates( $studio_dates, $start_of_day );
}
for my $date (@$studio_dates) {
$date = events::calc_dates( $config, $date );
push @$events, $date;
}
#get work_dates
my $work_dates = work_dates::get( $config, $options );
for my $date (@$work_dates) {
$date->{work} = 1;
$date->{series_id} = -1;
$date->{event_id} = -1;
$date->{origStart} = $date->{start};
delete $date->{day};
delete $date->{start_date};
delete $date->{end_date};
}
unless ( $params->{list} == 1 ) {
$work_dates = break_dates( $work_dates, $start_of_day );
}
for my $date (@$work_dates) {
$date = events::calc_dates( $config, $date );
push @$events, $date;
}
#get playout
delete $options->{exclude};
my $playout_dates = playout::get_scheduled( $config, $options );
$id = 0;
for my $date (@$playout_dates) {
my $format = undef;
if ( defined $date->{'format'} ) {
$format =
( $date->{'format'} || '' ) . " "
. ( $date->{'format_version'} || '' ) . " "
. ( $date->{'format_profile'} || '' );
$format =~ s/MPEG Audio Version 1 Layer 3/MP3/g;
$format .= ' ' . ( $date->{'format_settings'} || '' )
if defined $date->{'format_settings'};
$format .= '<br>';
}
$date->{play} = 1;
$date->{series_id} = -1;
$date->{event_id} = $id;
$date->{title} = '';
$date->{title} .= '<b>errors</b>: ' . $date->{errors} . '<br>'
if defined $date->{errors};
$date->{title} .= audio::formatDuration(
$date->{duration},
$date->{event_duration},
sprintf( "duration: %.1g h", $date->{duration} / 3600 ) . "<br>",
sprintf( "%d s", $date->{duration} )
) if defined $date->{duration};
$date->{title} .= audio::formatLoudness( $date->{rms_left}, 'L: ' ) . ', '
if defined $date->{rms_left};
$date->{title} .= audio::formatLoudness( $date->{rms_right}, 'R: ' ) . '<br>'
if defined $date->{rms_right};
$date->{title} .= audio::formatBitrate( $date->{bitrate} ) if defined $date->{bitrate};
$date->{title} .= ' ' . audio::formatBitrateMode( $date->{bitrate_mode} ) . '<br>'
if defined $date->{bitrate_mode};
$date->{title} .=
'<b>replay gain</b> ' . sprintf( "%.1f", $date->{replay_gain} ) . '<br>'
if defined $date->{replay_gain};
$date->{title} .= audio::formatSamplingRate( $date->{sampling_rate} )
if defined $date->{sampling_rate};
$date->{title} .= audio::formatChannels( $date->{channels} ) . '<br>'
if defined $date->{channels};
$date->{title} .= int( ( $date->{'stream_size'} || '0' ) / ( 1024 * 1024 ) ) . 'MB<br>'
if defined $date->{'stream_size'};
$date->{title} .= $format if defined $format;
$date->{title} .= '<b>library</b>: ' . ( $date->{writing_library} || '' ) . '<br>'
if defined $date->{'writing_library'};
$date->{title} .= '<b>path</b>: ' . ( $date->{file} || '' ) . '<br>'
if defined $date->{file};
$date->{title} .= '<b>updated_at</b>: ' . ( $date->{updated_at} || '' ) . '<br>'
if defined $date->{updated_at};
$date->{title} .= '<b>modified_at</b>: ' . ( $date->{modified_at} || '' ) . '<br>'
if defined $date->{modified_at};
$date->{rms_image} = URI::Escape::uri_unescape( $date->{rms_image} )
if defined $date->{rms_image};
$date->{origStart} = $date->{start};
# set end date seconds to 00 to handle error at break_dates/join_dates
$date->{end} =~ s/(\d\d\:\d\d)\:\d\d/$1\:00/;
delete $date->{day};
delete $date->{start_date};
delete $date->{end_date};
$id++;
}
unless ( $params->{list} == 1 ) {
$playout_dates = break_dates( $playout_dates, $start_of_day );
}
for my $date (@$playout_dates) {
$date = events::calc_dates( $config, $date );
if ( defined $events_by_start->{ $date->{start} } ) {
$events_by_start->{ $date->{start} }->{duration} = $date->{duration} || 0;
$events_by_start->{ $date->{start} }->{event_duration} =
$date->{event_duration} || 0;
$events_by_start->{ $date->{start} }->{rms_left} = $date->{rms_left} || 0;
$events_by_start->{ $date->{start} }->{rms_right} = $date->{rms_right} || 0;
$events_by_start->{ $date->{start} }->{playout_modified_at} = $date->{modified_at};
$events_by_start->{ $date->{start} }->{playout_updated_at} = $date->{updated_at};
$events_by_start->{ $date->{start} }->{file} = $date->{file};
}
push @$events, $date;
}
# series dates
if ($params->{list} == 1 and defined $options->{series_id}){
my $series = series::get(
$config,
{
#project_id => $project_id,
#studio_id => $studio_id,
series_id => $options->{series_id}
}
);
if ( defined $series->[0] and $series->[0]->{predecessor_id}
and $series->[0]->{predecessor_id} ne $series->[0]->{id} ){
my $events2 = getSeriesEvents( $config, $request, {
series_id => $series->[0]->{predecessor_id}
}, $params );
for my $event (@$events2) {
delete $event->{day};
delete $event->{start_date};
delete $event->{end_date};
push @$events, events::calc_dates( $config, $event );
}
}
}
}
#output
printToolbar( $config, $params, $calendar ) if $params->{part} == 0;
#if($params->{part}==1){
print qq{
<script>
var current_date="$calendar->{month} $calendar->{year}";
var previous_date="$calendar->{previous_date}";
var next_date="$calendar->{next_date}";
</script>
};
#}
#filter events by time
unless ( $params->{list} == 1 ) {
$events = filterEvents( $events, $options, $start_of_day );
}
#sort events by start
@$events = sort { $a->{start} cmp $b->{start} } @$events;
#separate by day (e.g. to 6 pm)
my $events_by_day = {};
for my $event (@$events) {
my $day =
time::datetime_to_date( time::add_hours_to_datetime( $event->{start}, -$start_of_day ) );
push @{ $events_by_day->{$day} }, $event;
}
#get min and max hour from all events
unless ( $params->{list} == 1 ) {
my $min_hour = 48;
my $max_hour = 0;
for my $event (@$events) {
if ( $event->{start} =~ /(\d\d)\:\d\d\:\d\d$/ ) {
my $hour = $1;
$hour += 24 if $hour < $start_of_day;
$min_hour = $hour if ( $hour < $min_hour ) && ( $hour >= $start_of_day );
}
if ( $event->{end} =~ /(\d\d)\:\d\d\:\d\d$/ ) {
my $hour = $1;
$hour += 24 if $hour <= $start_of_day;
$max_hour = $hour if ( $hour > $max_hour ) && ( $hour <= $end_of_day );
}
}
$cal_options->{min_hour} = $min_hour;
$cal_options->{max_hour} = $max_hour;
}
# calculate positions and find schedule errors (depending on position)
for my $date ( sort ( keys %$events_by_day ) ) {
my $events = $events_by_day->{$date};
calc_positions( $events, $cal_options );
find_errors($events);
}
for my $event (@$events) {
next unless defined $event->{uploaded_at};
next
if ( defined $event->{playout_updated_at} )
&& ( $event->{uploaded_at} lt $event->{playout_updated_at} );
}
if ( $params->{list} == 1 ) {
showEventList( $config, $permissions, $params, $events_by_day );
} else {
if ( $params->{part} == 0 ) {
print qq{<div id="calendarTable"> </div>};
}
if ( $params->{part} == 1 ) {
calcCalendarTable( $config, $permissions, $params, $calendar, $events_by_day,
$cal_options );
printTableHeader( $config, $permissions, $params, $cal_options );
printTableBody( $config, $permissions, $params, $cal_options );
}
if ( $params->{part} == 0 ) {
printSeries( $config, $permissions, $params, $cal_options );
print qq{
</main>
};
}
# time has to be set when events come in
printJavascript( $config, $permissions, $params, $cal_options );
if ( $params->{part} == 0 ) {
print qq{
</body>
</html>
};
}
}
}
sub debugDate {
my $date = shift;
$date->{program} = '' unless defined $date->{program};
$date->{series_name} = '' unless defined $date->{series_name};
$date->{title} = '' unless defined $date->{title};
$date->{splitCount} = 0 unless defined $date->{splitCount};
my $dt = ( $date->{start} || '' ) . " " . ( $date->{end} | '' );
my $da = ( $date->{start_date} || '' ) . " " . ( $date->{end_date} || '' );
my $type = "schedule:" . ( $date->{schedule} || "" ) . " grid:" . ( $date->{grid} || "" );
}
# break dates at start_of_day
sub break_dates {
my $dates = shift;
my $start_of_day = shift;
#return $dates if $start_of_day eq '0';
for my $date (@$dates) {
next unless defined $date;
$date->{splitCount} = 0 unless defined $date->{splitCount};
#debugDate($date);
next if $date->{splitCount} > 6;
my $nextDayStart = breaks_day( $date->{start}, $date->{end}, $start_of_day );
next if $nextDayStart eq '0';
# add new entry
my $entry = {};
for my $key ( keys %$date ) {
$entry->{$key} = $date->{$key};
}
$entry->{start} = $nextDayStart;
$entry->{splitCount}++;
push @$dates, $entry;
# print STDERR "add $entry->{start} $entry->{end} count:$entry->{splitCount} $entry->{program}-$entry->{series_name}-$entry->{title}\n";
#modify existing entry
my $start_date = time::datetime_to_date( $date->{start} );
$date->{end} = $nextDayStart;
$date->{splitCount}++;
# print STDERR "set $date->{start} $date->{end} count:$date->{splitCount} $date->{program}-$date->{series_name}-$date->{title}\n";
}
return join_dates( $dates, $start_of_day );
}
# check if event breaks the start of day (e.g. 06:00)
sub breaks_day {
my $start = shift;
my $end = shift;
my $start_of_day = shift;
my $starts = time::datetime_to_array($start);
my $startDate = time::array_to_date($starts);
my $startTime = time::array_to_time($starts);
$start = $startDate . ' ' . $startTime;
my $ends = time::datetime_to_array($end);
my $endDate = time::array_to_date($ends);
my $endTime = time::array_to_time($ends);
$end = $endDate . ' ' . $endTime;
my $dayStartTime = time::array_to_time($start_of_day);
my $dayStart = $startDate . ' ' . $dayStartTime;
# start before 6:00 of same day
return $dayStart if ( $start lt $dayStart ) && ( $end gt $dayStart );
# start before 6:00 of next day
my $nextDayStart = time::add_days_to_datetime( $dayStart, 1 );
#$nextDayStart=~s/:00$//;
return $nextDayStart if ( $start lt $nextDayStart ) && ( $end gt $nextDayStart );
return 0;
}
# merge events with same seriesId and eventId at 00:00
sub join_dates {
my $dates = shift;
my $start_of_day = shift;
return $dates if $start_of_day == 0;
@$dates = sort { $a->{start} cmp $b->{start} } @$dates;
my $prev_date = undef;
for my $date (@$dates) {
next unless defined $date;
unless ( defined $prev_date ) {
$prev_date = $date;
next;
}
if ( ( $date->{event_id} == $prev_date->{event_id} )
&& ( $date->{series_id} == $prev_date->{series_id} )
&& ( $date->{start} eq $prev_date->{end} )
&& ( $date->{start} =~ /00\:00\:\d\d/ ) )
{
$prev_date->{end} = $date->{end};
$date = undef;
next;
}
$prev_date = $date;
}
my $results = [];
for my $date (@$dates) {
next unless defined $date;
push @$results, $date;
}
return $results;
}
sub filterEvents {
my $events = shift;
my $options = shift;
my $start_of_day = shift;
return [] unless defined $options->{from};
return [] unless defined $options->{till};
my $dayStartTime = time::array_to_time($start_of_day);
my $startDatetime = $options->{from} . ' ' . $dayStartTime;
my $endDatetime = $options->{till} . ' ' . $dayStartTime;
my $results = [];
for my $date (@$events) {
next if ( ( $date->{start} ge $endDatetime ) || ( $date->{end} le $startDatetime ) );
push @$results, $date;
}
return $results;
}
sub showEventList {
my $config = shift;
my $permissions = shift;
my $params = shift;
my $events_by_day = shift;
my $language = $params->{language};
my $rerunIcon = qq{<img src="image/replay.svg" title="$params->{loc}->{label_rerun}">};
my $liveIcon = qq{<img src="image/mic.svg" title="$params->{loc}->{label_live}">};
my $draftIcon = qq{<img src="image/draft.svg" title="$params->{loc}->{label_draft}">};
my $archiveIcon = qq{<img src="image/archive.svg" title="$params->{loc}->{label_archived}">};
my $playoutIcon = qq{<img src="image/play.svg">};
my $processingIcon = qq{<img src="image/processsing.svg">};
my $preparedIcon = qq{<img src="image/prepared.svg>};
my $creoleIcon = qq{<img src="image/creole.svg>};
my $out = '';
$out = qq{
<div id="event_list">
<table>
<thead>
<tr>
<th class="day_of_year">$params->{loc}->{label_day_of_year}</th>
<th class="weekday">$params->{loc}->{label_weekday}</th>
<th class="start_date">$params->{loc}->{label_start}</th>
<th class="start_time">$params->{loc}->{label_end}</th>
<th class="series_name">$params->{loc}->{label_series}</th>
<th class="series_id">sid</th>
<th class="title">$params->{loc}->{label_title}</th>
<th class="episode">$params->{loc}->{label_episode}</th>
<th class="rerun">$rerunIcon</th>
<th class="draft">$draftIcon</th>
<th class="live">$liveIcon</th>
<th class="playout" title="$params->{loc}->{label_playout}">$playoutIcon</th>
<th class="archive">$archiveIcon</th>
<th class="project_id">project</th>
<th class="studio">studio</th>
<th class="creole">wiki format</th>
</tr>
</thead>
<tbody>
} if $params->{part} == 0;
my $i = 1;
my $scheduled_events = {};
for my $date ( reverse sort ( keys %$events_by_day ) ) {
for my $event ( reverse @{ $events_by_day->{$date} } ) {
next unless defined $event;
next if defined $event->{grid};
next if defined $event->{work};
next if defined $event->{play};
#schedules with matching date are marked to be hidden in find_errors
next if defined $event->{hide};
$event->{project_id} //= $params->{project_id};
$event->{studio_id} //= $params->{studio_id};
$event->{series_id} = '-1' unless defined $event->{series_id};
$event->{event_id} = '-1' unless defined $event->{event_id};
my $id =
'event_'
. $event->{project_id} . '_'
. $event->{studio_id} . '_'
. $event->{series_id} . '_'
. $event->{event_id};
my $class = 'event';
$class = $event->{class} if defined $event->{class};
$class = 'schedule' if defined $event->{schedule};
if ( $class =~ /(event|schedule)/ ) {
$class .= ' scheduled' if defined $event->{scheduled};
$class .= ' error' if defined $event->{error};
$class .= ' no_series'
if ( ( $class eq 'event' ) && ( $event->{series_id} eq '-1' ) );
for my $filter (
'rerun', 'archived', 'playout', 'published',
'live', 'disable_event_sync', 'draft'
)
{
$class .= ' ' . $filter
if ( ( defined $event->{$filter} ) && ( $event->{$filter} eq '1' ) );
}
$class .= ' preproduced'
unless ( ( defined $event->{'live'} ) && ( $event->{'live'} eq '1' ) );
$class .= ' no_playout'
unless ( ( defined $event->{'playout'} ) && ( defined $event->{'playout'} and $event->{'playout'} eq '1' ) );
$class .= ' no_rerun'
unless ( ( defined $event->{'rerun'} ) && ( $event->{'rerun'} eq '1' ) );
}
$event->{start} ||= '';
$event->{weekday_short_name} ||= '';
$event->{start_date_name} ||= '';
$event->{start_time_name} ||= '';
$event->{end_time} ||= '';
$event->{series_name} ||= '';
$event->{title} ||= '';
$event->{user_title} ||= '';
$event->{episode} ||= '';
$event->{rerun} ||= '';
$event->{draft} ||= '';
$event->{playout} ||= '';
$id ||= '';
$class ||= '';
my $archived = $event->{archived} || '-';
$archived = '-' if $archived eq '0';
$archived = $archiveIcon if $archived eq '1';
my $live = $event->{live} || '-';
$live = '-' if $live eq '0';
$live = $liveIcon if $live eq '1';
my $rerun = $event->{rerun} || '-';
$rerun = " [" . markup::base26( $event->{recurrence_count} + 1 ) . "]"
if ( defined $event->{recurrence_count} )
&& ( $event->{recurrence_count} ne '' )
&& ( $event->{recurrence_count} > 0 );
my $draft = $event->{draft} || '0';
$draft = '-' if $draft eq '0';
$draft = $draftIcon if $draft eq '1';
my $playout = '-';
if (defined $event->{upload_status}){
$playout = $processingIcon if $event->{upload_status} ne '';
$playout = $preparedIcon if $event->{upload_status} eq 'done';
}
$playout = $playoutIcon if $event->{playout} eq '1';
my $title = $event->{title};
$title .= ': ' . $event->{user_title} if $event->{user_title} ne '';
my $other_studio = $params->{studio_id} ne $event->{studio_id};
my $other_project = $params->{project_id} ne $event->{project_id};
$class.=' predecessor' if $other_project or $other_studio;
$other_studio = '<img src="image/globe.svg">' if $other_studio;
$other_project = '<img src="image/globe.svg">' if $other_project;
my $file = $event->{file}
? 'playout: ' . $event->{file} =~ s/\'/\&apos;/gr
: 'playout';
my $playout_info = $file // $event->{upload_status} // '';
my $studio_name = $event->{studio_name} // '-';
my $format = {"markdown" => "-", "creole" => "Lang Belta" }->{$event->{content_format}//''} // 'Lang Belta';
$out .=
qq!<tr id="$id" class="$class" start="$event->{start}" >!
. qq!<td class="day_of_year">!
. (defined $event->{start} ? time::dayOfYear( $event->{start} ) :'')
. q!</td>!
. qq!<td class="weekday">$event->{weekday_short_name},</td>!
. qq!<td class="start_date" data-text="$event->{start_datetime}">$event->{start_date_name}</td>!
. qq!<td class="start_time">$event->{start_time_name} - $event->{end_time}</td>!
. qq!<td class="series_name">$event->{series_name}</td>!
. qq!<td class="series_id">$event->{series_id}</td>!
. qq!<td class="title">$title</td>!
. qq!<td class="episode">$event->{episode}</td>!
. qq!<td class="rerun">$rerun</td>!
. qq!<td class="draft">$draft</td>!
. qq!<td class="live">$live</td>!
. qq!<td class="playout" title="$playout_info">$playout</td>!
. qq!<td class="archived">$archived</td>!
. qq!<td>$event->{project_name} $other_studio</td>!
. qq!<td>$studio_name $other_studio</td>!
. qq!<td>$format</td>!
. qq!</tr>! . "\n";
}
$i++;
if ( $i % 100 == 0 ) {
print $out;
$out = '';
}
}
$out .= qq{
</tbody>
</table>
</div>
} if $params->{part} == 0;
my $project_id = $params->{project_id};
my $studio_id = $params->{studio_id};
#add handler for events not assigned to series
if ( ( $params->{studio_id} ne '' ) && ( $params->{studio_id} ne '-1' ) ) {
my $series = series::get(
$config,
{
project_id => $project_id,
studio_id => $studio_id
}
);
$out .= q{<div id="event_no_series" style="display:none">};
$out .= addEventsToSeries( $series, $params )
if ( defined $permissions->{assign_series_events} )
&& ( $permissions->{assign_series_events} eq '1' );
$out .= createSeries($params)
if ( defined $permissions->{create_series} ) && ( $permissions->{create_series} eq '1' );
$out .= q{</div>};
}
$out .= qq{
</main>
<script>
var region='} . $params->{loc}->{region} . q{';
var calendarTable=0;
var label_events='} . $params->{loc}->{label_events} . q{';
var label_schedule='} . $params->{loc}->{label_schedule} . q{';
var label_worktime='} . $params->{loc}->{label_worktime} . q{';
var label_playout='} . $params->{loc}->{label_playout} . q{';
var label_descriptions='} . $params->{loc}->{label_descriptions} . q{';
var label_pin='} . $params->{loc}->{label_pin} . q{';
</script>
</body>
</html>
} if $params->{part} == 0;
print $out;
}
sub calcCalendarTable {
my $config = shift;
my $permissions = shift;
my $params = shift;
my $calendar = shift;
my $events_by_day = shift;
my $cal_options = shift;
my $start_of_day = $cal_options->{start_of_day};
my $end_of_day = $cal_options->{end_of_day};
my $min_hour = $cal_options->{min_hour};
my $max_hour = $cal_options->{max_hour};
my $project_id = $params->{project_id};
my $studio_id = $params->{studio_id};
my $language = $params->{language};
#insert time column
for my $hour ( $min_hour .. $max_hour ) {
push @{ $events_by_day->{0} },
{
start => sprintf( '%02d:00', $hour % 24 ),
start_time => sprintf( '%02d:00', $hour ),
end_time => sprintf( '%02d:00', $hour + 1 ),
series_id => -1,
event_id => -1,
project_id => $project_id,
studio_id => $studio_id,
class => 'time',
'time' => sprintf( '%02d', $hour % 24 )
};
}
#insert current time
my $time = '00:00';
my $date = '';
if ( time::get_datetime(
time::time_to_datetime(time()),
$config->{date}->{time_zone}
) =~ /(\d\d\d\d\-\d\d\-\d\d)[ T](\d\d\:\d\d)/ ) {
$date = $1;
$time = $2;
}
my $next_time = '00:00';
if ( time::get_datetime(
time::time_to_datetime(time()+60),
$config->{date}->{time_zone}
) =~ /(\d\d\d\d\-\d\d\-\d\d)[ T](\d\d\:\d\d)/ ) {
$next_time = $2;
}
unshift @{ $events_by_day->{0} },
{
#start => $time,
start_time => $time,
end_time => $next_time,
series_id => -1,
event_id => -1,
project_id => -1,
studio_id => -1,
class => 'time now',
'time' => $time,
};
calc_positions( $events_by_day->{0}, $cal_options );
my $yoffset = $min_hour * $hour_height;
my @days = sort keys %$events_by_day;
$cal_options->{days} = \@days;
$cal_options->{yoffset} = $yoffset;
$cal_options->{events_by_day} = $events_by_day;
$cal_options->{date} = $date;
}
sub printTableHeader {
my $config = shift;
my $permissions = shift;
my $params = shift;
my $cal_options = shift;
my $days = $cal_options->{days};
my $events_by_day = $cal_options->{events_by_day};
my $yoffset = $cal_options->{yoffset};
my $date = $cal_options->{date};
my $min_hour = $cal_options->{min_hour};
my $project_id = $params->{project_id};
my $studio_id = $params->{studio_id};
my $language = $params->{language};
#print row with weekday and date
my $out = '';
my $numberOfDays = scalar(@$days);
my $width = int( 85 / $numberOfDays );
$out .= qq!
<script>
var days=$numberOfDays;
</script>
<style>
#calendar div.time,
#calendar_weekdays div.date,
#calendar div.event,
#calendar div.schedule,
#calendar div.work,
#calendar div.play,
#calendar div.grid {
width: $width%
}
</style>
!;
$out .= q{
<div id="calendar_weekdays" style="visibility:hidden">
<table>
<tbody>
<tr>
};
my $next_day_found = 0;
#print navigation and weekday
my $ypos = 0;
my $old_week = undef;
my $dt = undef;
for my $day (@$days) {
my $events = $events_by_day->{$day};
if ( $day ne '0' ) {
$dt = time::get_datetime( $day . 'T00:00:00', $config->{date}->{time_zone} );
my $week = $dt->week_number();
if ( ( defined $old_week ) && ( $week ne $old_week ) ) {
$out .= qq{<td class="week"><div class="week"></div></td>};
}
$old_week = $week;
}
#header
$out .= qq{<td>};
my $event = $events->[0];
my $content = '';
my $class = 'date';
if ( $day eq '0' ) {
$out .= qq{<div id="position"></div></td>};
next;
} else {
#print weekday
$dt->set_locale($language);
$content = $dt->day_name() . '<br>';
$content .= $dt->strftime('%d. %b %Y') . '<br>';
$content .= time::dayOfYear( $event->{start} ) . '<br>';
#$class="date";
if ( ( $day ge $date ) && ( $next_day_found == 0 ) ) {
$class = "date today";
$next_day_found = 1;
}
}
#insert date name
my $hour = $min_hour;
my $date = $day;
$event = {
start => sprintf( '%02d:00', $hour % 24 ),
start_time => sprintf( '%02d:00', $hour ),
end_time => sprintf( '%02d:30', $hour + 1 ),
project_id => $project_id,
studio_id => $studio_id,
content => $content,
class => $class,
date => $date
};
calc_positions( [$event], $cal_options );
$out .= print_event( $params, $event, $ypos, $yoffset, $yzoom );
$out .= '</td>';
}
$out .= q{
</tr>
</tbody>
</table>
</div>
};
print $out;
}
sub printTableBody {
my $config = shift;
my $permissions = shift;
my $params = shift;
my $cal_options = shift;
my $days = $cal_options->{days};
my $events_by_day = $cal_options->{events_by_day};
my $yoffset = $cal_options->{yoffset};
my $project_id = $params->{project_id};
my $studio_id = $params->{studio_id};
if ( scalar( @{$days} ) == 0 ) {
uac::print_info("no dates found at the selected time span");
}
my $out = q{
<div id="calendar" style="display:none">
<table>
<tbody>
<tr>
};
#print events with weekday and date
my $ypos = 1;
my $dt = undef;
my $old_week = undef;
for my $day (@$days) {
my $events = $events_by_day->{$day};
if ( $day ne '0' ) {
$dt = time::get_datetime( $day . 'T00:00:00', $config->{date}->{time_zone} );
my $week = $dt->week_number();
if ( ( defined $old_week ) && ( $week ne $old_week ) ) {
$out .= qq{<td class="week"><div class="week"></div></td>};
}
$old_week = $week;
}
$out .= qq{<td>}; # width="$width">};
for my $event (@$events) {
my $content = '';
if ( ( defined $event->{series_name} ) && ( $event->{series_name} ne '' ) ) {
$event->{series_name} = $params->{loc}->{single_event}
if $event->{series_name} eq '' || $event->{series_name} eq '_single_';
$content = '<b>' . $event->{series_name} . '</b><br>';
}
if ( ( defined $event->{title} ) && ( defined $event->{title} ne '' ) ) {
$content .= $event->{title};
unless ( $event->{title} =~ /\#\d+/ ) {
$content .= ' #' . $event->{episode}
if ( ( defined $event->{episode} ) && ( $event->{episode} ne '' ) );
}
}
$content = $event->{start} if $day eq '0';
$event->{project_id} = $project_id unless defined $event->{project_id};
$event->{studio_id} = $studio_id unless defined $event->{studio_id};
$event->{content} = $content
unless ( ( defined $event->{class} ) && ( $event->{class} eq 'time now' ) );
$event->{class} = 'event' if $day ne '0';
$event->{class} = 'grid' if ( ( defined $event->{grid} ) && ( $event->{grid} == 1 ) );
$event->{class} = 'schedule'
if ( ( defined $event->{schedule} ) && ( $event->{schedule} == 1 ) );
$event->{class} = 'work' if ( ( defined $event->{work} ) && ( $event->{work} == 1 ) );
$event->{class} = 'play' if ( ( defined $event->{play} ) && ( $event->{play} == 1 ) );
if ( $event->{class} eq 'event' ) {
$event->{content} .= '<br><span class="weak">';
$event->{content} .= audio::formatFile($event->{file}, $event->{event_id});
$event->{content} .= audio::formatDuration(
$event->{duration},
$event->{event_duration},
sprintf( "%d min", ( $event->{duration} + 30 ) / 60 ),
sprintf( "%d s", $event->{duration} )
)
. ' '
if defined $event->{duration};
$event->{content} .= audio::formatLoudness( $event->{rms_left}, 'L: ' ,'round') . ' '
if defined $event->{rms_left};
$event->{content} .= audio::formatLoudness( $event->{rms_right}, 'R: ','round' )
if defined $event->{rms_right};
#$event->{content} .= formatBitrate( $event->{bitrate} ) if defined $event->{bitrate};
$event->{content} .= '</span>';
}
$out .= print_event( $params, $event, $ypos, $yoffset, $yzoom );
$ypos++;
}
$out .= '</td>';
}
$out .= q{
</tr>
</tbody>
</table>
</div><!--table-->
};
print $out;
}
sub printSeries {
my $config = shift;
my $permissions = shift;
my $params = shift;
my $cal_options = shift;
my $project_id = $params->{project_id};
my $studio_id = $params->{studio_id};
my $series = series::get(
$config,
{
project_id => $project_id,
studio_id => $studio_id
}
);
my $out = '';
#add schedule entry for series
if ( ( defined $permissions->{update_schedule} )
&& ( $permissions->{update_schedule} eq '1' )
&& ( scalar(@$series) > 0 ) )
{
$out .= q{<div id="series" style="display:none">};
$out .= addSeries( $series, $params );
$out .= q{</div>};
}
if ( ( $params->{studio_id} ne '' ) && ( $params->{studio_id} ne '-1' ) ) {
$out .= q{<div id="event_no_series" style="display:none">};
$out .= addEventsToSeries( $series, $params )
if ( ( defined $permissions->{assign_series_events} )
&& ( $permissions->{assign_series_events} eq '1' ) );
$out .= createSeries($params)
if ( ( defined $permissions->{create_series} )
&& ( $permissions->{create_series} eq '1' ) );
$out .= q{</div>};
}
$out .= q{
<div id="no_studio_selected" style="display:none">
} . $params->{loc}->{label_no_studio_selected} . q{
</div>
};
print $out;
}
sub printJavascript {
my $config = shift;
my $permissions = shift;
my $params = shift;
my $cal_options = shift;
my $startOfDay = $cal_options->{min_hour} % 24;
#print STDERR "js: ".$cal_options->{min_hour}." ".$startOfDay."\n";
my $out = q{
<script>
var region='} . $params->{loc}->{region} . q{';
var calendarTable=1;
var startOfDay=} . $startOfDay . q{;
var label_events='} . $params->{loc}->{label_events} . q{';
var label_schedule='} . $params->{loc}->{label_schedule} . q{';
var label_worktime='} . $params->{loc}->{label_worktime} . q{';
var label_descriptions='} . $params->{loc}->{label_descriptions} . q{';
var label_playout='} . $params->{loc}->{label_playout} . q{';
var label_pin='} . $params->{loc}->{label_pin} . q{';
</script>
};
print $out;
}
#TODO: Javascript
sub addCalendarButton {
my $params = shift;
my $calendar = shift;
#add calendar button
my $content = qq{
<div id="previous_month"><a id="previous">&laquo;</a></div>
<div id="selectDate" data-toggle>
<input id="start_date" data-input/>
<div id="current_date">$calendar->{month} $calendar->{year}</div>
</div>
<div id="next_month"><a id="next">&raquo;</a></div>
};
return $content;
}
sub addSeries {
my $series = shift;
my $params = shift;
return unless defined $series;
return unless scalar @$series > 0;
my $out = '';
$out .= q{
<table>
<tr>
<td>} . $params->{loc}->{label_series} . q{</td>
<td><select id="series_select" name="series_id">
};
for my $serie (@$series) {
my $id = $serie->{series_id} || -1;
my $duration = $serie->{duration} || 0;
my $name = $serie->{series_name} || '';
my $title = $serie->{title} || '';
$name = $params->{loc}->{single_events} if $serie->{has_single_events} eq '1';
$title = ' - ' . $title if $title ne '';
$out .=
'<option value="'
. $id
. '" duration="'
. $duration . '">'
. $name
. $title
. '</option>' . "\n";
}
$out .= q{
</select>
</td>
</tr>
<tr>
<td>} . $params->{loc}->{label_date} . q{</td>
<td><input id="series_date" name="start_date" value=""></td>
</tr>
<tr>
<td>} . $params->{loc}->{label_duration} . q{</td>
<td><input id="series_duration" value="60"></td>
</tr>
</table>
</div>
};
return $out;
}
# create form to add events to series (that are not assigned to series, yet)
sub addEventsToSeries {
my $series = shift;
my $params = shift;
return unless defined $series;
return unless scalar @$series > 0;
my $project_id = $params->{project_id};
my $studio_id = $params->{studio_id};
my $out = '';
$out .= qq{
<div>
<b>} . $params->{loc}->{label_assign_event_series} . qq{</b>
<form id="assign_series_events" method="post" action="series.cgi">
<input type="hidden" name="project_id" value="$project_id">
<input type="hidden" name="studio_id" value="$studio_id">
<input type="hidden" name="event_id">
<table>
<tr>
<td>} . $params->{loc}->{label_series} . qq{</td>
<td><select id="select_series" name="series_id">
};
for my $serie (@$series) {
my $id = $serie->{series_id} || -1;
my $duration = $serie->{duration} || '';
my $name = $serie->{series_name} || '';
my $title = $serie->{title} || '';
$name = $params->{loc}->{single_events} if $serie->{has_single_events} == 1;
$title = ' - ' . $title if $title ne '';
$out .=
'<option value="'
. $id
. '" duration="'
. $duration . '">'
. $name
. $title
. '</option>' . "\n";
}
$out .= q{
</select>
</td>
</tr>
<tr><td></td>
<td>
<button type="submit" name="action" value="assign_event">}
. $params->{loc}->{button_assign_event_series} . q{</button>
</td>
</tr>
</table>
</form>
</div>
};
return $out;
}
# insert form to create series on not assigned events
sub createSeries {
my $params = shift;
my $project_id = $params->{project_id};
my $studio_id = $params->{studio_id};
return qq{
<div>
<b>} . $params->{loc}->{label_create_series} . qq{</b>
<form method="post" action="series.cgi">
<input type="hidden" name="project_id" value="$project_id">
<input type="hidden" name="studio_id" value="$studio_id">
<table>
<tr><td class="label">}
. $params->{loc}->{label_name} . qq{</td> <td><input name="series_name"></td></tr>
<tr><td class="label">}
. $params->{loc}->{label_title} . qq{</td> <td><input name="title"></td></tr>
<tr><td></td>
<td>
<button type="submit" name="action" value="create">}
. $params->{loc}->{button_create_series} . qq{</button>
</td>
</tr>
</table>
</form>
</div>
};
}
sub print_event {
my $params = shift;
my $event = shift;
my $ypos = shift;
my $yoffset = shift;
my $yzoom = shift;
$event->{project_id} = '-1' unless defined $event->{project_id};
$event->{studio_id} = '-1' unless defined $event->{studio_id};
$event->{series_id} = '-1' unless defined $event->{series_id};
$event->{event_id} = '-1' unless defined $event->{event_id};
my $id =
'event_'
. $event->{project_id} . '_'
. $event->{studio_id} . '_'
. $event->{series_id} . '_'
. $event->{event_id};
$id = 'grid_' . $event->{project_id} . '_' . $event->{studio_id} . '_' . $event->{series_id}
if defined $event->{grid};
$id = 'work_' . $event->{project_id} . '_' . $event->{studio_id} . '_' . $event->{schedule_id}
if defined $event->{work};
$id = 'play_' . $event->{project_id} . '_' . $event->{studio_id} if defined $event->{play};
my $class = $event->{class} || '';
my $showIcons = 0;
if ( $class =~ /(event|schedule)/ ) {
$class .= ' scheduled' if defined $event->{scheduled};
$class .= ' no_series' if ( ( $class eq 'event' ) && ( $event->{series_id} eq '-1' ) );
$class .= " error x$event->{error}" if defined $event->{error};
for my $filter ( 'rerun', 'archived', 'playout', 'published', 'live', 'disable_event_sync',
'draft' )
{
$class .= ' ' . $filter
if ( ( defined $event->{$filter} ) && ( $event->{$filter} eq '1' ) );
}
$class .= ' preproduced'
unless ( ( defined $event->{'live'} ) && ( $event->{'live'} eq '1' ) );
$class .= ' no_playout'
unless ( ( defined $event->{'playout'} ) && ( $event->{'playout'} eq '1' ) );
$class .= ' no_rerun'
unless ( ( defined $event->{'rerun'} ) && ( $event->{'rerun'} eq '1' ) );
$showIcons = 1;
}
my $ystart = $event->{ystart} - $yoffset;
my $yend = $event->{yend} - $yoffset - 10;
$ystart = int( $ystart * $yzoom );
$yend = int( $yend * $yzoom );
my $height = $yend - $ystart + 1;
if ( $ypos > 0 ) {
$height = q{height:} . ($height) . 'px;';
} else {
$height = '';
}
my $content = '<div class="header">';
$content .= qq!<img class="icon" src="!.($event->{series_icon_url}).q!">! if $class=~/event/;
$content .= $event->{content} || '';
$content .= '</div>';
if ( $class =~ /schedule/ ) {
my $frequency = getFrequency($event);
$content .= "<br>($frequency)" if defined $frequency;
}
my $attr = '';
if ( $class =~ /play/ ) {
$attr .= ' rms="' . $event->{rms_image} . '"' if defined $event->{rms_image};
$attr .= ' start="' . $event->{start} . '"' if defined $event->{start};
}
if ( defined $event->{upload} ) {
$content .= '<br>uploading <progress max="10" ></progress> ';
}
$content .= q{<div class="scrollable">};
$content .= q{<div class="excerpt">}.$event->{excerpt}.q{</div>} if defined $event->{excerpt};
$content .= q{<div class="excerpt">}.$event->{html_topic}.q{</div>} if defined $event->{topic};
$content .= q{</div>};
if ($showIcons) {
my $attr = { map { $_ => undef } split( /\s+/, $class) };
my $file = $event->{file}
? 'playout: ' . $event->{file} =~ s/\'/\&apos;/gr
: 'playout';
my $playoutClass = qq{<img src="image/play.svg">};
my $processingClass = qq{<img src="image/processing.svg">};
my $preparedClass = qq{<img src="image/prepare.svg">};
my $icons = '';
if ( exists $attr->{event} ){
my $playout = '';
if (exists $attr->{upload_status}){
$playout = $processingClass if $attr->{upload_status} ne '';
$playout = $preparedClass if $attr->{upload_status} eq 'done';
}
$playout = $playoutClass if exists $attr->{playout};
$icons.='<img src="image/mic.svg" title="live"/>'
if exists($attr->{live}) && exists($attr->{no_rerun});
$icons.='<img src="image/mic_off.svg" title="preproduced"/>'
if exists($attr->{preproduced}) && exists($attr->{no_rerun});
$icons.='<img src="image/replay.svg" title="rerun"/>'
if exists $attr->{rerun};
$icons.=qq{<img src="image/play.svg" title="$file" onmouseenter="console.log('$file');"/>}
if $playout;
$icons.='<img src="image/archive.svg" title="archived"/>'
if exists $attr->{archived};
}
$content = qq{<div class="text" style="$height">$content</div><div class="icons">$icons</div>};
}
my $time = '';
$time = qq{ time="$event->{time}"} if $class =~ m/time/;
my $date = '';
$date = qq{ date="$event->{date}"} if $class =~ m/date/;
my $line = q{<div } . qq{class="$class" id="$id"};
$line .= qq{ style="} . $height . q{top:} . $ystart . q{px;"};
$line .= $time . $date . qq{ $attr};
$line .= qq{>$content</div>};
$line .= "\n";
return $line;
}
sub getFrequency {
my $event = shift;
my $period_type = $event->{period_type};
return undef unless defined $period_type;
return undef if $period_type ne 'days';
my $frequency = $event->{frequency};
return undef unless defined $frequency;
return undef unless $frequency > 0;
if ( ( $frequency >= 7 ) && ( ( $frequency % 7 ) == 0 ) ) {
$frequency /= 7;
return '1 week' if $frequency == 1;
return $frequency .= ' weeks';
}
return '1 day' if $frequency == 1;
return $frequency .= ' days';
}
sub calc_positions {
my $events = $_[0];
my $cal_options = $_[1];
my $start_of_day = $cal_options->{start_of_day};
for my $event (@$events) {
my ( $start_hour, $start_min ) = getTime( $event->{start_time} );
my ( $end_hour, $end_min ) = getTime( $event->{end_time} );
$start_hour += 24 if $start_hour < $start_of_day;
$end_hour += 24 if $end_hour < $start_of_day;
$end_hour += 24 if $start_hour > $end_hour;
$end_hour += 24 if ( $start_hour == $end_hour ) && ( $start_min == $end_min );
$event->{ystart} = $start_hour * 60 + $start_min;
$event->{yend} = $end_hour * 60 + $end_min;
}
}
sub find_errors {
my $events = $_[0];
for my $event (@$events) {
next if defined $event->{grid};
next if defined $event->{work};
next if defined $event->{play};
next if ( defined $event->{draft} ) && ( $event->{draft} == 1 );
next unless defined $event->{ystart};
next unless defined $event->{yend};
$event->{check_errors} = 1;
}
#check next events
for my $i ( 0 .. scalar(@$events) - 1 ) {
my $event = $events->[$i];
next unless defined $event->{check_errors};
#look for conflicts with next 5 events of day
my $min_index = $i + 1;
next if $min_index >= scalar @$events;
my $max_index = $i + 8;
$max_index = scalar(@$events) - 1 if $max_index >= (@$events);
for my $j ( $min_index .. $max_index ) {
my $event2 = $events->[$j];
next unless defined $event2->{check_errors};
#mark events if same start,stop,series_id, one is schedule one is event
if ( ( defined $event->{series_id} )
&& ( defined $event2->{series_id} )
&& ( $event->{series_id} == $event2->{series_id} ) )
{
if ( ( $event->{ystart} eq $event2->{ystart} )
&& ( $event->{yend} eq $event2->{yend} ) )
{
if ( ( defined $event->{schedule} ) && ( !( defined $event2->{schedule} ) ) ) {
$event->{hide} = 1;
$event2->{scheduled} = 1;
next;
}
if ( ( !( defined $event->{schedule} ) ) && ( defined $event2->{schedule} ) ) {
$event->{scheduled} = 1;
$event2->{hide} = 1;
next;
}
} elsif ( ( $event->{ystart} >= $event2->{ystart} )
&& ( $event->{scheduled} == 1 )
&& ( $event2->{scheduled} == 1 ) )
{
#subsequent schedules
$event->{error}++;
$event2->{error} = 1 unless defined $event2->{error};
$event2->{error}++;
next;
}
} elsif ( $event->{ystart} >= $event2->{ystart} ) {
#errors on multiple schedules or events
$event->{error}++;
$event2->{error} = 1 unless defined $event2->{error};
$event2->{error}++;
}
}
}
#remove error tags from correctly scheduled entries (subsequent entries with same series id)
for my $event (@$events) {
delete $event->{error}
if (
( defined $event->{error} )
&& ( ( ( defined $event->{scheduled} ) && ( $event->{scheduled} == 1 ) )
|| ( ( defined $event->{hide} ) && ( $event->{hide} == 1 ) ) )
);
}
}
sub printToolbar {
my $config = shift;
my $params = shift;
my $calendar = shift;
my $today = time::time_to_date();
my $toolbar = '<div id="toolbar">';
$toolbar .= addCalendarButton( $params, $calendar );
$toolbar .= qq{<button id="setToday">} . $params->{loc}->{button_today} . qq{</button>};
#ranges
my $ranges = {
$params->{loc}->{label_month} => 'month',
$params->{loc}->{label_4_weeks} => '28',
$params->{loc}->{label_2_weeks} => '14',
$params->{loc}->{label_1_week} => '7',
$params->{loc}->{label_day} => '1',
};
$toolbar .= qq{
<select id="range" name="range" onchange="reloadCalendar()" value="$params->{range}">
};
# my $options=[];
for my $range (
$params->{loc}->{label_month}, $params->{loc}->{label_4_weeks},
$params->{loc}->{label_2_weeks}, $params->{loc}->{label_1_week},
$params->{loc}->{label_day}
)
{
my $value = $ranges->{$range} || '';
$toolbar .= qq{<option name="$range" value="$value">} . $range . '</option>';
}
$toolbar .= q{
</select>
};
# start of day
my $day_start = $params->{day_start} || '';
$toolbar .= qq{
<select id="day_start" name="day_start" onchange="updateDayStart();reloadCalendar()" value="$day_start">
};
for my $hour ( 0 .. 24 ) {
my $selected = '';
$selected = 'selected="selected"' if $hour eq $day_start;
$toolbar .= qq{<option value="$hour">} . sprintf( "%02d:00", $hour ) . '</option>';
}
$toolbar .= q{
</select>
};
#filter
my $filter = $params->{filter} || '';
$toolbar .= qq{
<select id="filter" name="filter" onchange="reloadCalendar()">
};
for my $filter (
'no markup', 'conflicts', 'rerun', 'archived',
'playout', 'published', 'live', 'disable_event_sync',
'draft'
)
{
my $key = $filter;
$key =~ s/ /_/g;
$toolbar .=
qq{<option value="$filter">} . $params->{loc}->{ 'label_' . $key } . '</option>';
}
$toolbar .= q{
</select>
};
#search
$toolbar .= qq{
<form class="search">
<input type="hidden" name="project_id" value="$params->{project_id}">
<input type="hidden" name="studio_id" value="$params->{studio_id}">
<input type="hidden" name="date" value="$params->{date}">
<input type="hidden" name="list" value="1">
<input class="search" name="search" value="$params->{search}" placeholder="}
. $params->{loc}->{button_search} . qq{">
<button type="submit" name="action" value="search">}
. $params->{loc}->{button_search} . qq{</button>
</form>
};
#
$toolbar .= qq{
<button id="editSeries">} . $params->{loc}->{button_edit_series} . qq{</button>
} if $params->{list} == 1;
$toolbar .= qq{
</div>
};
print $toolbar;
}
sub getTime {
my $time = shift;
if ( $time =~ /^(\d\d)\:(\d\d)/ ) {
return ( $1, $2 );
}
return ( -1, -1 );
}
sub getCalendar {
my $config = shift;
my $params = shift;
my $language = shift;
my $from_date = getFromDate( $config, $params );
my $till_date = getTillDate( $config, $params );
my $range = $params->{range};
my $previous = '';
my $next = '';
if ( $range eq 'month' ) {
$previous =
time::get_datetime( $from_date, $config->{date}->{time_zone} )->subtract( months => 1 )
->set_day(1)->date();
$next = time::get_datetime( $from_date, $config->{date}->{time_zone} )->add( months => 1 )
->set_day(1)->date();
} else {
$previous = time::get_datetime( $from_date, $config->{date}->{time_zone} )
->subtract( days => $range )->date();
$next =
time::get_datetime( $from_date, $config->{date}->{time_zone} )->add( days => $range )
->date();
}
my ( $year, $month, $day ) = split( /\-/, $from_date );
my $monthName = time::getMonthNamesShort($language)->[ $month - 1 ] || '';
return {
from_date => $from_date,
till_date => $till_date,
next_date => $next,
previous_date => $previous,
month => $monthName,
year => $year
};
}
sub getFromDate {
my $config = shift;
my $params = shift;
if ( $params->{from_date} ne '' ) {
return $params->{from_date};
}
my $date = $params->{date};
if ( $date eq '' ) {
$date = DateTime->now( time_zone => $config->{date}->{time_zone} )->date();
}
if ( $params->{range} eq '28' ) {
#get start of 4 week period
$date = time::get_datetime( $date, $config->{date}->{time_zone} )->truncate( to => 'week' )
->ymd();
}
if ( $params->{range} eq 'month' ) {
#get first day of month
return time::get_datetime( $date, $config->{date}->{time_zone} )->set_day(1)->date();
}
#get date
return time::get_datetime( $date, $config->{date}->{time_zone} )->date();
}
sub getTillDate {
my $config = shift;
my $params = shift;
if ( $params->{till_date} ne '' ) {
return $params->{till_date};
}
my $date = $params->{date} || '';
if ( $date eq '' ) {
$date = DateTime->now( time_zone => $config->{date}->{time_zone} )->date();
}
if ( $params->{range} eq '28' ) {
$date = time::get_datetime( $date, $config->{date}->{time_zone} )->truncate( to => 'week' )
->ymd();
}
if ( $params->{range} eq 'month' ) {
#get last day of month
return time::get_datetime( $date, $config->{date}->{time_zone} )->set_day(1)
->add( months => 1 )->subtract( days => 1 )->date();
}
#add range to date
return time::get_datetime( $date, $config->{date}->{time_zone} )
->add( days => $params->{range} )->date();
}
sub getSeriesEvents {
my $config = shift;
my $request = shift;
my $options = shift;
my $params = shift;
#get events by series id
my $series_id = $request->{params}->{checked}->{series_id};
if ( defined $series_id ) {
my $events = series::get_events( $request->{config}, $options );
return $events;
}
#get events (directly from database to get the ones, not assigned, yet)
delete $options->{studio_id};
delete $options->{project_id};
$options->{active_recording} = 1;
my $request2 = {
params => {
checked => events::check_params( $config, $options )
},
config => $request->{config},
permissions => $request->{permissions}
};
$request2->{params}->{checked}->{published} = 'all';
$request2->{params}->{checked}->{draft} = '1' if $params->{list} == 1;
my $events = events::get( $config, $request2 );
series::add_series_ids_to_events( $request->{config}, $events );
my $studios = studios::get(
$request->{config},
{
project_id => $options->{project_id}
}
);
my $studio_id_by_location = {};
for my $studio (@$studios) {
$studio_id_by_location->{ $studio->{location} } = $studio->{id};
}
for my $event (@$events) {
$event->{project_id} = $options->{project_id} unless defined $event->{project_id};
$event->{studio_id} = $studio_id_by_location->{ $event->{location} }
unless defined $event->{studio_id};
}
return $events;
}
sub check_params {
my $config = shift;
my $params = shift;
my $checked = {
user => $config->{user}
};
my $template = '';
$checked->{template} = template::check( $config, $params->{template}, 'series' );
#numeric values
$checked->{part} = 0;
$checked->{list} = 0;
$checked->{open_end} = 1;
entry::set_numbers( $checked, $params, [
'id', 'project_id', 'studio_id', 'default_studio_id',
'user_id', 'series_id', 'event_id', 'part',
'list', 'day_start', 'open_end'
]);
my $start = user_day_start::get( $config, {
user => $checked->{user},
project_id => $checked->{project_id},
studio_id => $checked->{studio_id}
});
print STDERR "read start $start\n";
$checked->{day_start} = $start->{day_start} if $start;
$checked->{day_start} = $config->{date}->{day_starting_hour}
unless defined $checked->{day_start};
$checked->{day_start} %= 24;
if ( defined $checked->{studio_id} ) {
# a studio is selected, use the studio from parameter
$checked->{default_studio_id} = $checked->{studio_id};
} elsif ( ( defined $params->{studio_id} ) && ( $params->{studio_id} eq '-1' ) ) {
# all studios selected, use -1
$checked->{studio_id} = -1;
} else {
# no studio given, use default studio
$checked->{studio_id} = $checked->{default_studio_id};
}
for my $param ('expires') {
$checked->{$param} = time::check_datetime( $params->{$param} );
}
#scalars
$checked->{search} = '';
$checked->{filter} = '';
for my $param ( 'date', 'from_date', 'till_date' ) {
$checked->{$param} = time::check_date( $params->{$param} );
}
entry::set_strings( $checked, $params, [
'search', 'filter', 'range',
'series_name', 'title', 'excerpt', 'content',
'program', 'image', 'user_content'
]);
$checked->{action} = entry::element_of( $params->{action},
[ 'add_user', 'remove_user', 'delete', 'save', 'details', 'show', 'edit_event', 'save_event' ]
);
return $checked;
}