diff options
Diffstat (limited to 'vdradmind.pl')
-rwxr-xr-x | vdradmind.pl | 363 |
1 files changed, 287 insertions, 76 deletions
diff --git a/vdradmind.pl b/vdradmind.pl index 54a03a1..7f8308a 100755 --- a/vdradmind.pl +++ b/vdradmind.pl @@ -26,7 +26,7 @@ require 5.004; use vars qw($PROCNAME); -my $VERSION = "3.6.5"; +my $VERSION = "3.6.6"; my $BASENAME; my $EXENAME; @@ -77,6 +77,7 @@ my $can_use_encode = 1; $can_use_encode = undef unless (eval { require Encode }); my $InetSocketModule = 'IO::Socket::INET'; +my $VdrSocketModule = 'IO::Socket::INET'; my $can_use_net_smtp = 1; $can_use_net_smtp = undef unless (eval { require Net::SMTP }); my $can_use_smtpauth = 1; @@ -124,7 +125,7 @@ sub LOG_DEBUG () { [ 7, "debug" ] } my (%CONFIG, %CONFIG_TEMP); $CONFIG{LOGLEVEL} = 4; #LOG_WARNING $CONFIG{LOGGING} = 0; -$CONFIG{LOGFILE} = "vdradmind.log"; +$CONFIG{LOGFILE} = "syslog"; $CONFIG{MOD_GZIP} = 0; $CONFIG{CACHE_BG_UPDATE} = 1; $CONFIG{CACHE_TIMEOUT} = 60; @@ -164,6 +165,11 @@ $CONFIG{TIMES} = "18:00, 20:00, 21:00, 22:00"; $CONFIG{TL_TOOLTIP} = 1; # +$CONFIG{EPG_SUMMARY} = 0; +$CONFIG{EPG_SUBTITLE} = 1; +$CONFIG{EPG_START_TIME} = "00:00"; + +# $CONFIG{AT_OFFER} = 0; $CONFIG{AT_FUNC} = 1; $CONFIG{AT_LIFETIME} = 99; @@ -203,9 +209,9 @@ $CONFIG{NO_EVENTID_ON} = ""; # $CONFIG{AT_SENDMAIL} = 0; # set to 1 and set all the "MAIL_" things if you want email notification on new autotimers. -$CONFIG{MAIL_FROM} = "from\@address.tld"; -$CONFIG{MAIL_TO} = "your\@email.address"; -$CONFIG{MAIL_SERVER} = "your.email.server"; +chomp($CONFIG{MAIL_FROM} = 'autotimer@' . (`hostname -f 2>/dev/null` || "localhost.localdomain")); +$CONFIG{MAIL_TO} = "you\@example.org"; +$CONFIG{MAIL_SERVER} = "localhost"; $CONFIG{MAIL_AUTH_USER} = ""; $CONFIG{MAIL_AUTH_PASS} = ""; @@ -244,22 +250,26 @@ $CONFIG{GUI_POPUP_HEIGHT} = 250; # my %FEATURES; -$FEATURES{STREAMDEV} = 0; -$FEATURES{REC_RENAME} = 0; -$FEATURES{AUTOTIMER} = 0; +$FEATURES{STREAMDEV} = 0; # streamdev plugin available? +$FEATURES{REC_RENAME} = 0; # RENR patch available? +$FEATURES{AUTOTIMER} = 0; # use autotimer feature? +$FEATURES{MYVERSION_HR} = "$VERSION"; # Human readable VDRAdmin-AM version, e.g. 3.6.5 +$FEATURES{VDRVERSION} = 0; # Numeric VDR version, e.g. 10344 +$FEATURES{VDRVERSION_HR} = ''; # Human readable VDR version, e.g. 1.3.44 +$FEATURES{EPGSEARCH_VERSION} = 0; # Numeric epgsearch plugin version, e.g. 924 +$FEATURES{EPGSEARCH_VERSION_HR} = ''; # Human readable epgsearch plugin version, e.g. 0.9.24 my %EPGSEARCH_SETTINGS; my $SERVERVERSION = "vdradmind/$VERSION"; -my $VDRVERSION = 0; # Numeric VDR version, e.g. 10344 -my $VDRVERSION_HR; # Human readable VDR version, e.g. 1.3.44 -my $EPGSEARCH_VERSION = 0; # Numeric epgsearch plugin version, e.g. 918 my %ERROR_MESSAGE; my $MY_ENCODING = ''; -my ($TEMPLATEDIR, $CONFFILE, $LOGDIR, $LOGLEVEL, $PIDFILE, $AT_FILENAME, $DONE_FILENAME, $BL_FILENAME, $ETCDIR, $USER_CSS); +my ($TEMPLATEDIR, $TEMPLATECACHE, $CONFFILE, $LOGDIR, $LOGLEVEL, $PIDFILE, $AT_FILENAME, $DONE_FILENAME, $BL_FILENAME, $ETCDIR, $CERTSDIR, $USER_CSS); if (!$SEARCH_FILES_IN_SYSTEM) { $ETCDIR = "${BASENAME}"; + $CERTSDIR = "${ETCDIR}/certs"; $TEMPLATEDIR = "${BASENAME}template"; + $TEMPLATECACHE = "${BASENAME}cache"; $CONFFILE = "${BASENAME}vdradmind.conf"; $LOGDIR = "${BASENAME}"; $PIDFILE = "${BASENAME}vdradmind.pid"; @@ -270,9 +280,11 @@ if (!$SEARCH_FILES_IN_SYSTEM) { bindtextdomain("vdradmin", "${BASENAME}locale"); } else { $ETCDIR = "/etc/vdradmin"; + $CERTSDIR = "${ETCDIR}/certs"; $TEMPLATEDIR = "/usr/share/vdradmin/template"; - $LOGDIR = "/var/log"; - $PIDFILE = "/var/run/vdradmind.pid"; + $TEMPLATECACHE = "/var/cache/vdradmin"; + $LOGDIR = "/var/log/vdradmin"; + $PIDFILE = "/var/run/vdradmin/vdradmind.pid"; $CONFFILE = "${ETCDIR}/vdradmind.conf"; $AT_FILENAME = "${ETCDIR}/vdradmind.at"; $DONE_FILENAME = "${ETCDIR}/vdradmind.done"; @@ -376,6 +388,10 @@ for (my $i = 0 ; $i < scalar(@ARGV) ; $i++) { $PIDFILE = $ARGV[ ++$i ]; next; } + if (/^(--ipv6-all)/) { + $UseIPv6 = 2; + next; + } if (/^(--ipv6|-6)/) { $UseIPv6 = 1; next; @@ -410,18 +426,25 @@ for (my $i = 0 ; $i < scalar(@ARGV) ; $i++) { } } +check_permissions() or exit 1; + if ($UseIPv6) { if (eval { require IO::Socket::INET6 }) { $InetSocketModule = 'IO::Socket::INET6'; + $VdrSocketModule = 'IO::Socket::INET6' if ($UseIPv6 == 2); } else { die("ERROR: Can't load module IO::Socket::INET6! $!\n"); } } +ReadConfig(); +LoadTranslation(); + #use Template::Constants qw( :debug ); # IMHO a better Template Modul ;-) # some useful options (see below for full list) my $Xtemplate_vars = { usercss => $UserCSS, + charset => $MY_ENCODING, gettext => sub{ $_[0] =~ s/\n\s+//g; return gettext($_[0]); }, config => \%CONFIG, features => \%FEATURES @@ -436,7 +459,7 @@ my $Xconfig = { POST_CHOMP => 1, # cleanup whitespace EVAL_PERL => 1, # evaluate Perl code blocks COMPILE_EXT => 'cache', # tuning for templates - COMPILE_DIR => '/var/cache/vdradmin', # tuning for templates + COMPILE_DIR => $TEMPLATECACHE, # tuning for templates STAT_TTL => 3600, # tuning for templates VARIABLES => $Xtemplate_vars, @@ -461,14 +484,19 @@ if ($@) { # ---- End new template section ---- -ReadConfig(); -LoadTranslation(); - -if ($DAEMON && $CONFIG{LOGFILE} eq "syslog") { - require Sys::Syslog; - Sys::Syslog->import(qw(:standard)); - openlog($PROCNAME, "cons,pid", "daemon"); -} else { +my $LOG_TO_SYSLOG = 0; +if ($DAEMON && $CONFIG{LOGGING} && $CONFIG{LOGFILE} eq "syslog") { + eval { + require Sys::Syslog; + Sys::Syslog->import(qw(:standard)); + openlog($PROCNAME, "cons,pid", "daemon"); + } and $LOG_TO_SYSLOG = 1; + if ($@) { + Log(LOG_WARNING, + "Error setting up syslog logging, falling back to stderr: $@"); + } +} +if (!$LOG_TO_SYSLOG) { *closelog = sub {}; # for Shutdown() } @@ -513,11 +541,27 @@ my @vdrcmds = loadCommandsConf("$CONFIG{VDRCONFDIR}/commands.conf"); my ($Socket); if ($UseSSL) { if (eval { require IO::Socket::SSL; }) { - $Socket = IO::Socket::SSL->new(Proto => 'tcp', - LocalPort => $CONFIG{SERVERPORT}, - LocalAddr => $CONFIG{SERVERHOST}, - Listen => 10, - Reuse => 1 + my $CERT_FILE = "$CERTSDIR/server-cert.pem"; + die("ERROR: $CERT_FILE missing. Please create it!\n") unless (-e $CERT_FILE); + + my $KEY_FILE = "$CERTSDIR/server-key.pem"; + die("ERROR: $KEY_FILE missing. Please create it!\n") unless (-e $KEY_FILE); + + my $CA_PATH = "$CERTSDIR/ca"; + $CA_PATH = undef unless (-d $CA_PATH); + + my $CA_FILE = "$CERTSDIR/my-ca.pem"; + $CA_FILE = undef unless (-f $CA_FILE); + + $Socket = IO::Socket::SSL->new(Proto => 'tcp', + LocalPort => $CONFIG{SERVERPORT}, + LocalAddr => $CONFIG{SERVERHOST}, + Listen => 10, + Reuse => 1, + SSL_cert_file => "$CERT_FILE", + SSL_key_file => "$KEY_FILE", + SSL_ca_file => "$CA_FILE", + SSL_ca_path => "$CA_PATH" ); } else { die("ERROR: Can't load module IO::Socket::SSL! $!\n"); @@ -710,6 +754,82 @@ while (true) { ############################################################################# ############################################################################# +sub check_permissions { + my $rc = 1; + check_rw_dir($ETCDIR) or $rc = 0; + check_rw_dir($CERTSDIR) if ($UseSSL); + check_rw_dir($TEMPLATECACHE) or $rc = 0; + check_rw_dir($LOGDIR) or $rc = 0; + check_rw_file($PIDFILE) or $rc = 0; + check_rw_file($CONFFILE) or $rc = 0; + + if ($CONFIG{AT_FUNC} || $FEATURES{AUTOTIMER}) { + check_rw_file($AT_FILENAME) or $rc = 0; + check_rw_file($DONE_FILENAME) or $rc = 0; + check_rw_file($BL_FILENAME) or $rc = 0; + } + + return $rc; +} + +sub check_rw_dir { + my $dir = shift; + +# print "Checking directory '$dir':\n"; + if (-e "$dir") { + if (! -d _) { + print "ERROR: '$dir' is NOT a directory!\n"; + return 0; + } + if (-r _) { +# print "directory '$dir' is readable!\n"; + } else { + print "ERROR: directory '$dir' is NOT readable!\n"; + return 0; + } + if (-w _) { +# print "directory '$dir' is writable!\n"; + } else { + print "ERROR: directory '$dir' is NOT writable!\n"; + return 0; + } + } else { + print "ERROR: directory '$dir' is missing!\n"; + return 0; + } + + return 1; +} + +sub check_rw_file { + my $file = shift; + +# print "Checking file '$file':\n"; + if (-e "$file") { + if (-d _) { + print "ERROR: '$file' is a directory!\n"; + return 0; + } + if (-r _) { +# print "file '$file' is readable!\n"; + } else { + print "ERROR: file '$file' is NOT readable!\n"; + return 0; + } + if (-w _) { +# print "file '$file' is writable!\n"; + } else { + print "ERROR: file '$file' is NOT writable!\n"; + return 0; + } + } else { + $file =~ /(^.*)\/[^\/]*$/; + return check_rw_dir($1); + } + + return 1; +} + sub GetChannelDesc { #TODO: unused my (%hash); for (@{$CHAN{$CHAN_FULL}->{channels}}) { @@ -1180,7 +1300,7 @@ sub EPG_buildTree { } } } elsif (/^c/) { - if ($VDRVERSION < 10305) { # EPG is sorted by date since VDR 1.3.5 + if ($FEATURES{VDRVERSION} < 10305) { # EPG is sorted by date since VDR 1.3.5 my ($last) = 0; my (@temp); for (sort({ $a->{start} <=> $b->{start} } @events)) { @@ -1233,7 +1353,7 @@ sub OpenSocket { sub SendCMD { my $cmd = join("", @_); - if (($VDRVERSION < 10336) && (length($cmd) > $VDR_MAX_SVDRP_LENGTH)) { + if (($FEATURES{VDRVERSION} < 10336) && (length($cmd) > $VDR_MAX_SVDRP_LENGTH)) { Log(LOG_FATALERROR, "[INT] SendCMD(): command is too long(" . length($cmd) . "): " . substr($cmd, 0, 10)); return; } @@ -1900,7 +2020,7 @@ sub AT_ProgTimer { last; } if ($start_fmt eq my_strftime("%H%M", $_->{start})) { - if ($VDRVERSION < 10323) { + if ($FEATURES{VDRVERSION} < 10323) { if ($_->{dor} == my_strftime("%d", $start)) { $found = 1; last; @@ -1936,7 +2056,7 @@ sub AT_ProgTimer { $at->{prio} ne "" ? $at->{prio} : $CONFIG{AT_PRIORITY}, $at->{lft} ne "" ? $at->{lft} : $CONFIG{AT_LIFETIME}, $title, - append_timer_metadata($VDRVERSION < 10344 ? $summary : undef, + append_timer_metadata($FEATURES{VDRVERSION} < 10344 ? $summary : undef, $event_id, $autotimer, $at->{buffers} ? ($at->{bstart} eq "" ? $CONFIG{AT_MARGIN_BEGIN} : $at->{bstart}) : $CONFIG{TM_MARGIN_BEGIN}, @@ -2180,7 +2300,7 @@ sub CheckTimers { sub epgsearch_list { return if (UptoDate() != 0); - if ($EPGSEARCH_VERSION < 923) { + if ($FEATURES{EPGSEARCH_VERSION} < 924) { HTMLError("Your version of epgsearch plugin is too old! You need at least v0.9.23!"); return } @@ -2601,6 +2721,8 @@ sub ExtractEpgSearchConf { $timer->{searchtimer_from}, #48 - useAsSearchTimerFrom (if "use as search timer?" = 2) $timer->{searchtimer_until}, #49 - useAsSearchTimerTil (if "use as search timer?" = 2) $timer->{ignore_missing_epgcats}, #50 - ignoreMissingEPGCats + $timer->{unmute}, #51 - unmute sound if off when used as switch timer + $timer->{min_match}, #52 - the minimum required match in percent when descriptions are compared to avoid repeats (-> 33) $timer->{unused}) = split(/:/, $line); #format selected fields @@ -2613,9 +2735,13 @@ sub ExtractEpgSearchConf { if ($timer->{action} == 0) { $timer->{action_text} = gettext("record"); } elsif ($timer->{action} == 1) { - $timer->{action_text} = gettext("announce only"); + $timer->{action_text} = gettext("announce by OSD"); } elsif ($timer->{action} == 2) { $timer->{action_text} = gettext("switch only"); + } elsif ($timer->{action} == 3) { + $timer->{action_text} = gettext("announce and switch"); + } elsif ($timer->{action} == 4) { + $timer->{action_text} = gettext("announce by mail"); } else { $timer->{action_text} = gettext("unknown"); } @@ -2808,7 +2934,7 @@ sub epgsearch_Param2Line { . ($q->param("use_extepg") ? "1" : "0") . ":" . $extepg_info . ":" . $q->param("fuzzy_tolerance") . ":" - . $q->param("ignore_missing_epgcats"); + . $q->param("ignore_missing_epgcats"); } else { # ! $mode_blacklist $cmd .= $q->param("has_action") . ":" . ($q->param("use_days") ? "1" : "0") . ":" @@ -2845,6 +2971,11 @@ sub epgsearch_Param2Line { . $searchtimer_from . ":" . $searchtimer_until . ":" . $q->param("ignore_missing_epgcats"); + + if ($FEATURES{EPGSEARCH_VERSION} >= 925) { + $cmd .= ":" . $q->param("unmute") . ":" + . $q->param("min_match"); + } } $cmd .= ":" . $q->param("unused") if ($q->param("unused")); @@ -3290,10 +3421,10 @@ sub append_timer_metadata { if ($tool == $TOOL_AUTOTIMER) { # remove old autotimer info $aux =~ s/\|?<vdradmin-am>.*<\/vdradmin-am>//i if ($aux); - $aux = substr($aux, 0, 9000) if ($VDRVERSION < 10336 and length($aux) > 9000); + $aux = substr($aux, 0, 9000) if ($FEATURES{VDRVERSION} < 10336 and length($aux) > 9000); # add a new line if VDR<1.3.44 because then there might be a summary - $aux .= "|" if ($VDRVERSION < 10344 and length($aux)); + $aux .= "|" if ($FEATURES{VDRVERSION} < 10344 and length($aux)); $aux .= "<vdradmin-am>"; $aux .= "<epgid>$epg_id</epgid>" if ($epg_id); $aux .= "<autotimer>$autotimer</autotimer>" if ($autotimer); @@ -3304,10 +3435,10 @@ sub append_timer_metadata { } elsif ($tool == $TOOL_EPGSEARCH) { # remove old epgsearch info $aux =~ s/\|?<epgsearch>.*<\/epgsearch>//i if ($aux); - $aux = substr($aux, 0, 9000) if ($VDRVERSION < 10336 and length($aux) > 9000); + $aux = substr($aux, 0, 9000) if ($FEATURES{VDRVERSION} < 10336 and length($aux) > 9000); # add a new line if VDR<1.3.44 because then there might be a summary - $aux .= "|" if ($VDRVERSION < 10344 and length($aux)); + $aux .= "|" if ($FEATURES{VDRVERSION} < 10344 and length($aux)); $aux .= "<epgsearch>"; $aux .= "<eventid>$epg_id</eventid>" if ($epg_id); $aux .= "<update>$autotimer</update>" if (defined $autotimer); @@ -3341,8 +3472,13 @@ sub LoadTranslation { ); setlocale(LC_ALL, $CONFIG{LANG}); - $LANG = $CONFIG{LANG}; - $MY_ENCODING = gettext("ISO-8859-1"); + if (! $CONFIG{LANG} eq '') { + setlocale(LC_ALL, $CONFIG{LANG}); + chomp($MY_ENCODING = `LC_ALL=$CONFIG{LANG} locale charmap`); + } + else { + chomp($MY_ENCODING = `locale charmap`); + } bind_textdomain_codeset("vdradmin", $MY_ENCODING) if($can_use_bind_textdomain_codeset); CGI::charset($MY_ENCODING); } @@ -3361,7 +3497,7 @@ sub ProgTimer { my $send_cmd = $timer_id ? "modt $timer_id" : "newt"; my $send_dor = $dor ? $dor : RemoveLeadingZero(strftime("%d", localtime($start))); - my $send_summary = ($VDRVERSION >= 10336) ? $summary : substr($summary, 0, $VDR_MAX_SVDRP_LENGTH - 9 - length($send_cmd) - length($active) - length($channel) - length($send_dor) - 8 - length($prio) - length($lft) - length($title)); + my $send_summary = ($FEATURES{VDRVERSION} >= 10336) ? $summary : substr($summary, 0, $VDR_MAX_SVDRP_LENGTH - 9 - length($send_cmd) - length($active) - length($channel) - length($send_dor) - 8 - length($prio) - length($lft) - length($title)); Log(LOG_DEBUG, sprintf("[SVDRP] ProgTimer: Programming Timer \"%s\" (Channel %s, Event-ID %s, %s - %s, Active %s)", $title, $channel, $event_id, my_strftime("%Y%m%d-%H%M", $start), my_strftime("%Y%m%d-%H%M", $stop), $active)); my $return = SendCMD(sprintf("%s %s:%s:%s:%s:%s:%s:%s:%s:%s", $send_cmd, $active, $channel, $send_dor, strftime("%H%M", localtime($start)), strftime("%H%M", localtime($stop)), $prio, $lft, trim($title), $send_summary)); @@ -3472,12 +3608,12 @@ sub UptoDate { sub Log { if ($#_ >= 1) { - my $level = shift; - my $message = join("", @_); - # Logging is always on in non-daemon mode return 1 unless ($CONFIG{LOGGING} || !$DAEMON); + my $level = shift; + chomp(my $message = join("", @_)); + my $my_loglevel = $CONFIG{LOGLEVEL}; $my_loglevel = $LOGLEVEL if $LOGLEVEL; if ($my_loglevel >= shift @$level) { @@ -3485,10 +3621,10 @@ sub Log { # Always log to stderr in non-daemon mode my $logfile = $DAEMON ? $CONFIG{LOGFILE} : "stderr"; - if ($logfile eq "stderr") { - printf STDERR "%s: %s\n", my_strftime("%x %X"), $message; - } elsif ($logfile eq "syslog") { + if ($LOG_TO_SYSLOG) { syslog(shift @$level, '%s', $message); + } elsif ($logfile eq "stderr" || $logfile eq "syslog") { + printf STDERR "%s: %s\n", my_strftime("%x %X"), $message; } else { if (open(LOGFILE, ">>", "$LOGDIR/$logfile")) { printf LOGFILE "%s: %s\n", my_strftime("%x %X"), $message; @@ -3597,6 +3733,9 @@ sub ValidConfig { $CONFIG{AT_OFFER} = 1; } } + + $CONFIG{GUI_POPUP_WIDTH} = 500 unless ($CONFIG{GUI_POPUP_WIDTH} =~ /\d+/); + $CONFIG{GUI_POPUP_HEIGHT} = 250 unless ($CONFIG{GUI_POPUP_HEIGHT} =~ /\d+/); } sub ReadConfig { @@ -3768,6 +3907,8 @@ sub prog_detail { my ($channel_name, $title, $subtitle, $vps, $video, $audio, $start, $stop, $text, @epgimages); + my @timers = ParseTimer(0); + if ($q->param("channel_id")) { $vdr_id = get_vdrid_from_channelid($q->param("channel_id")); } @@ -3838,6 +3979,14 @@ sub prog_detail { $recurl = sprintf("%s?aktion=timer_new_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $epg_id, $vdr_id, Encode_Referer($referer)) unless ($referer =~ "timer_list"); $editurl = sprintf("%s?aktion=prog_detail_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $epg_id, $vdr_id, Encode_Referer($referer)); + my $timerset = 0; + foreach my $timer (@timers) { + if (($timer->{vdr_id} == $vdr_id) && ($timer->{start} <= $start) && ($timer->{stop} >= $stop)) { + $timerset = 1; + last; + } + } + my $now = time(); my $vars = { title => $displaytitle ? $displaytitle : gettext("Can't find EPG entry!"), recurl => $recurl, @@ -3860,6 +4009,7 @@ sub prog_detail { video => $video, vdr_id => $vdr_id, epg_id => $epg_id, + timerset => $timerset, }; return showTemplate("prog_detail.html", $vars); } @@ -3994,6 +4144,7 @@ sub prog_list { } my $myself = Encode_Referer($MyURL . "?" . $Query); + my @timers = ParseTimer(0); # my (@channel, $current); @@ -4086,12 +4237,32 @@ sub prog_list { $srch2_url =~ s/\%TITLE\%/$search_title/g; } + my $subtitle = ""; + if ($CONFIG{EPG_SUBTITLE}) { + $subtitle = CGI::escapeHTML($event->{subtitle}); + } + if ($CONFIG{EPG_SUMMARY}) { + if (length($subtitle)) { + $subtitle .= "<BR />"; + } + $subtitle .= CGI::escapeHTML($event->{summary}); + $subtitle =~ s/\|/<BR \/>/g; + } + + my $timerset = 0; + foreach my $timer (@timers) { + if (($timer->{vdr_id} == $vdr_id) && ($timer->{start} <= $event->{start}) && ($timer->{stop} >= $event->{stop})) { + $timerset = 1; + last; + } + } + push(@show, { ssse => $event->{start}, emit => my_strftime("%H:%M", $event->{start}), duration => my_strftime("%H:%M", $event->{stop}), title => CGI::escapeHTML($event->{title}), - subtitle => CGI::escapeHTML($event->{subtitle}), + subtitle => $subtitle, recurl => sprintf("%s?aktion=timer_new_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->{event_id}, $event->{vdr_id}, $myself), infurl => $event->{summary} ? sprintf("%s?aktion=prog_detail&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->{event_id}, $event->{vdr_id}, $myself) : undef, editurl => sprintf("%s?aktion=prog_detail_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->{event_id}, $event->{vdr_id}, $myself), @@ -4101,7 +4272,8 @@ sub prog_list { srch2_url => $srch2_url, srch2_title => $srch2_url ? gettext($CONFIG{SRCH2_TITLE}) : undef, newd => 0, - anchor => "id" . $event->{event_id} + anchor => "id" . $event->{event_id}, + timerset => $timerset } ); $progname = $event->{progname}; @@ -4142,11 +4314,14 @@ sub prog_list2 { $day = $q->param("day") if ($q->param("day")); my $param_time = $q->param("time"); $CONFIG{CHANNELS_WANTED_PRG2} = $q->param("wanted_channels") if (defined $q->param("wanted_channels")); + my ($start_hour, $start_min) = getSplittedTime($CONFIG{EPG_START_TIME}); + my $day_start = (($start_hour * 60) + $start_min) * 60; # my $vdr_id; my @channel; my $myself = Encode_Referer($MyURL . "?" . $Query); + my @timers = ParseTimer(0); for my $channel (@{$CHAN{$CONFIG{CHANNELS_WANTED_PRG2}}->{channels}}) { @@ -4182,8 +4357,8 @@ sub prog_list2 { my $dayflag = 0; for my $event (@{ $EPG{$vdr_id} }) { - my $event_day = my_strftime("%d.%m.", $event->{start}); - my $event_day_long = my_strftime("%Y%m%d", $event->{start}); + my $event_day = my_strftime("%d.%m.", $event->{start}-$day_start); + my $event_day_long = my_strftime("%Y%m%d", $event->{start}-$day_start); $hash_days{$event_day_long} = $event_day unless(exists $hash_days{$event_day_long}); @@ -4226,12 +4401,32 @@ sub prog_list2 { $srch2_url =~ s/\%TITLE\%/$search_title/g; } + my $subtitle = ""; + if ($CONFIG{EPG_SUBTITLE}) { + $subtitle = CGI::escapeHTML($event->{subtitle}); + } + if ($CONFIG{EPG_SUMMARY}) { + if (length($subtitle)) { + $subtitle .= "<BR />"; + } + $subtitle .= CGI::escapeHTML($event->{summary}); + $subtitle =~ s/\|/<BR \/>/g; + } + + my $timerset = 0; + foreach my $timer (@timers) { + if (($timer->{vdr_id} == $vdr_id) && ($timer->{start} <= $event->{start}) && ($timer->{stop} >= $event->{stop})) { + $timerset = 1; + last; + } + } + push(@show, { ssse => $event->{start}, emit => my_strftime("%H:%M", $event->{start}), duration => my_strftime("%H:%M", $event->{stop}), title => CGI::escapeHTML($event->{title}), - subtitle => CGI::escapeHTML($event->{subtitle}), + subtitle => $subtitle, recurl => sprintf("%s?aktion=timer_new_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->{event_id}, $event->{vdr_id}, $myself), infurl => $event->{summary} ? sprintf("%s?aktion=prog_detail&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->{event_id}, $event->{vdr_id}, $myself) : undef, editurl => sprintf("%s?aktion=prog_detail_form&epg_id=%s&vdr_id=%s&referer=%s", $MyURL, $event->{event_id}, $event->{vdr_id}, $myself), @@ -4241,7 +4436,8 @@ sub prog_list2 { srch2_url => $srch2_url, srch2_title => $srch2_url ? gettext($CONFIG{SRCH2_TITLE}) : undef, newd => 0, - anchor => "id" . $event->{event_id} + anchor => "id" . $event->{event_id}, + timerset => $timerset } ); $progname = $event->{progname}; @@ -4341,7 +4537,7 @@ sub timer_list { for my $timer (ParseTimer(0)) { # VDR >= 1.3.24 reports if it's recording, so don't overwrite it here - if ($VDRVERSION < 10324 && $timer->{recording} == 0 && $timer->{startsse} < time() && $timer->{stopsse} > time() && ($timer->{active} & 1)) { + if ($FEATURES{VDRVERSION} < 10324 && $timer->{recording} == 0 && $timer->{startsse} < time() && $timer->{stopsse} > time() && ($timer->{active} & 1)) { $timer->{recording} = 1; } $timer->{active} = 0 unless ($timer->{active} & 1); @@ -4661,7 +4857,7 @@ sub timer_new_form { } # Do NOT append EPG summary if VDR >= 10344 as this will be done by VDR itself - $this_event->{summary} = $this->{summary} if ($VDRVERSION < 10344); + $this_event->{summary} = $this->{summary} if ($FEATURES{VDRVERSION} < 10344); $this_event->{vdr_id} = $this->{vdr_id}; } elsif ($timer_id) { # edit existing timer $this_event = ParseTimer(0, $timer_id); @@ -5474,6 +5670,8 @@ sub prog_summary { $CONFIG{PS_VIEW} = $view; $CONFIG{CHANNELS_WANTED_SUMMARY} = $q->param("wanted_channels") if (defined $q->param("wanted_channels")); + my @timers = ParseTimer(0); + # zeitpunkt bestimmen my $event_time = getStartTime($time); @@ -5561,6 +5759,15 @@ sub prog_summary { } my $myself = Encode_Referer($MyURL . "?" . $Query); my $running = $event->{start} <= $now && $now <= $event->{stop}; + + my $timerset = 0; + foreach my $timer (@timers) { + if (($timer->{vdr_id} == $event->{vdr_id}) && ($timer->{start} <= $event->{start}) && ($timer->{stop} >= $event->{stop})) { + $timerset = 1; + last; + } + } + push(@show, { date => my_strftime("%x", $event->{start}), longdate => my_strftime("%A, %x", $event->{start}), @@ -5588,7 +5795,8 @@ sub prog_summary { srch1_title => $imdb_url ? gettext($CONFIG{SRCH1_TITLE}) : undef, srch2_url => $srch2_url, srch2_title => $srch2_url ? gettext($CONFIG{SRCH2_TITLE}) : undef, - anchor => "id" . $event->{event_id} + anchor => "id" . $event->{event_id}, + timerset => $timerset } ); last if (!$search); @@ -5892,7 +6100,7 @@ sub ParseRecordings { # my $yearofrecording; - if ($VDRVERSION >= 10326) { + if ($FEATURES{VDRVERSION} >= 10326) { # let localtime() decide about the century $yearofrecording = substr($date, 6, 2); @@ -5933,8 +6141,8 @@ sub ParseRecordings { delurl => $MyURL . "?aktion=rec_delete&rec_delete=y&id=$id", editurl => $FEATURES{REC_RENAME} ? $MyURL . "?aktion=rec_edit&id=$id" : undef, infurl => $MyURL . "?aktion=rec_detail&id=$id", - playurl => $VDRVERSION >= 10331 ? $MyURL . "?aktion=rec_play&id=$id" : undef, #TODO - cuturl => $VDRVERSION >= 10331 ? $MyURL . "?aktion=rec_cut&id=$id" : undef, #TODO + playurl => $FEATURES{VDRVERSION} >= 10331 ? $MyURL . "?aktion=rec_play&id=$id" : undef, #TODO + cuturl => $FEATURES{VDRVERSION} >= 10331 ? $MyURL . "?aktion=rec_cut&id=$id" : undef, #TODO streamurl => ($CONFIG{ST_FUNC} && $CONFIG{ST_REC_ON}) ? $MyStreamBase . $CONFIG{REC_EXT} . "?aktion=rec_stream&id=$id" : undef } ); @@ -5978,7 +6186,7 @@ sub getRecInfo { chomp($title); my $vars; - if ($VDRVERSION >= 10325) { + if ($FEATURES{VDRVERSION} >= 10325) { $SVDRP->command("lstr $id"); my ($channel_name, $subtitle, $text, $video, $audio); while ($_ = $SVDRP->readoneline) { @@ -6296,7 +6504,7 @@ sub config { } # vdradmind.conf writable? - $error_msg .= sprintf(gettext("Configuration file %s not writeable! Configuration won't be saved!") . "<br />", $CONFFILE) unless (-w $CONFFILE); + $error_msg .= sprintf(gettext("Configuration file %s not writable! Configuration won't be saved!") . "<br />", $CONFFILE) unless (-w $CONFFILE); # my @LOGINPAGES_DESCRIPTION = (gettext("What's On Now?"), gettext("Playing Today?"), gettext("Timeline"), gettext("Channels"), gettext("Timers"), gettext("Recordings")); @@ -6481,8 +6689,7 @@ sub show_help { # information ############################################################################# sub about { - my $vars = { vdrversion => $VDRVERSION_HR, - myversion => $VERSION + my $vars = { }; return showTemplate("about.html", $vars); } @@ -6509,7 +6716,7 @@ sub grab_picture { ($width, $height) = ($maxwidth / 4, $maxheight / 4); } - if ($VDRVERSION < 10338) { + if ($FEATURES{VDRVERSION} < 10338) { # Grab using temporary file my $file = new File::Temp(TEMPLATE => "vdr-XXXXX", DIR => File::Spec->tmpdir(), UNLINK => 1, SUFFIX => ".jpg"); @@ -6553,6 +6760,8 @@ sub loadCommandsConf { s/^\s+//; s/\s+$//; next unless length; + next if (/{$/); + next if (/^}$/); my ($title, $cmd) = split(":", $_); push(@commands, { title => $title, cmd => $cmd, id => $id }); $id = $id + 1; @@ -6705,7 +6914,7 @@ sub myconnect { main::Log(LOG_DEBUG, "[SVDRP] Connecting to $CONFIG{VDR_HOST}:$CONFIG{VDR_PORT}"); $SOCKET = - $InetSocketModule->new(PeerAddr => $CONFIG{VDR_HOST}, + $VdrSocketModule->new(PeerAddr => $CONFIG{VDR_HOST}, PeerPort => $CONFIG{VDR_PORT}, Proto => 'tcp' ) @@ -6714,25 +6923,26 @@ sub myconnect { $connected = true; my $line; $line = <$SOCKET>; - if (!$VDRVERSION) { - $line =~ /^220.*VideoDiskRecorder (\d+)\.(\d+)\.(\d+).*;/; - $VDRVERSION_HR = "$1.$2.$3"; - $VDRVERSION = ($1 * 10000 + $2 * 100 + $3); - $line =~ /^220.*VideoDiskRecorder (\d+)\.(\d+)\.(\d+).*; .*; (.*)\r|$/; - $VDR_ENCODING = $4; - $need_recode = ($can_use_encode and $VDR_ENCODING and $VDR_ENCODING ne $MY_ENCODING) ? 1 : 0; + if (!$FEATURES{VDRVERSION}) { + $line =~ /^220.*VideoDiskRecorder (\d+)\.(\d+)\.(\d+)([^;]*);/; + $FEATURES{VDRVERSION_HR} = "$1.$2.$3$4"; + $FEATURES{VDRVERSION} = ($1 * 10000 + $2 * 100 + $3); getSupportedFeatures($this); } + $line =~ /^220.*VideoDiskRecorder (\d+)\.(\d+)\.(\d+).*; .*; (.*)\r|$/; + $VDR_ENCODING = $4; + $need_recode = ($can_use_encode and $VDR_ENCODING and $VDR_ENCODING ne $MY_ENCODING) ? 1 : 0; } sub getSupportedFeatures { my $this = shift; - if ($VDRVERSION >= 10331) { + if ($FEATURES{VDRVERSION} >= 10331) { command($this, "plug"); while ($_ = readoneline($this)) { - if ($_ =~ /^epgsearch v(\d+)\.(\d+)\.(\d+)/) { + if ($_ =~ /^epgsearch v(\d+)\.(\d+)\.(\d+)([^ ]*)/) { $FEATURES{EPGSEARCH} = 1; - $EPGSEARCH_VERSION = ($1 * 10000 + $2 * 100 + $3); + $FEATURES{EPGSEARCH_VERSION} = ($1 * 10000 + $2 * 100 + $3); + $FEATURES{EPGSEARCH_VERSION_HR} = "$1.$2.$3$4"; } if ($_ =~ /^streamdev-server/) { $FEATURES{STREAMDEV} = 1; @@ -6769,6 +6979,7 @@ sub command { main::Log(LOG_DEBUG, sprintf("[SVDRP] Sending \"%s\"", $cmd)); $cmd = $cmd . CRLF; if ($SOCKET && $SOCKET->connected()) { + Encode::from_to($cmd, $MY_ENCODING, $VDR_ENCODING) if ($need_recode); my $result = send($SOCKET, $cmd, 0); if ($result != length($cmd)) { main::HTMLError(sprintf($ERROR_MESSAGE{send_command}, $CONFIG{VDR_HOST})); |