summaryrefslogtreecommitdiff
path: root/Tools/master-timer/master-timer.pl
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/master-timer/master-timer.pl')
-rwxr-xr-xTools/master-timer/master-timer.pl1169
1 files changed, 1169 insertions, 0 deletions
diff --git a/Tools/master-timer/master-timer.pl b/Tools/master-timer/master-timer.pl
new file mode 100755
index 0000000..3b98acc
--- /dev/null
+++ b/Tools/master-timer/master-timer.pl
@@ -0,0 +1,1169 @@
+#!/usr/bin/perl -w
+
+use strict;
+# For the TCP-Connection to VDR
+use Socket;
+# For converting the Timers, read from VDR, back to Unix-Timestamps
+use Time::Local;
+
+# Debugmode
+# You have to add the following numbers to build the debug-var
+# 1 : Dump the "torecord"
+# 2 : Dump all timers
+# 4 : Show when a timer will be deleted
+# 8 : Dump the "Done" REs
+# 16 : Verbose Config-Reading
+my $debug = 0;
+
+# The Supervariable Program
+# %Program{$title}{$channel}{$time}{duration}
+# {subtitle}
+# {description}
+
+# The Supervariable Timer
+# %Timer{$time}{$channel}{$title}{duration}
+# {subtitle}
+# {prio}
+# {real_title}
+# {VDR} (Already programmed)
+# The Value of VDR is ">0" for the position in the Timer-List or "R" for a "Repeating" Timer.
+# A Value of >1.000.000 is a Master Timer-Timer which is already programmed into VDR
+
+# Variable-Definition
+my (%Program, @channels, %channels, %Timer);
+
+# Which Subtitles are Movies
+my ($subtitle_movie);
+
+# Blacklist
+my ($title_deepblack);
+
+# What is already recorded/Should not be recorded
+my ($title_done, $subtitle_done);
+
+# What to record
+my ($title_torecord, $subtitle_torecord, $description_torecord, @title_torecord, @subtitle_torecord, @description_torecord, @channel_torecord, @timeframe_torecord, @prio_torecord, @timer_title_torecord, $num_torecord, @marginstart_torecord, @marginstop_torecord, @machine_torecord);
+
+# Default Priority for Timers (Config: defaultprio)
+my $default_prio = 50;
+
+# How many DVB-S cards are there (Config: DVBCards)
+my $DVB_cards = 1;
+
+# How many seconds to substract from the time and to add to the duration
+my $marginstart = 60*10; # Config: Marginstart
+my $marginstop = 60*10; # Config: Marginstop
+
+# Shall Timers, on the same channel, be joined if they overlap
+my $jointimers = 0;
+
+# Hostname/IP of DVB-Computer and the Port of VDR
+my @Dest = ("localhost:2001"); # Config: Dest
+
+# Which VDR-Instance shall be used
+my $currentVDR = 1;
+
+# Working-Variables
+my ($title, $duration, $subtitle, $channel, $time, $description, $hit);
+my (@time, @date);
+
+sub sub_die
+ {
+ my ($error) = @_;
+ &closesocket();
+ die "$error";
+ }
+
+
+if ($ARGV[0])
+ {
+ $currentVDR = $ARGV[0];
+ }
+
+&init();
+&dumpdone() if ($debug & 8);
+&dumptorecord() if ($debug & 1);
+&fetchVDRTimers();
+&process_torecord();
+print "Timers before joining\n" if ($debug & 2 && $jointimers);
+&dumptimers() if ($debug & 2);
+if ($jointimers)
+ {
+ &jointimers();
+ print "Timers after joining\n" if ($debug & 2);
+ &dumptimers() if ($debug & 2);
+ }
+
+&printtimers();
+&transfertimers();
+&closesocket();
+
+#
+# Subfunctions
+#
+
+sub dumpdone()
+ {
+ print "Start Done-dump\n";
+ print "Titledone: \"$title_done\"\n";
+ print "Subtitledone \"$subtitle_done\"\n";
+ print "End Done-dump\n";
+ }
+
+sub dumptorecord()
+ {
+ print "Start Torecord-dump\n";
+ print "Regex-Title: $title_torecord\n";
+ print "Regex-Subtitle: $subtitle_torecord\n";
+ print "Regex-Description: $description_torecord\n";
+ foreach my $num (0 .. $num_torecord)
+ {
+ print "Timer Number $num: ";
+
+ print "Title: \"$title_torecord[$num]\" " if ($title_torecord[$num]);
+ print "Title: \"\" " unless ($title_torecord[$num]);
+
+ print "Subtitle: \"$subtitle_torecord[$num]\" "if ($subtitle_torecord[$num]);
+ print "Subtitle: \"\" " unless ($subtitle_torecord[$num]);
+
+ print "Description: \"$description_torecord[$num]\" " if ($description_torecord[$num]);
+ print "Description: \"\" " unless ($description_torecord[$num]);
+
+ print "Timeframe: \"$timeframe_torecord[$num]\" " if ($timeframe_torecord[$num]);
+ print "Timeframe: \"\" " unless ($timeframe_torecord[$num]);
+
+ print "Channel: \"". join (";",@{$channel_torecord[$num]})."\" " if ($channel_torecord[$num]);
+ print "Channel: \"\" " unless ($channel_torecord[$num]);
+
+ print "Prio: \"$prio_torecord[$num]\" " if ($prio_torecord[$num]);
+ print "Prio: \"\" " unless ($prio_torecord[$num]);
+
+ print "Timertitle: \"$timer_title_torecord[$num]\" " if ($timer_title_torecord[$num]);
+ print "Timertitle: \"\" " unless ($timer_title_torecord[$num]);
+
+ print "Marginstart: \"$marginstart_torecord[$num]\" " if ($marginstart_torecord[$num]);
+ print "Marginstart: \"\" " unless ($marginstart_torecord[$num]);
+
+ print "Marginstop: \"$marginstop_torecord[$num]\" " if ($marginstop_torecord[$num]);
+ print "Marginstop: \"\" " unless ($marginstop_torecord[$num]);
+
+ print "Machine: \"$machine_torecord[$num]\" " if ($machine_torecord[$num]);
+ print "Machine: \"\" " unless ($machine_torecord[$num]);
+
+ print "\n";
+ }
+ print "End Torecord-dump\n";
+ }
+
+sub dumptimers()
+ {
+ print "Start Timers-dump\n";
+ foreach $time (sort {$a <=> $b} keys %Timer)
+ {
+ foreach $channel (sort keys %{%Timer->{$time}})
+ {
+ foreach $title (sort keys %{%Timer->{$time}->{$channel}})
+ {
+ my ($prio, @time, @date, @time2);
+ my ($realtitle);
+ @time = &GetTime ($time);
+ @date = &GetDay ($time);
+ @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration});
+ $subtitle = $Timer{$time}{$channel}{$title}{subtitle};
+ $prio = $Timer{$time}{$channel}{$title}{prio};
+ $realtitle = $Timer{$time}{$channel}{$title}{real_title};
+ print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\":$Timer{$time}{$channel}{$title}{VDR}\n";
+ }
+ }
+ }
+ print "End Timers-dump\n";
+ }
+
+sub printtimers()
+ {
+ foreach $time (sort {$a <=> $b} keys %Timer)
+ {
+ foreach $channel (sort keys %{%Timer->{$time}})
+ {
+ foreach $title (sort keys %{%Timer->{$time}->{$channel}})
+ {
+ my ($prio, @time, @date, @time2);
+ if ($Timer{$time}{$channel}{$title}{VDR} eq 0)
+ {
+ my ($realtitle);
+ @time = &GetTime ($time);
+ @date = &GetDay ($time);
+ @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration});
+ $subtitle = $Timer{$time}{$channel}{$title}{subtitle};
+ $prio = $Timer{$time}{$channel}{$title}{prio};
+ $realtitle = $Timer{$time}{$channel}{$title}{real_title};
+
+ print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"\n";
+ }
+ }
+ }
+ }
+ }
+
+sub transfertimers()
+ {
+ foreach $time (sort {$a <=> $b} keys %Timer)
+ {
+ foreach $channel (sort keys %{%Timer->{$time}})
+ {
+ foreach $title (sort keys %{%Timer->{$time}->{$channel}})
+ {
+ my ($prio, @time, @date, @time2, $realtitle, $result);
+ if ($Timer{$time}{$channel}{$title}{VDR} eq 0)
+ {
+ @time = &GetTime ($time);
+ @date = &GetDay ($time);
+ @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration});
+ $subtitle = $Timer{$time}{$channel}{$title}{subtitle};
+ $prio = $Timer{$time}{$channel}{$title}{prio};
+ $realtitle = $Timer{$time}{$channel}{$title}{real_title};
+
+ ($result) = GetSend ("newt 2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"");
+ print "Timer: $result" if ($debug & 2);
+ }
+ }
+ }
+ }
+ }
+
+# Convert the Unix-Time-Stamp into "month" and "Day of month"
+sub GetDay
+ {
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift);
+ $mon++;
+ $mon = sprintf ("%02i",$mon);
+ $mday = sprintf ("%02i",$mday);
+ return ($mon, $mday);
+ }
+
+# Convert the Unix-Time-Stramp into "hour" and "minute"
+sub GetTime
+ {
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift);
+ $hour = sprintf ("%02i",$hour);
+ $min = sprintf ("%02i",$min);
+ return ($hour, $min);
+ }
+
+# Workaround some EPG-Bugs
+sub correct_epg_data
+ {
+ if ($subtitle)
+ {
+ # For Pro-7. Remove $title from $subtitle
+ $subtitle =~ s/$title\s\/\s//;
+
+ # For VOX & VIVA. The Format it '"<Subtitle>". <Description>'
+ if ($subtitle =~ /^\"(.*?)\"\.\s(.*)/)
+ {
+ # Lets see if there are Channels that where the VOX/VIVA scheme matches, but also have a description
+ if ($description)
+ {
+ sub_die ("Subtitle: \"$subtitle\"\nDescription\"$description\"\n");
+ }
+ $subtitle = $1;
+ $description = $2;
+ }
+ elsif ($channel eq "VIVA")
+ {
+ if ($subtitle =~ /^\s(.*)/)
+ {
+ $subtitle = "";
+ $description = $1;
+ }
+ }
+ }
+
+ # Workaround for the broken PRO-7/Kabel-1 EPG-Date. If Time is between 00.00 and 05.00 the time is shifted forward by a day
+ if ($channel eq "Pro-7" || $channel eq "Kabel-1")
+ {
+ my (@time);
+ @time = GetTime ($time);
+ if ($time[0] >= 0 && ($time[0] <= 4 || ($time[0] == 5 && $time[1] == 0)))
+ {
+ $time += 24*60*60;
+ }
+ }
+}
+
+# Add a Recording into the "to record"-List
+sub addtimer
+ {
+ my ($hit, $title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $VDR, $time2, $title2, $channel2, $marginstart, $marginstop);
+ ($title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $VDR, $marginstart, $marginstop) = @_;
+# print "Title: \"$title\" Realtitle: \"$realtitle\" Subtitle: \"$subtitle\" Channel: \"$channel\" Time: \"$time\" Duration: \"$duration\" Prio: \"$prio\" VDR: \"$VDR\"\n";
+
+ $hit = 1;
+
+ foreach $time2 (sort keys %Timer)
+ {
+ foreach $title2 (sort keys %{%Timer->{$time2}->{$channel}})
+ {
+ my ($ctime, $ctime2);
+ $ctime = $time2;
+ $ctime2 = $time2 + $Timer{$time2}{$channel}{$title2}{duration};
+
+ if (($time >= $ctime) && ($time <= $ctime2))
+ {
+ undef $hit;
+ }
+ }
+ }
+
+
+ if ($hit)
+ {
+ $time -= $marginstart;
+ $duration += $marginstart + $marginstop;
+ $Timer{$time}{$channel}{$title}{duration}=$duration;
+ $Timer{$time}{$channel}{$title}{subtitle}=$subtitle;
+ $Timer{$time}{$channel}{$title}{prio}=$prio;
+ $Timer{$time}{$channel}{$title}{VDR}=$VDR;
+ $Timer{$time}{$channel}{$title}{real_title}=$realtitle;
+ }
+ }
+
+sub deltimer()
+ {
+ my ($time, $channel, $title, $delete_from_VDR);
+ ($time, $channel, $title, $delete_from_VDR) = @_;
+
+# if ($delete_from_VDR)
+# {
+# if ($Timer{$time}{$channel}{$title}{VDR})
+# {
+# if ($Timer{$time}{$channel}{$title}{VDR} =~ s/ ^R/)
+# {
+# print "Error: A Repeating-Timer can't be deleted from VDR: \"$title\"\n";
+# }
+# elsif ($Timer{$time}{$channel}{$title}{VDR} < 1000000)
+# {
+# print "A User-Programmed Timer has been deleted from VDR: \"$title\"\n";
+# }
+# else
+# {
+#
+# }
+# }
+# }
+
+ delete $Timer{$time}{$channel}{$title}{duration};
+ delete $Timer{$time}{$channel}{$title}{subtitle};
+ delete $Timer{$time}{$channel}{$title}{prio};
+ delete $Timer{$time}{$channel}{$title}{VDR};
+ delete $Timer{$time}{$channel}{$title}{real_title};
+ delete $Timer{$time}{$channel}{$title};
+ delete $Timer{$time}{$channel} if (keys %{ $Timer{$time}{$channel} } == 1);
+ delete $Timer{$time} if (keys %{ $Timer{$time} } == 1);
+ }
+
+sub jointimers
+ {
+ #
+ # FIXME: 2 Timers on the same channel will always be joined.
+ # It should be checked if there is another DVB-Card available.
+ #
+ # FIXME2: When one timer is already programmed in VDR, delete that timer in VDR.
+ my ($running, $counter, @times, $channel, $title, $channel2, $title2);
+ $running = 1;
+ outer: while ($running)
+ {
+ $counter = 0;
+ @times = sort {$a <=> $b} keys %Timer;
+
+ # We only need to check till the second last timer. The last one can't have a overlapping one.
+ while ($counter < $#times)
+ {
+ foreach $channel (sort keys %{%Timer->{$times[$counter]}})
+ {
+ foreach $title (sort keys %{%Timer->{$times[$counter]}->{$channel}})
+ {
+ if ($times[$counter + 1] < ($times[$counter] + $Timer{$times[$counter]}{$channel}{$title}{duration}))
+ {
+ foreach $channel2 (sort keys %{%Timer->{$times[$counter + 1]}})
+ {
+ foreach $title2 (sort keys %{%Timer->{$times[$counter + 1]}->{$channel}})
+ {
+ if ($channel eq $channel2)
+ {
+ my ($duration, $subtitle, $prio, $realtitle, $duration2, $subtitle2, $prio2, $realtitle2);
+ # Values from Lower-Timer
+ $duration = $Timer{$times[$counter]}{$channel}{$title}{duration};
+ $subtitle = $Timer{$times[$counter]}{$channel}{$title}{subtitle};
+ $prio = $Timer{$times[$counter]}{$channel}{$title}{prio};
+ $realtitle = $Timer{$times[$counter]}{$channel}{$title}{real_title};
+
+ # Values from Higher-Timer
+ $duration2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{duration};
+ $subtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{subtitle};
+ $prio2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{prio};
+ $realtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{real_title};
+
+ # Use the Higher Priority for the new Timer
+ $prio = ($prio > $prio2) ? $prio : $prio2;
+
+ # Delete the two "Obsolet" Timers
+ &deltimer ($times[$counter], $channel, $title);
+ &deltimer ($times[$counter + 1], $channel2, $title2);
+
+ # And set the new one
+ &addtimer ("$title + $title2", "$realtitle\~$realtitle2", "$subtitle\~$subtitle2", $channel, $times[$counter], $duration2 + ($times[$counter + 1 ] - $times[$counter]),$prio,0,0,0);
+
+ # Now a Value is "missing", so we will redo the whole thing. (This will do three-times JOIN correct)
+ redo outer;
+ }
+ }
+ }
+ }
+ }
+ }
+ $counter++;
+ }
+ undef $running;
+ }
+ }
+
+sub process_torecord
+ {
+ my ($first_hit, $prio, $timer_title);
+ foreach $title (sort keys %Program)
+ {
+ foreach $channel (sort keys %{%Program->{$title}})
+ {
+ foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}})
+ {
+ undef $hit;
+
+ # First look if any of the Title/Subtitle/Description REs match
+ if ($title =~ /$title_torecord/i)
+ {
+ $hit = 1;
+ }
+ elsif ($Program{$title}{$channel}{$time}{subtitle} && $Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_torecord/i)
+ {
+ $hit = 1;
+ }
+ elsif ($Program{$title}{$channel}{$time}{description} && $Program{$title}{$channel}{$time}{description} =~ /$description_torecord/i)
+ {
+ $hit = 1;
+ }
+
+ # Now look if we have a "exact" hit
+ if ($hit)
+ {
+ my ($counter);
+ undef $hit;
+ foreach $counter (0 .. $num_torecord)
+ {
+
+ if ($title_torecord[$counter])
+ {
+ if (!($title =~ /$title_torecord[$counter]/i))
+ {
+ next;
+ }
+ }
+
+ if ($subtitle_torecord[$counter])
+ {
+ if (!($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_torecord[$counter]/i))
+ {
+ next;
+ }
+ elsif (!$title_torecord[$counter] && !$description_torecord[$counter])
+ {
+ next;
+ }
+ }
+
+ if ($description_torecord[$counter])
+ {
+ if ($Program{$title}{$channel}{$time}{description})
+ {
+ if (!($Program{$title}{$channel}{$time}{description} =~ /$description_torecord[$counter]/i))
+ {
+ next;
+ }
+ }
+ elsif (!$title_torecord[$counter] && !$subtitle_torecord[$counter])
+ {
+ next;
+ }
+ }
+
+ if ($channel_torecord[$counter])
+ {
+ my ($hit);
+ # Blacklist-Mode
+ if ($channel_torecord[$counter][0] =~ /^!/)
+ {
+ $hit = 1;
+ foreach (0 .. $#{$channel_torecord[$counter]})
+ {
+ # Strip a possibel "!" Charactar
+ $channel_torecord[$counter][$_] =~ /^!?(.*)/;
+ if ($channel =~ /^$1$/)
+ {
+ undef $hit;
+ last;
+ }
+ }
+ }
+ # Whitelist-Mode
+ else
+ {
+ undef $hit;
+ foreach (0 .. $#{$channel_torecord[$counter]})
+ {
+ # Strip a possibel "!" Charactar
+ $channel_torecord[$counter][$_] =~ /^!?(.*)/;
+ if ($channel =~ /^$1$/)
+ {
+ $hit = 1;
+ last ;
+ }
+ }
+ }
+ if (!$hit)
+ {
+ next;
+ }
+ }
+
+ if ($timeframe_torecord[$counter])
+ {
+ my (@time, $time2, $ctime, $ctime2);
+ @time = GetTime($time);
+ $time2 = "$time[0]$time[1]";
+
+ ($ctime, $ctime2) = split (/\-/,$timeframe_torecord[$counter]);
+
+ if (!$ctime)
+ {
+ $ctime = "0";
+ }
+ if (!$ctime2)
+ {
+ $ctime2 = "2400";
+ }
+
+ if ($ctime < $ctime2)
+ {
+ if (!($time2 >= $ctime && $time2 <= $ctime2))
+ {
+ next;
+ }
+ }
+ else
+ {
+ if (!(($time2 >= $ctime && $time2 <= "2400") || ($time2 >= "0" && $time2 <= $ctime2)))
+ {
+ next;
+ }
+ }
+ }
+
+ if ($prio_torecord[$counter])
+ {
+ $prio = $prio_torecord[$counter];
+ }
+ else
+ {
+ $prio = 50;
+ }
+
+ # What Title to use for the timer
+ if ($timer_title_torecord[$counter])
+ {
+ $timer_title = $timer_title_torecord[$counter]
+ }
+ elsif ($title_torecord[$counter])
+ {
+ $timer_title = $title_torecord[$counter]
+ }
+ else
+ {
+ $timer_title = $title;
+ }
+
+ my ($subtitle);
+ if ($Program{$title}{$channel}{$time}{subtitle})
+ {
+ $subtitle = $Program{$title}{$channel}{$time}{subtitle};
+ }
+ else
+ {
+ $subtitle = "";
+ }
+
+ &addtimer ($timer_title,$title,$subtitle,$channel,$time,$Program{$title}{$channel}{$time}{duration},$prio,0,$marginstart_torecord[$counter],$marginstop_torecord[$counter]);
+ last;
+ }
+ }
+ }
+ }
+ }
+ }
+
+# Open the connection to VDR
+sub initsocket
+ {
+ my ($Dest, $Port) = split (/\:/,$Dest[$currentVDR - 1],2);
+ my $iaddr = inet_aton($Dest);
+ my $paddr = sockaddr_in($Port, $iaddr);
+
+ socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
+ connect(SOCKET, $paddr) or sub_die ("Can't connect to VDR\n");
+ select(SOCKET); $| = 1;
+ select(STDOUT);
+
+ while (<SOCKET>) {
+ last if substr($_, 3, 1) ne "-";
+ }
+ }
+
+# Send a command to VDR and read back the result
+sub GetSend
+ {
+ my ($command, @retval);
+
+ while ($command = shift)
+ {
+ print SOCKET "$command\r\n";
+ while (<SOCKET>) {
+ (@retval) = (@retval, $_);
+ last if substr($_, 3, 1) ne "-";
+ }
+ }
+
+ foreach my $retval (@retval)
+ {
+ $retval =~ s/\x0d//g;
+ }
+ return (@retval);
+ }
+
+# Close the socket to VDR
+sub closesocket
+ {
+ print SOCKET "Quit\r\n";
+ close(SOCKET);
+ }
+
+
+# Fetch the timers-List from VDR via SVDR and process it.
+sub fetchVDRTimers
+ {
+ my (@timers, $timer, $position, $active, $channel, $day, $start, $end, $prio, $ttl, $title, $subtitle, $minute, $duration);
+ my ($utime, $utime2);
+
+ # First fetch the timers-list from VDR
+ @timers = GetSend ("lstt");
+
+ foreach $timer (@timers)
+ {
+# $timer =~ s/\x0d//g;
+ chomp $timer;
+ # a Valid Timer-line beginns with "250"
+ if ($timer =~ s/250-|250\s//)
+ {
+ # Extract the Position in front of the line
+ ($position, $timer) = split (/\s/,$timer,2);
+
+# print "Position: \"$position\" Timer: \"$timer\"\n";
+ # Split the : seperated values
+ ($active, $channel, $day, $start, $end, $prio, $ttl, $title, $subtitle) = split (/\:/,$timer,9);
+
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+
+ # If the string is exactly 7 char wide, then its a "repeating"-timer
+ if ($active >= 1)
+ {
+ if ($day =~ /(.)(.)(.)(.)(.)(.)(.)/)
+ {
+ my (@days);
+ @days = ($1, $2, $3, $4, $5, $6, $7);
+ ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+
+ $start =~ /(\d\d)(\d\d)/;
+ $hour = $1;
+ $minute = $2;
+ $utime = timelocal 0, $minute, $hour, $mday, $mon, $year;
+ $end =~ /(\d\d)(\d\d)/;
+ $hour = $1;
+ $minute = $2;
+ $utime2 = timelocal 0, $minute, $hour, $mday, $mon, $year;
+ if ($end < $start)
+ {
+ $utime2 += 24*60*60;
+ }
+ $duration = $utime2 - $utime;
+
+ # "Normalize" the timestamp to monday
+ $utime = $utime - ($wday * 24 * 60 *60);
+
+ foreach my $num (0 .. $#days)
+ {
+ if ($days[$num] ne "-")
+ {
+ my $utime3;
+ # Todays before today will be shifted in the next week
+ if (($num + 1) < $wday)
+ {
+ $utime3 = $utime + (($num + 7 + 1) * 24 * 60 * 60);
+ }
+ else
+ {
+ $utime3 = $utime + (($num + 1) * 24 * 60 * 60);
+ }
+ &addtimer ($title,$title,$subtitle,$channels[$channel],$utime3,$duration,$prio,"R$position",0,0);
+ }
+ }
+ }
+
+ # When the Day-Value is between 1 and 31, then its a "One time" Timer
+ elsif (($day >= 1) && ($day <= 31))
+ {
+ if ($active == "2")
+ {
+ $position += 1000000;
+ }
+ # When the Day is before the Current-Day, then the Timer is for the next month
+ if ($day < $mday)
+ {
+ $mon++;
+ if ($mon == 12)
+ {
+ $mon = 0;
+ $year ++;
+ }
+ }
+ $start =~ /(\d\d)(\d\d)/;
+ $hour = $1;
+ $minute = $2;
+ $utime = timelocal 0, $minute, $hour, $day, $mon, $year;
+ $end =~ /(\d\d)(\d\d)/;
+ $hour = $1;
+ $minute = $2;
+ $utime2 = timelocal 0, $minute, $hour, $day, $mon, $year;
+ if ($end < $start)
+ {
+ $utime2 += 24*60*60;
+ }
+ $duration = $utime2 - $utime;
+
+ &addtimer ($title,$title,$subtitle,$channels[$channel],$utime,$duration,$prio,$position,0,0);
+ }
+ }
+ }
+ }
+ }
+
+# Parse file "epg.data"
+sub initepgdata
+ {
+ open (FI,"epg.data") or sub_die ("Can't open file \"epg.data\"\n");
+
+ while (<FI>)
+ {
+ # Begin Channel
+ if (/^C\s(\d+)\s+(.+)/)
+ {
+ $channel = $2;
+ while (<FI>)
+ {
+ # End Channel
+ if (/^c$/)
+ {
+ last;
+ }
+ # Begin Timer
+ elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/)
+ {
+ # Undef this Variables because it is possibel that not every timer uses this values
+ undef $duration;
+ undef $subtitle;
+ undef $description;
+
+ $time=$2;
+ $duration=$3;
+ }
+ # Title
+ elsif (/^T\s(.*)/)
+ {
+ $title = $1;
+ }
+ # Subtitle
+ elsif (/^S\s(.*)/)
+ {
+ $subtitle=$1;
+ }
+ # Description
+ elsif (/^D\s(.*)/)
+ {
+ $description=$1;
+ }
+ # End Timer
+ elsif (/^e$/)
+ {
+ # Only accept timers that are in the future
+ if ($time < time)
+ {
+ next;
+ }
+
+ # Work around the diffrent Bugs in the data
+ &correct_epg_data();
+
+ # Check if the title is in the DEEP-Blacklist
+ if ($title =~ /$title_deepblack/i)
+ {
+ next;
+ }
+
+ # Check if the Title & Subtitle is in the Done-List
+ if ($title =~ /$title_done/)
+ {
+ if ($subtitle)
+ {
+ if ($subtitle =~ /$subtitle_done/)
+ {
+ next;
+ }
+ }
+ }
+
+ $Program{$title}{$channel}{$time}{duration}=$duration;
+ if ($subtitle)
+ {
+ $Program{$title}{$channel}{$time}{subtitle}=$subtitle;
+ }
+ if ($description)
+ {
+ $Program{$title}{$channel}{$time}{description}=$description;
+ }
+ }
+ }
+ }
+ }
+ close (FI);
+ }
+
+# What is a Movie (When correctly stored into Subtitle)
+sub initmovie
+ {
+ my (@list,$list);
+ open (FI,"$ENV{HOME}/.master-timer/subtitle-movie") or return;
+ @list = <FI>;
+ close(FI);
+
+ foreach $list (@list)
+ {
+ chomp $list;
+ }
+ $subtitle_movie = join ('|',@list);
+ }
+
+# What should be blacklistet
+sub initblacklist
+ {
+ my (@list,$list);
+ if (open (FI,"$ENV{HOME}/.master-timer/deepblack"))
+ {
+ @list = <FI>;
+ close(FI);
+
+ foreach $list (@list)
+ {
+ chomp $list;
+ }
+ $title_deepblack = join ('|',@list);
+ }
+ else
+ {
+ $title_deepblack = "^\$";
+ }
+ }
+
+# What is already recorded/Should not be recorded
+sub initdone
+ {
+ my (@list,$list, %title_done, %subtitle_done, $title_temp, $subtitle_temp);
+ if (open (FI,"$ENV{HOME}/.master-timer/done"))
+ {
+ @list = <FI>;
+ close (FI);
+
+ foreach $list (@list)
+ {
+ chomp $list;
+ ($title_temp,$subtitle_temp) = split (/\|/,$list);
+ if ($title_temp)
+ {
+ $title_done{"^$title_temp\$"} = 1;
+ }
+ if ($subtitle_temp)
+ {
+ $subtitle_done{"^$subtitle_temp\$"} = 1;
+ }
+ }
+ $title_done = join ('|',sort keys %title_done);
+ $subtitle_done = join ('|',sort keys %subtitle_done);
+
+ # Ein paar Zeichen Escapen
+ $title_done =~ s/\?/\\\?/g;
+ $title_done =~ s/\+/\\\+/g;
+ $subtitle_done =~ s/\?/\\\?/g;
+ $subtitle_done =~ s/\+/\\\+/g;
+
+ # Now delete Timers in VDR that are already in the done-List
+ my ($position, $timer, $active, $g, $title, $subtitle, $counter, @todel);
+ $counter = 0;
+ @list = GetSend ("LSTT");
+
+ foreach $timer (@list)
+ {
+# $timer =~ s/0x0d//g;
+ chomp $timer;
+ if ($timer =~ s/250-|250\s//)
+ {
+ ($position, $timer) = split (/\s/,$timer,2);
+ # Split the : seperated values
+ ($active, $g, $g, $g, $g, $g, $g, $title, $subtitle) = split (/\:/,$timer,9);
+ if ($active == 2)
+ {
+ # Title: "Shakespeare in Love"||Subtitle: "Romanze"
+ my ($ctitle, $csubtitle);
+ if ($subtitle && $subtitle =~ /^Title\:\s\"(.*)\"\|\|Subtitle\:\s\"(.*)\"/)
+ {
+ $title = $1;
+ $subtitle = $2;
+ if ($subtitle)
+ {
+ my (@titles, @subtitles, $num, $hit);
+ undef $hit;
+ @titles = split (/\~/,$title);
+ @subtitles = split (/\~/,$subtitle);
+ foreach $num (0 .. $#titles)
+ {
+ if ($titles[$num] =~ /$title_done/ && $subtitles[$num] =~ /$subtitle_done/)
+ {
+ $hit = 1;
+ }
+ else
+ {
+ undef $hit;
+ last;
+ }
+ }
+
+ if ($hit)
+ {
+ my ($result);
+ print "Delete Timer: $title $subtitle\n" if ($debug & 4);
+ $position -= $counter;
+ ($result) = GetSend ("DELT $position");
+ print "Result: $result" if ($debug & 4);
+ if ($result =~ /^250/)
+ {
+ $counter++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+# What should be recorded
+sub inittorecord
+ {
+ my (@list, $list, $title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine, @title_list, @subtitle_list, @description_list);
+ my $counter = 0;
+ open (FI,"$ENV{HOME}/.master-timer/torecord") or sub_die ("Can't open file \"torecord\"\n");
+ @list = <FI>;
+ close(FI);
+
+ foreach $list (0 .. $#list)
+ {
+ chomp $list[$list];
+ if ($list[$list] && !($list[$list] =~ /^\#/))
+ {
+ ($title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine) = split (/\|/,$list[$list]);
+
+ # Accept torecord only if it is for the current machine
+ if ((!$machine && $currentVDR == 1) || $machine == $currentVDR)
+ {
+ if ($title)
+ {
+ $title_torecord[$counter] = $title;
+ $title_list[$#title_list + 1] = $title;
+ }
+ if ($subtitle)
+ {
+ $subtitle_torecord[$counter] = $subtitle;
+ $subtitle_list[$#subtitle_list + 1] = $subtitle;
+ }
+ if ($description)
+ {
+ $description_torecord[$counter] = $description;
+ $description_list[$#description_list + 1] = $description;
+ }
+ if ($channel)
+ {
+ my (@temp);
+ @temp = split (/\;/,$channel);
+ foreach (0 .. $#temp)
+ {
+ $channel_torecord[$counter][$_] = $temp[$_];
+ }
+ }
+ if ($timeframe)
+ {
+ $timeframe_torecord[$counter] = $timeframe;
+ }
+ if ($prio)
+ {
+ $prio_torecord[$counter] = $prio;
+ }
+ else
+ {
+ $prio_torecord[$counter] = $default_prio;
+ }
+ if ($timer_title)
+ {
+ $timer_title_torecord[$counter] = $timer_title;
+ }
+ if ($margin)
+ {
+ my ($start, $stop);
+ ($start, $stop) = split (/;/,$margin, 2);
+ $marginstart_torecord[$counter] = $start if ($start);
+ $marginstop_torecord[$counter] = $stop if ($stop);
+ }
+ # Set Default-Margins if not margins defined
+ $marginstart_torecord[$counter] = $marginstart if (!$marginstart_torecord[$counter]);
+ $marginstop_torecord[$counter] = $marginstop if (!$marginstop_torecord[$counter]);
+ $counter++;
+ }
+ }
+ }
+
+ $num_torecord = $counter - 1;
+
+ $title_torecord = join ('|',@title_list);
+ $subtitle_torecord = join ('|',@subtitle_list);
+ $description_torecord = join ('|',@description_list);
+
+ if (!$title_torecord)
+ {
+ $title_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$";
+ }
+ if (!$subtitle_torecord)
+ {
+ $subtitle_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$";
+ }
+ if (!$description_torecord)
+ {
+ $description_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$";
+ }
+ }
+
+# Parse the "channels.conf" of VDR
+sub initchannellist
+ {
+ my ($counter, $chan, $garbage, $card, @temp_channels, $temp, $i);
+
+ @temp_channels = GetSend ("LSTC");
+
+ foreach $i (0 .. $#temp_channels)
+ {
+ $temp = $temp_channels[$i];
+# $temp =~ s/\x0d//g;
+ chomp $temp;
+
+ if ($temp =~ s/250-|250\s//)
+ {
+ ($counter, $temp) = split (/\s/,$temp,2);
+ ($chan, $garbage,$garbage, $garbage, $garbage, $garbage, $garbage, $card, $garbage) = split (/\:/,$temp);
+ $channels[$counter] = $chan;
+ $channels{$chan}{number} = $counter;
+ $channels{$chan}{card} = $card;
+ $counter++;
+ }
+ }
+ }
+
+sub initconfigfile
+ {
+ open (FI,"$ENV{HOME}/.master-timer/config") or return;
+ while (<FI>)
+ {
+ s/\#.*//;
+ chomp;
+ if ($_)
+ {
+ my ($key, $value);
+ ($key, $value) = split (/\s+=\s+/);
+ if ($key =~ /^debug$/i)
+ {
+ $debug = $value;
+ print "Debug-Level = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^marginstart$/i)
+ {
+ print "Marginstart = $value\n" if ($debug & 16);
+ $marginstart = $value;
+ }
+ elsif ($key =~ /^marginstop$/i)
+ {
+ print "Marginstop = $value\n" if ($debug & 16);
+ $marginstop = $value;
+ }
+ elsif ($key =~ /^DVBCards$/i)
+ {
+ print "DVB_Cards = $value\n" if ($debug & 16);
+ $DVB_cards = $value;
+ }
+ elsif ($key =~ /^defaultprio$/i)
+ {
+ print "Default Priority = $value\n" if ($debug & 16);
+ $default_prio = $value;
+ }
+ elsif ($key =~ /^Dest$/i)
+ {
+ print "Destination Host/IP:Port = $value\n" if ($debug & 16);
+ @Dest = split (/\s+/,$value);
+ }
+ elsif ($key =~ /^jointimers$/i)
+ {
+ print "Join Timers = $value\n" if ($debug & 16);
+ $jointimers = $value;
+ }
+ else
+ {
+ print "Unkown Key: \"$key\" with Value: \"$value\"\n";
+ }
+ }
+ }
+ print "End Config\n" if ($debug & 16);
+ }
+
+sub init
+ {
+ &initconfigfile();
+ &initsocket();
+ &initmovie();
+ &initblacklist();
+ &initdone();
+ &initchannellist();
+ &initepgdata();
+ &inittorecord();
+ }