diff options
| author | Andreas Brachold <vdr07@deltab.de> | 2008-03-15 17:33:21 +0000 |
|---|---|---|
| committer | Andreas Brachold <vdr07@deltab.de> | 2008-03-15 17:33:21 +0000 |
| commit | 30e961ffb92ab553f481496d6d500e0cb81255fd (patch) | |
| tree | a49195eddd9a00dc4d473a8d85023cf0776004c7 /lib | |
| parent | f5f6f58f7a09ea69899359965d45eca5b89ff69c (diff) | |
| download | xxv-30e961ffb92ab553f481496d6d500e0cb81255fd.tar.gz xxv-30e961ffb92ab553f481496d6d500e0cb81255fd.tar.bz2 | |
* split template string into string for single line and textfield for multiline. Avoid carriage return by long timer title
* Add import module for XML-TV sources and template for scheme based programs. New commands xn (new) xe (edit) xd (delete) xl (list) xt (manual update)
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/XXV/MODULES/EPG.pm | 52 | ||||
| -rw-r--r-- | lib/XXV/MODULES/RECORDS.pm | 5 | ||||
| -rw-r--r-- | lib/XXV/MODULES/SVDRP.pm | 3 | ||||
| -rw-r--r-- | lib/XXV/MODULES/TIMERS.pm | 2 | ||||
| -rw-r--r-- | lib/XXV/MODULES/XMLTV.pm | 771 |
5 files changed, 826 insertions, 7 deletions
diff --git a/lib/XXV/MODULES/EPG.pm b/lib/XXV/MODULES/EPG.pm index edbbf81..6b73fc1 100644 --- a/lib/XXV/MODULES/EPG.pm +++ b/lib/XXV/MODULES/EPG.pm @@ -234,6 +234,7 @@ sub _init { |); } + $obj->{before_updated} = []; $obj->{after_updated} = []; # Repair later Data ... @@ -268,18 +269,21 @@ sub startReadEpgData { my $watcher = shift; my $console = shift; + debug sprintf('The read on epg data start now!'); + my $waiter; if(ref $console && $console->typ eq 'HTML') { $waiter = $console->wait(gettext("Read EPG data ..."),0,1000,'no'); } + $obj->_before_updated($watcher,$console,$waiter); + # Read data over SVDRP my $vdata = $obj->{svdrp}->command('LSTE'); map { $_ =~ s/^\d{3}.//; $_ =~ s/[\r|\n]$//; } @$vdata; - debug sprintf('The read on epg data start now!'); # Adjust waiter max value now. @@ -307,6 +311,36 @@ sub startReadEpgData { } } +# Routine um Callbacks zu registrieren die vor dem Aktualisieren der EPG Daten +# ausgeführt werden +# ------------------ +sub before_updated { +# ------------------ + my $obj = shift || return error('No object defined!'); + my $cb = shift || return error('No callback defined!'); + my $log = shift || 0; + + push(@{$obj->{before_updated}}, [$cb, $log]); +} + +# Ausführen der Registrierten Callbacks vor dem Aktualisieren der EPG Daten +# ------------------ +sub _before_updated { +# ------------------ + my $obj = shift || return error('No object defined!'); + my $watcher = shift; + my $console = shift; + my $waiter = shift; + + foreach my $CB (@{$obj->{before_updated}}) { + next unless(ref $CB eq 'ARRAY'); + lg $CB->[1] + if($CB->[1]); + &{$CB->[0]}($watcher,$console,$waiter) + if(ref $CB->[0] eq 'CODE'); + } +} + # Routine um Callbacks zu registrieren die nach dem Aktualisieren der EPG Daten # ausgeführt werden # ------------------ @@ -737,7 +771,14 @@ sub program { my $mod = main::getModule('CHANNELS'); + my $search; + if($console->{cgi}->param('filter')) { + $search = buildsearch("e.title,e.subtitle,e.description",$console->{cgi}->param('filter')); + $search->{query} .= ' AND '; + } + my $cid; + $search->{query} .= ' e.channel_id = ?'; if($channel =~ /^\d+$/sig) { $cid = $mod->PosToChannel($channel) or return con_err($console, sprintf(gettext("This channel '%s' does not exist in the database!"),$channel)); @@ -745,6 +786,9 @@ sub program { $cid = $mod->NameToChannel($channel) or return con_err($console, sprintf(gettext("This channel '%s' does not exist in the database!"),$channel)); } + push(@{$search->{term}},$cid); + + my %f = ( 'id' => gettext('Service'), @@ -786,8 +830,8 @@ from EPG as e, CHANNELS as c where e.channel_id = c.Id + AND ( $search->{query} ) AND ((UNIX_TIMESTAMP(e.starttime) + e.duration) > UNIX_TIMESTAMP()) - AND e.channel_id = ? order by starttime |; @@ -798,7 +842,7 @@ order by if($limit > 0) { # Query total count of rows my $rsth = $obj->{dbh}->prepare($sql); - $rsth->execute($cid) + $rsth->execute(@{$search->{term}}) or return error sprintf("Couldn't execute query: %s.",$rsth->errstr); $rows = $rsth->rows; if($rows <= $limit) { @@ -816,7 +860,7 @@ order by unless($sth) { $sth = $obj->{dbh}->prepare($sql); - $sth->execute($cid) + $sth->execute(@{$search->{term}}) or return error sprintf("Couldn't execute query: %s.",$sth->errstr); $rows = $sth->rows unless($rows); } diff --git a/lib/XXV/MODULES/RECORDS.pm b/lib/XXV/MODULES/RECORDS.pm index 152025c..b745bdb 100644 --- a/lib/XXV/MODULES/RECORDS.pm +++ b/lib/XXV/MODULES/RECORDS.pm @@ -2004,19 +2004,22 @@ WHERE }, }, 'description' => { + typ => 'textfield', msg => gettext("Description"), def => $status->{description} || '', }, 'video' => { + typ => 'textfield', msg => gettext('Video'), def => $status->{video}, }, 'audio' => { + typ => 'textfield', msg => gettext('Audio'), def => $status->{audio}, }, 'marks' => { - param => {type => 'text'}, + typ => 'textfield', msg => gettext("Cut marks"), def => $marks || '', }, diff --git a/lib/XXV/MODULES/SVDRP.pm b/lib/XXV/MODULES/SVDRP.pm index cbcc167..bf9ac16 100644 --- a/lib/XXV/MODULES/SVDRP.pm +++ b/lib/XXV/MODULES/SVDRP.pm @@ -189,7 +189,8 @@ sub command { $telnet->close(); foreach my $command (@commands) { - event(sprintf('Call command "%s" on svdrp %s.', $command, $obj->{ERROR} ? " failed" : "successful")) + my @lines = (split(/[\r\n]/, $command)); + event(sprintf('Call command "%s" on svdrp %s.', $lines[0], $obj->{ERROR} ? " failed" : "successful")) if($command ne "quit"); } return \@$data; diff --git a/lib/XXV/MODULES/TIMERS.pm b/lib/XXV/MODULES/TIMERS.pm index 7d8b224..fa2d842 100644 --- a/lib/XXV/MODULES/TIMERS.pm +++ b/lib/XXV/MODULES/TIMERS.pm @@ -798,7 +798,7 @@ WHERE }, 'description' => { msg => gettext('Description'), - typ => $timerData->{description} ? 'string' : 'hidden', + typ => $timerData->{description} ? 'textfield' : 'hidden', def => $timerData->{description}, readonly => 1 } diff --git a/lib/XXV/MODULES/XMLTV.pm b/lib/XXV/MODULES/XMLTV.pm new file mode 100644 index 0000000..dff5ad7 --- /dev/null +++ b/lib/XXV/MODULES/XMLTV.pm @@ -0,0 +1,771 @@ +package XXV::MODULES::XMLTV; + +use strict; +use File::Find; +use File::Basename; +use Tools; +use utf8; +use Encode; + +# This module method must exist for XXV +# ------------------ +sub module { +# ------------------ + my $self = shift || return error('No object defined!'); + my $args = { + Name => 'XMLTV', + Prereq => { + 'Template' => 'Front-end module to the Template Toolkit ', + 'Date::Manip' => 'date manipulation routines', + 'Time::Local' => 'efficiently compute time from local and GMT time ', + 'XML::Simple' => 'Easy API to maintain XML (esp config files)' + }, + Description => gettext('This module import epg data from xmltv sources.'), + Version => (split(/ /, '$Revision$'))[1], + Date => (split(/ /, '$Date$'))[1], + Author => 'Andreas Brachold', + LastAuthor => (split(/ /, '$Author$'))[1], + Preferences => { + active => { + description => gettext('Activate this service'), + default => 'n', + type => 'confirm', + required => gettext('This is required!'), + }, + }, + Commands => { + xmltv => { + description => gettext("Manual import epg data from xmltv sources."), + short => 'xt', + callback => sub{ $self->manual(@_) }, + Level => 'user', + DenyClass => 'tedit', + }, + xmltvlist => { + description => gettext("List rules to import epg data from xmltv sources."), + short => 'xl', + callback => sub{ $self->list(@_) }, + Level => 'user', + DenyClass => 'tedit', + }, + xmltvcreate => { + description => gettext("Create rule to import epg data from xmltv sources."), + short => 'xc', + callback => sub{ $self->create(@_) }, + Level => 'user', + DenyClass => 'tedit', + }, + xmltvremove => { + description => gettext("Delete rule to import epg data from xmltv sources."), + short => 'xd', + callback => sub{ $self->remove(@_) }, + Level => 'user', + DenyClass => 'tedit', + }, + xmltvedit => { + description => gettext("Edit rule to import epg data from xmltv sources."), + short => 'xe', + callback => sub{ $self->edit(@_) }, + Level => 'user', + DenyClass => 'tedit', + }, + }, + }; + return $args; +} + +# ------------------ +sub new { +# ------------------ + my($class, %attr) = @_; + my $self = {}; + bless($self, $class); + + # paths + $self->{paths} = delete $attr{'-paths'}; + + $self->{charset} = delete $attr{'-charset'}; + + # who am I + $self->{MOD} = $self->module; + + # all configvalues to $self without parents (important for ConfigModule) + map { + $self->{$_} = $attr{'-config'}->{$self->{MOD}->{Name}}->{$_}; + $self->{$_} = $self->{MOD}->{Preferences}->{$_}->{default} unless($self->{$_}); + } keys %{$self->{MOD}->{Preferences}}; + + # Try to use the Requirments + map { + eval "use $_"; + return panic("\nCouldn't load modul: $_\nPlease install this modul on your system:\nperl -MCPAN -e 'install $_'") if($@); + } keys %{$self->{MOD}->{Prereq}}; + + # read the DB Handle + $self->{dbh} = delete $attr{'-dbh'}; + + # run as background process + #$self->{background} = delete $attr{'-background'}; + + # create Template object + $self->{tt} = Template->new( + START_TAG => '\[\%', # Tagstyle + END_TAG => '\%\]', # Tagstyle + INCLUDE_PATH => '', +# INTERPOLATE => 1, # expand "$var" in plain text +# PRE_CHOMP => 0, # cleanup whitespace +# EVAL_PERL => 0, # evaluate Perl code blocks + ) || return error("Can't create Template instance!"); + + + $self->{xml} = XML::Simple->new( NumericEscape => $self->{charset} eq 'UTF-8' ? 0 : 1 ) + || return error("Can't create XML instance!"); + + # The Initprocess + my $erg = $self->_init or return error('Problem to initialize modul!'); + + return $self; +} + +# ------------------ +sub _init { +# ------------------ + my $self = shift || return error('No object defined!'); + + unless($self->{dbh}) { + panic("Session to database is'nt connected"); + return 0; + } + + my $version = main::getDBVersion(); + if(!tableUpdated($self->{dbh},'XMLTV',$version,0)) { + return 0; + } + + # Look for table or create this table + $self->{dbh}->do(qq| + CREATE TABLE IF NOT EXISTS XMLTV ( + id int unsigned auto_increment NOT NULL, + active enum('y', 'n') default 'n', + xmltvname varchar(256) default NULL, + channel varchar(64) NOT NULL, + template enum('y', 'n') default 'n', + updateinterval enum('e', 'd', 'w') default 'e', + source text NOT NULL, + updated datetime NOT NULL default '0000-00-00 00:00:00', + PRIMARY KEY (id), + UNIQUE KEY (channel) + ) COMMENT = '$version' + |); + + main::after(sub{ + + $self->{svdrp} = main::getModule('SVDRP'); + unless($self->{svdrp}) { + panic ("Couldn't get modul SVDRP"); + return 0; + } + + my $m = main::getModule('EPG'); + $m->before_updated( + sub{ + my $watcher = shift; + my $console = shift; + my $waiter = shift; + + return 0 if($self->{active} ne 'y'); + lg 'Start callback to import xmltv epg data!'; + $self->_XMLTV($watcher,$console,$waiter); + } + ); + return 1; + }, "XMLTV: Install callback to import xmltv epg data ...", 28); + + return 1; +} + +# ------------------ +sub manual { +# ------------------ + my $self = shift || return error('No object defined!'); + my $watcher = shift; + my $console = shift; + my $id = shift; + + my $waiter; + if(ref $console && !$id && $console->typ eq 'HTML') { + $waiter = $console->wait(gettext("Import epg data from xmltv sources ..."),0,1000,'no'); + } + + my ($msg, $error) = $self->_XMLTV($watcher,$console,$waiter,$id); + + $waiter->end() if(ref $waiter); + $console->start() if(ref $waiter); + + if($error) { $console->err($error); } + elsif($msg) { + $console->message($msg); + $console->redirect({url => '?cmd=xmltvlist', wait => 1}) + if($console->typ eq 'HTML'); + } + return 1; +} + +# ------------------ +sub _XMLTV { +# ------------------ + my $self = shift || return error('No object defined!'); + my $watcher = shift; + my $console = shift; + my $waiter = shift; + my $id = shift; + + my $sth = $self->{dbh}->prepare(q| + select + x.id, + x.active, + x.xmltvname, + x.channel, + x.template, + x.updateinterval, + x.source, + UNIX_TIMESTAMP(x.updated) as updated, + c.Name + from XMLTV as x, CHANNELS as c + where + active != 'n' + AND x.channel = c.Id + |); + if(!$sth->execute()) { + error sprintf("Couldn't execute query: %s.",$sth->errstr); + return (undef, undef) + } + my $rules = $sth->fetchall_hashref('id'); + return (undef, undef) unless($rules); + + # Adjust waiter max value now. + $waiter->max(scalar keys %$rules) + if(ref $console && ref $waiter); + + my $now = time(); + my $l = 0; + my $output; + + foreach my $id (sort keys %$rules) { + my $rule = $rules->{$id}; + + $waiter->next(++$l, undef, sprintf(gettext("Import epg data for channel '%s'"), $rule->{Name})) + if(ref $waiter); + + if($rule->{updateinterval} eq 'd' && ($rule->{updated} + 86400) > $now ) { + lg sprintf("Skip import xml data by update interval : %s (%s) id %d",$rule->{Name},$rule->{channel},$rule->{id}); + next; + } elsif($rule->{updateinterval} eq 'w' && ($rule->{updated} + (86400 * 7)) > $now ) { + lg sprintf("Skip import xml data by update interval : %s (%s) id %d",$rule->{Name},$rule->{channel},$rule->{id}); + next; + } + + my $file = sprintf("%s/%s",$self->{paths}->{XMLTV},$rule->{source}); + if(-r $file and my $text = load_file($file)) { + if($rule->{template} eq 'y') { + $text = $self->_parse_template($text,$now); + } + my $adjust = 0; + debug sprintf("Import xml data at %s (%s) id %d",$rule->{Name},$rule->{channel},$rule->{id}); + my $e = $self->_ProcessXML($rule->{channel},$rule->{Name},$rule->{xmltvname},$adjust,$text); + if($e) { + $self->_updateTime($rule->{id}); + $output .= $e; + } + else { + error sprintf("Can't process xml data at %s (%s) id %d",$rule->{Name},$rule->{channel},$rule->{id}); + } + } + } + + if($output and length $output) { + $waiter->next(undef,undef,gettext('Transmit data.')) + if(ref $waiter); + my $erg = $self->{svdrp}->command(sprintf("PUTE\n%s\n.\n",$output)); + my $error; + foreach my $zeile (@$erg) { + if($zeile =~ /^(\d{3})\s+(.+)/) { + $error = $2 if(int($1) >= 500); + } + } + + unless($error) { + debug 'Data import complete'; + return ($erg, undef); + + } else { + error sprintf('Data does\'nt imported : %s',$error); + return (undef, $erg); + } + } else { + error sprintf('None data exits to import'); + return (undef, gettext('None data exits to import')); + } +} + +# Convert XMLTV time format (YYYYMMDDmmss ZZZ) into VDR (secs since epoch) +sub xmltime2vdr { + my $xmltime=shift; + my $skew=shift; + my $secs = &UnixDate($xmltime, "%s"); + return $secs + ( $skew * 60 ); +} +# ------------------ +sub encodeEpgId { +# ------------------ + my $self = shift || return error('No object defined!'); + my $epgid = shift || return error('No event defined!'); + my $channel = shift || return error('No channel defined!'); + + # look for NID-TID-SID for unique eventids (SID 0-30000 / TID 0 - 1000 / NID 0 - 10000 + my @id = split('-', $channel); + + # Make a fix format 0xCCCCEEEE : C-Channelid (high-word), E-Eventid(low-word) => real-eventid = uniqueid & FFFF + my $eventid = ((($id[-3] + $id[-2] + $id[-1]) & 0x3FFF) << 16) | ($epgid & 0xFFFF); + + return $eventid; +} + + +# ------------------ +sub _ProcessXML { +# ------------------ + my $self = shift || return error('No object defined!'); + my $cid = shift; + my $channel_name = shift; + my $xmltvname = shift; + my $adjust = shift; + my $text = shift; + + my $xdata = $self->{xml}->XMLin($text); + # Ausgabe +# dumper($xdata); + + return error "Missing channel" unless $xdata->{channel}; + return error "Missing program data" unless $xdata->{programme}; + + my $epgdata = ''; + + + # Find XML events + foreach my $xml (@{$xdata->{programme}}) { +# dumper($xml); +# { +# 'stop' => '20080317200000 +0100', +# 'desc' => { +# 'lang' => 'de', +# 'content' => 'desc' +# }, +# 'title' => { +# 'lang' => 'de', +# 'content' => 'title' +# }, +# 'channel' => 'abc', +# 'start' => '20080317160000 +0100' +# }, + next if($xmltvname and $xml->{channel} ne $xmltvname); + + my $vdrst = &xmltime2vdr($xml->{start}, $adjust); + my $vdret = &xmltime2vdr($xml->{stop}, $adjust); + my $vdrdur = $vdret - $vdrst; + my $vdrid = $self->encodeEpgId($vdrst / 60,$cid); + my $vdrtitle = $xml->{title} && $xml->{title}->{content} ? $xml->{title}->{content} : gettext('Title not available'); + my $vdrdesc = $xml->{desc} && $xml->{desc}->{content} ? $xml->{desc}->{content} : ''; + $vdrtitle =~ s/\r\n//g; # pipe used from vdr as linebreak + $vdrtitle =~ s/\n//g; # pipe used from vdr as linebreak + $vdrdesc =~ s/\r\n/\|/g; # pipe used from vdr as linebreak + $vdrdesc =~ s/\n/\|/g; # pipe used from vdr as linebreak + + if($self->{charset} ne 'UTF-8') { + $vdrtitle = encode($self->{charset},$vdrtitle); + $vdrdesc = encode($self->{charset},$vdrdesc); + } + + # Send VDR Event + $epgdata .= "E $vdrid $vdrst $vdrdur 0\n"; + $epgdata .= "T $vdrtitle\n"; + $epgdata .= "D $vdrdesc\n"; + $epgdata .= "e\n"; + + } + + return unless($epgdata and length $epgdata); + + return "C $cid $channel_name\n".$epgdata . "c\n"; +} + +# ------------------ +sub _parse_template { +# ------------------ + my $self = shift || return error('No object defined!'); + my $text = shift || return error('No text defined!'); + my $now = shift || return error('No time defined!'); + + # Get current wday + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now); + + my %wd = ( + 'monday' => 1, + 'tuesday' => 2, + 'wednesday' => 3, + 'thursday' => 4, + 'friday' => 5, + 'saturday' => 6, + 'sunday' => 0 + ); + + my $vars = { + # [% date("sunday","08:00","+0100") %] => 20060119220000 +0100 + date => sub{ + my $day = $wd{$_[0]}; + $day += 7 if($day<$wday); + $day -= $wday; + + my ($t1,$t2,$t3,$tmday,$tmon,$tyear,$t4,$t5,$t6) = localtime($now + ($day * 86400)); + + ($hour,$min,$sec) = split(':',$_[1]); + $min = 0 if(!defined $min); + $sec = 0 if(!defined $sec); + return sprintf("%04d%02d%02d%02d%02d%02d %s",$tyear + 1900,$tmon+1,$tmday,$hour,$min,$sec,$_[2]); + }, + }; + my $output = ''; + $self->{tt}->process(\$text, $vars, \$output) + or return error($self->{tt}->error()); + return $output; +} + + +# ------------------ +# Name: create +# Descr: create rule to import epg data from xmltv sources. +# Usage: $self->create($watcher, $console, [$userdata]); +# ------------------ +sub create { + my $self = shift || return error('No object defined!'); + my $watcher = shift || return error('No watcher defined!'); + my $console = shift || return error('No console defined!'); + my $id = shift || 0; + my $data = shift || 0; + + $self->edit($watcher, $console, $id, $data); +} + +# ------------------ +# Name: edit +# Descr: edit rule to import epg data from xmltv sources. +# Usage: $self->edit($watcher, $console, [$id], [$userdata]); +# ------------------ +sub edit { + my $self = shift || return error('No object defined!'); + my $watcher = shift || return error('No watcher defined!'); + my $console = shift || return error('No console defined!'); + my $id = shift || 0; + my $data = shift || 0; + + my $modC = main::getModule('CHANNELS'); + + my $rule; + if($id and not ref $data) { + my $sth = $self->{dbh}->prepare("select * from XMLTV where id = ?"); + $sth->execute($id) + or return $console->err(sprintf(gettext("Rule to import epg data from xmltv sources with ID '%s' does not exist in the database!"),$id)); + $rule = $sth->fetchrow_hashref(); + + } elsif (ref $data eq 'HASH') { + $rule = $data; + } + + my $con = $console->typ eq "CONSOLE"; + my $questions = [ + 'id' => { + typ => 'hidden', + def => $rule->{id} || 0, + }, + 'active' => { + typ => 'confirm', + def => $rule->{active} || 'y', + msg => gettext('Enable this rule'), + }, + 'source' => { + msg => gettext('Source to import?'), + def => $rule->{source}, + typ => 'list', + required => gettext('This is required!'), + choices => sub{ return $self->findfiles(); } + }, + 'xmltvname' => { + msg => gettext('Limit import by this channel name inside xmltv source?'), + def => $rule->{xmltvname} || '', + typ => 'string' + }, + 'channel' => { + typ => 'list', + def => $con ? $modC->ChannelToPos($rule->{channel}) : $rule->{channel}, + choices => $con ? $modC->ChannelArray('Name') : $modC->ChannelWithGroup('Name,Id'), + msg => gettext('Assign data to channel?'), + req => gettext("This is required!"), + check => sub{ + my $value = shift || return; + + if(my $name = $modC->ChannelToName($value)) { + $data->{channel} = $value; + return $value; + } elsif(my $ch = $modC->PosToChannel($value) || $modC->NameToChannel($value) ) { + $data->{channel} = $value; + return $ch; + } elsif( ! $modC->NameToChannel($value)) { + return undef, sprintf(gettext("This channel '%s' does not exist!"),$value); + } else { + return undef, gettext("This is required!"); + } + }, + }, + 'template' => { + msg => gettext('Parse data as template?'), + def => $rule->{template} || 'n', + typ => 'list', + choices => sub { + my $erg = $self->_template_rules(); + map { my $x = $_->[1]; $_->[1] = $_->[0]; $_->[0] = $x; } @$erg; + return @$erg; + }, + }, + 'updateinterval' => { + msg => gettext('Interval to parse data?'), + def => $rule->{updateinterval} || 'e', + typ => 'list', + choices => sub { + my $erg = $self->_interval_rules(); + map { my $x = $_->[1]; $_->[1] = $_->[0]; $_->[0] = $x; } @$erg; + return @$erg; + }, + }, + ]; + + # Ask Questions + $data = $console->question(($id ? gettext('Edit rule to import epg data from xmltv sources') + : gettext('Create a new rule to import epg data from xmltv sources')), $questions, $data); + + if(ref $data eq 'HASH') { + $self->_insert($console, $data); + + $data->{id} = $self->{dbh}->selectrow_arrayref('SELECT max(id)+1 FROM XMLTV')->[0] + if(not $data->{id}); + + $console->message(gettext('Rule to import epg data from xmltv sources saved!')); + debug sprintf('%s rule to import epg data from xmltv sources is saved%s', + ($id ? 'New' : 'Changed'), + ( $console->{USER} && $console->{USER}->{Name} ? sprintf(' from user: %s', $console->{USER}->{Name}) : "" ) + ); + + my ($msg, $error) = $self->_XMLTV($watcher,$console,undef,$data->{id}); + + if($error) { $console->err($error); } + elsif($msg) { + $console->message($msg); + $console->redirect({url => '?cmd=xmltvlist', wait => 1}) + + if($console->typ eq 'HTML'); + } + } + return 1; +} + +# ------------------ +sub _insert { +# ------------------ + my $self = shift || return error('No object defined!'); + my $console = shift || return error('No console defined!'); + my $data = shift || return; + + my $sth; + if(ref $data eq 'HASH') { + my ($names, $vals, $kenn); + map { + push(@$names, $_); + push(@$vals, $data->{$_}), + push(@$kenn, '?'), + } sort keys %$data; + + my $sql = sprintf("REPLACE INTO XMLTV (%s) VALUES (%s)", + join(', ', @$names), + join(', ', @$kenn), + ); + $sth = $self->{dbh}->prepare( $sql ); + if(!$sth->execute(@$vals)) { + error sprintf("Couldn't execute query: %s.",$sth->errstr); + $console->err(sprintf(gettext("Couldn't insert rule to import epg data from xmltv sources in database!"))); + return 0; + } + } else { + $sth = $self->{dbh}->prepare('REPLACE INTO XMLTV VALUES (?,?,?,?,?,NOW())'); + if(!$sth->execute(@$data)) { + error sprintf("Couldn't execute query: %s.",$sth->errstr); + $console->err(sprintf(gettext("Couldn't insert rule to import epg data from xmltv sources in database!"))); + return 0; + } + } + return 1; +} + +# ------------------ +sub _updateTime { +# ------------------ + my $obj = shift || return error('No object defined!'); + my $id = shift || return error ('No data defined!'); + + my $sth = $obj->{dbh}->prepare('UPDATE XMLTV SET updated=NOW() where id=?'); + return $sth->execute($id); +} + +# ------------------ +# Name: remove +# Descr: Routine to delete rule to import epg data from xmltv sources. +# Usage: $self->remove($watcher, $console, $id); +# ------------------ +sub remove { + my $self = shift || return error('No object defined!'); + my $watcher = shift || return error('No watcher defined!'); + my $console = shift || return error('No console defined!'); + my $id = shift || return $console->err(gettext("Missing ID to select rules for deletion! Please use xmltvremove 'id'")); + + my @rules = reverse sort{ $a <=> $b } split(/[^0-9]/, $id); + + my $sql = sprintf('DELETE FROM XMLTV where id in (%s)', join(',' => ('?') x @rules)); + my $sth = $self->{dbh}->prepare($sql); + if(!$sth->execute(@rules)) { + error sprintf("Couldn't execute query: %s.",$sth->errstr); + $console->err(sprintf(gettext("Rule to import epg data from xmltv sources with ID '%s' does not exist in the database!"),$id)); + return 0; + } + + $console->message(sprintf gettext("Rule import epg data from xmltv sources %s is deleted."), join(',', @rules)); + debug sprintf('Rule import epg data from xmltv sources with id "%s" is deleted%s', + join(',', @rules), + ( $console->{USER} && $console->{USER}->{Name} ? sprintf(' from user: %s', $console->{USER}->{Name}) : "" ) + ); + $console->redirect({url => '?cmd=xmltvlist', wait => 1}) + if($console->typ eq 'HTML'); +} + +# ------------------ +# Name: list +# Descr: List Rules to import epg data from xmltv sources in a table display. +# Usage: $self->list($watcher, $console); +# ------------------ +sub list { + my $self = shift || return error('No object defined!'); + my $watcher = shift || return error('No watcher defined!'); + my $console = shift || return error('No console defined!'); + + my %f = ( + 'id' => gettext('Service'), + 'active' => gettext('Active'), + 'channel' => gettext('Channel'), + 'template' => gettext('Parse data as template'), + 'interval' => gettext('Interval to parse data'), + 'source' => gettext('source to import'), + ); + + my $sql = qq| + select + id as \'$f{'id'}\', + active as \'$f{'active'}\', + (SELECT Name + FROM CHANNELS as c + WHERE x.channel = c.Id + LIMIT 1) as \'$f{'channel'}\', + template as \'$f{'template'}\', + updateinterval as \'$f{'interval'}\', + source as \'$f{'source'}\' + from + XMLTV as x + order by + id + |; + + my $sth = $self->{dbh}->prepare($sql); + $sth->execute() + or return error sprintf("Couldn't execute query: %s.",$sth->errstr); + my $fields = $sth->{'NAME'}; + my $erg = $sth->fetchall_arrayref(); + + my %m; + my %i; + my $mr = $self->_template_rules(); + foreach my $mrr (@{$mr}) { + $m{$mrr->[0]} = $mrr->[1]; + } + + my $ir = $self->_interval_rules(); + foreach my $irr (@{$ir}) { + $i{$irr->[0]} = $irr->[1]; + } + + map { + $_->[3] = $m{$_->[3]}; + $_->[4] = $i{$_->[4]}; + } @$erg; + + unshift(@$erg, $fields); + + $console->table($erg); +} + +# ------------------ +sub findfiles +# ------------------ +{ + my $self = shift || return error('No object defined!'); + my @files; + find({ wanted => sub{ + if(-r $File::Find::name) { + if($File::Find::name =~ /\.xml$/sig # Lookup for *.xml + or $File::Find::name =~ /\.tpl$/sig) { # Lookup for *.xml + my $l = basename($File::Find::name); + push(@files,[$l,$l]); + } + } + }, + follow => 1, + follow_skip => 2, + }, + $self->{paths}->{XMLTV} + ); + error "Couldn't find useable file at : $self->{paths}->{XMLTV}" + unless(scalar @files); + @files = sort { lc($a->[0]) cmp lc($b->[0]) } @files; + return \@files; +} + +# ------------------ +sub _template_rules { +# ------------------ + my $self = shift || return error('No object defined!'); + + return [ + [ 'y', gettext('Yes') ], + [ 'n', gettext('No') ] + ]; +} + + +# ------------------ +sub _interval_rules { +# ------------------ + my $self = shift || return error('No object defined!'); + + return [ + [ 'e', gettext('Every EPG Data import') ], + [ 'd', gettext('Once every day') ], + [ 'w', gettext('Once every week') ] + ]; +} + +1; |
