From 955d5eb012227fa6fa70f784d967e831a55e5c1b Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 15 Feb 2004 13:35:52 +0100 Subject: [PATCH] Adapted the 'sky' plugin to use the actual channel IDs, and to fetch EPG data from www.bleb.org --- HISTORY | 4 +- PLUGINS/src/sky/HISTORY | 6 ++ PLUGINS/src/sky/README | 27 +++--- PLUGINS/src/sky/channels.conf.sky | 38 ++++++++- PLUGINS/src/sky/getskyepg.pl | 136 +++++++++++++++++++----------- PLUGINS/src/sky/sky.c | 92 ++++++++++++++++---- eitscan.c | 5 +- 7 files changed, 221 insertions(+), 87 deletions(-) diff --git a/HISTORY b/HISTORY index 9c6dd2eb..dc639d7f 100644 --- a/HISTORY +++ b/HISTORY @@ -2652,7 +2652,7 @@ Video Disk Recorder Revision History actual CAM type as reported by the CAM. The 'ca.conf' file has been stripped down to the values 0..4. -2004-02-14: Version 1.3.5 +2004-02-15: Version 1.3.5 - Fixed reading the EPG preferred language parameter from 'setup.conf'. - Fixed switching to a visible programme in case the current channel has neither @@ -2667,3 +2667,5 @@ Video Disk Recorder Revision History now initiates an "emergency exit" if the number of UPT errors during one recording exceeds 10 (suggested by Gregoire Favre). Since the UPT error doesn't happen on my system, this has not been explicitly tested. +- Adapted the 'sky' plugin to use the actual channel IDs, and to fetch EPG data + from www.bleb.org. diff --git a/PLUGINS/src/sky/HISTORY b/PLUGINS/src/sky/HISTORY index d3da71ec..2b7f2b34 100644 --- a/PLUGINS/src/sky/HISTORY +++ b/PLUGINS/src/sky/HISTORY @@ -16,3 +16,9 @@ VDR Plugin 'sky' Revision History 2004-01-04: Version 0.2.0 - Implemented automatic PID switching and channel detection + +2004-02-15: Version 0.3.0 + +- Now using the actual channel IDs a derived from the data stream. +- Switched EPG data retrieval to http://www.bleb.org. +- Added automatic DST detection to getskyepg.pl. diff --git a/PLUGINS/src/sky/README b/PLUGINS/src/sky/README index bd089ccf..185a98b0 100644 --- a/PLUGINS/src/sky/README +++ b/PLUGINS/src/sky/README @@ -28,23 +28,18 @@ control the Digibox. In order to access the Sky channels VDR needs to know the channel number under which each channel is stored in the Sky Digibox. These numbers are -used as 'frequency' parameters in the channels.conf definitions of the Sky -channels (see the file 'channels.conf.sky'). Since these numbers are always -less than 1000, they can be easily distinguished from normal satellite -transponder frequencies. The VPID is 160 and the APID is 80 for all Sky -channels. These are just fake PIDs, since the Kfir card always uses these -fixed PIDs. The 'Ca' parameter of the Sky channels is set to 301, which -is defined as "Videoguard, Sky Digital" in VDR's 'ca.conf' file. Again, please -note that VDR doesn't do any decrypting here, this is just to mark these -channels as "conditionally accessible" and have a way of setting the CICAM -value for the Kfir device in VDR's Setup menu. +stored in the file 'channels.conf.sky', together with the channel IDs as +derived from the actual channel data and the names under which the EPG +data for each channel can be found (see below). Copy this file to your +plugins config directory, in a subdirectory named 'sky', as in -The Sky EPG is available on the Internet at http://www.ananova.com. +/video/plugins/sky/channels.conf.sky + +The Sky EPG is available on the Internet at http://www.bleb.org. The Perl script getskyepg.pl extracts the EPG data from these pages -and sends it to VDR via an SVDRP connection. The channel numbers Sky -uses to generate the EPG pages are stored as the 'sid' parameter in -the channels.conf definitions of the Sky channels. You can keep your -EPG data up-to-date by entering a call to getskyepg.pl into your -/etc/crontab. Call 'getskyepg.pl -h' for a list of options. +and sends it to VDR via an SVDRP connection. The channel names as +used on the bleb.org pages are defined in the channels.conf.sky file. +You can keep your EPG data up-to-date by entering a call to getskyepg.pl +into your /etc/crontab. Call 'getskyepg.pl -h' for a list of options. The getskyepg.pl script requires the programs /usr/bin/wget and /usr/bin/logger to be installed on your system. diff --git a/PLUGINS/src/sky/channels.conf.sky b/PLUGINS/src/sky/channels.conf.sky index f4a437be..ba262f82 100644 --- a/PLUGINS/src/sky/channels.conf.sky +++ b/PLUGINS/src/sky/channels.conf.sky @@ -1,4 +1,34 @@ -Sky One:106:h:S28.2E:0:160:80:0:301:222 -itv2:226:h:S28.2E:0:160:80:0:301:451 -sci-fi:130:h:S28.2E:0:160:80:0:301:161 -Paramount Comedy:127:h:S28.2E:0:160:80:0:301:185 +# Sky channel definitions +# +# Syntax: +# +# ChannelID:ChannelNumber:EPGname +# +# where +# +# ChannelID is the channel ID as derived from the actual channel +# data as broadcast in the data stream (see man vdr(5)). +# +# ChannelNumber is the number of this channel as you have to +# enter it on the DigiBox remote control. +# +# EPGname is the name of the page at www.bleb.org that has EPG +# data for this channel (without the '.xml'). If no such +# page exists, 'x' is entered. +# +S28.2E-2-2027-4705:106:sky_one +S28.2E-2-2027-5104:107:sky_one_mix +S28.2E-2-2054-10240:226:itv2 +S28.2E-2-2023-4905:130:scifi +S28.2E-2-2025-5904:127:paramount +S28.2E-2-2009-6201:551:discovery +S28.2E-2-2020-4809:310:sky_cinema +S28.2E-2-2007-4303:301:sky_movies1 +S28.2E-2-2007-4302:302:sky_movies2 +S28.2E-2-2007-4403:303:sky_movies3 +S28.2E-2-2011-4402:304:sky_movies4 +S28.2E-2-2011-4503:305:sky_movies5 +S28.2E-2-2011-4502:306:sky_movies6 +S28.2E-2-2020-4603:307:sky_movies7 +S28.2E-2-2007-5502:308:sky_movies8 +S28.2E-2-2020-4602:309:x diff --git a/PLUGINS/src/sky/getskyepg.pl b/PLUGINS/src/sky/getskyepg.pl index 46c2d7ff..77768ade 100755 --- a/PLUGINS/src/sky/getskyepg.pl +++ b/PLUGINS/src/sky/getskyepg.pl @@ -1,14 +1,14 @@ #!/usr/bin/perl -# getskyepg.pl: Get EPG data from Sky's web pages +# getskyepg.pl: Get EPG data for Sky channels from the Internet # # Connects to a running VDR instance via SVDRP, gets the channel data -# for the Sky channels and connects to Sky's web pages to extract the +# for the Sky channels and connects to Internet web pages to extract the # EPG data for these channels. The result is sent to VDR via SVDRP. # # See the README file for copyright information and how to reach the author. # -# $Id: getskyepg.pl 1.2 2003/04/02 16:21:47 kls Exp $ +# $Id: getskyepg.pl 1.3 2004/02/15 13:35:52 kls Exp $ use Getopt::Std; use Time::Local; @@ -16,31 +16,33 @@ use Time::Local; $Usage = qq{ Usage: $0 [options] -Options: -d hostname destination hostname (default: localhost) +Options: -c filename channel config file name (default: channels.conf.sky) + -d hostname destination hostname (default: localhost) -p port SVDRP port number (default: 2001) -S source channel source (default: S28.2E) -D days days to get EPG for (1..7, default: 2) }; -die $Usage if (!getopts("d:D:hp:S:") || $opt_h); +die $Usage if (!getopts("c:d:D:hp:S:") || $opt_h); +$Conf = $opt_c || "channels.conf.sky"; $Dest = $opt_d || "localhost"; $Port = $opt_p || 2001; $Source = $opt_S || "S28.2E"; $Days = $opt_D || 2; -$SkyWebPage = "www.ananova.com/tv/frontpage.html"; +$SkyWebPage = "www.bleb.org/tv/data/listings"; $WGET = "/usr/bin/wget -q -O-"; $LOGGER = "/usr/bin/logger -t SKYEPG"; -$DST = -3600; ##XXX TODO find out whether DST is active! +$DST = -3600; # Daylight Saving Time offset $SecsInDay = 86400; -$MaxFrequency = 1000; -$idxName = 0; -$idxFrequency = 1; -$idxSource = 3; -$idxSid = 9; +@Channels = (); + +$idxSource = 0; +$idxNumber = 1; +$idxName = 2; Error("days out of range: $Days") unless (1 <= $Days && $Days <= 7); @@ -57,34 +59,52 @@ sub Error sub GetChannels { - SVDRPsend("LSTC"); - my @channels = (); - for (SVDRPreceive(250)) { - my @a = split(':', substr($_, 4)); - if ($a[$idxSource] eq $Source && $a[$idxFrequency] < $MaxFrequency) { - push(@channels, [@a]); - } - } - return @channels; + open(CHANNELS, $Conf) || Error("$Conf: $!"); + while () { + chomp; + next if (/^#/); + my @a = split(":"); + push(@Channels, [@a]) unless ($a[$idxName] eq "x"); + } + close(CHANNELS); } +GetChannels(); + sub GetPage { my $channel = shift; my $day = shift; - my $url = "$SkyWebPage?c=$channel&day=day$day"; + $day--; + my $url = "$SkyWebPage/$day/$channel.xml"; Log("reading $url"); my @page = split("\n", `$WGET '$url'`); Log("received " . ($#page + 1) . " lines"); return @page; } +sub StripWhitespace +{ + my $s = shift; + $s =~ s/\s*(.*)\s*/$1/; + $s =~ s/\s+/ /g; + return $s; +} + +sub Extract +{ + my $s = shift; + my $t = shift; + $s =~ /<$t>([^<]*)<\/$t>/; + return StripWhitespace($1); +} + # In order to get the duration we need to buffer the last event: $Id = ""; $Time = 0; $Title = ""; -$Episode = ""; -$Descr = ""; +$Subtitle = ""; +$Desc = ""; sub GetEpgData { @@ -94,40 +114,64 @@ sub GetEpgData $Time = 0; for $day (1 .. $Days) { my $dt = 0; - my $ap = ""; my @page = GetPage($channel, $day); + my $data = ""; for $line (@page) { - if ($line =~ /^<\/tr>(.*?)<\/b>.*?(.*?)<\/b> *(.*?<\/i>)? *(.*?) *<\/small>/); - my ($h, $m, $a) = ($time =~ /([0-9]+)\.([0-9]+)(.)m/); - # handle am/pm: - $dt = $SecsInDay if ($ap eq "p" && $a eq "a"); - $ap = $a; - $h += 12 if ($a eq "p" && $h < 12); - $h -= 12 if ($a eq "a" && $h == 12); + chomp($line); + if ($line =~ //) { + $data = ""; + } + elsif ($line =~ /<\/programme>/) { + my $title = Extract($data, "title"); + my $subtitle = Extract($data, "subtitle"); + my $desc = Extract($data, "desc"); + my $start = Extract($data, "start"); + # 'end' is useless, because it is sometimes missing :-( + # my $end = Extract($data, "end"); + if (!$subtitle) { + # They sometimes write all info into the description, as in + # Episode: some description. + # Why don't they just fill in the data correctly? + my ($s, $d) = ($desc =~ /([^:]*)[:](.*)/); + if ($s && $d) { + $subtitle = $s; + $desc = $d; + } + } + # 'start' and 'end' as time of day isn't of much use here, since + # the page for one day contains data that actually belongs to the + # next day (after midnight). Oh well, lets reconstruct the missing + # information: + $start = "0" . $start if (length($start) < 4); + my ($h, $m) = ($start =~ /(..)(..)/); + $dt = $SecsInDay if ($h > 12); # convert to time_t: my @gmt = gmtime; $gmt[0] = 0; # seconds $gmt[1] = $m; # minutes $gmt[2] = $h; # hours - $time = timegm(@gmt) + ($day - 1) * $SecsInDay + $dt + $DST; + $time = timegm(@gmt) + ($day - 1) * $SecsInDay + ($h < 12 ? $dt : 0); + # comensate for DST: + $time += $DST if (localtime($time))[8]; # create EPG data: if ($Time) { $duration = $time - $Time; SVDRPsend("E $Id $Time $duration"); SVDRPsend("T $Title"); - SVDRPsend("S $Episode"); - SVDRPsend("D $Descr"); + SVDRPsend("S $Subtitle"); + SVDRPsend("D $Desc"); SVDRPsend("e"); $numEvents++; } # buffer the last event: $Id = $time / 60 % 0xFFFF; # this gives us unique ids for every minute of over 6 weeks $Time = $time; - ($Title = $title) =~ s/<[^>]+>//g; - ($Episode = $episode) =~ s/<[^>]+>//g; - ($Descr = $descr) =~ s/<[^>]+>//g; + $Title = $title; + $Subtitle = $subtitle; + $Desc = $desc; + } + else { + $data .= $line; } } } @@ -137,14 +181,10 @@ sub GetEpgData sub ProcessEpg { - Log("getting Sky channel definitions"); - my @channels = GetChannels(); - Error("no Sky channels found") unless @channels; - Log("found " . ($#channels + 1) . " channels"); - for (@channels) { - my $channel = @$_[$idxSid]; - my $channelID = "@$_[$idxSource]-0-@$_[$idxFrequency]-$channel"; - Log("processing channel @$_[0]"); + for (@Channels) { + my $channel = @$_[$idxName]; + my $channelID = @$_[$idxSource]; + Log("processing channel $channel - $channelID"); SVDRPsend("PUTE"); SVDRPreceive(354); GetEpgData($channel, $channelID); diff --git a/PLUGINS/src/sky/sky.c b/PLUGINS/src/sky/sky.c index 0f2da6e9..dbadf1dc 100644 --- a/PLUGINS/src/sky/sky.c +++ b/PLUGINS/src/sky/sky.c @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: sky.c 1.4 2004/01/04 12:30:00 kls Exp $ + * $Id: sky.c 1.5 2004/02/15 12:40:22 kls Exp $ */ #include @@ -14,16 +14,53 @@ #include #include -static const char *VERSION = "0.2.0"; +static const char *VERSION = "0.3.0"; static const char *DESCRIPTION = "Sky Digibox interface"; // --- cDigiboxDevice -------------------------------------------------------- +#define DUMMYAPID 80 +#define DUMMYVPID 160 + +class cSkyChannel : public cListObject { +public: + tChannelID channelID; + int digiboxChannelNumber; + bool Parse(const char *s); + }; + +bool cSkyChannel::Parse(const char *s) +{ + char *id = NULL; + if (2 == sscanf(s, "%a[^:]:%d", &id, &digiboxChannelNumber)) + channelID = tChannelID::FromString(id); + free(id); + return digiboxChannelNumber && channelID.Valid(); +} + +class cSkyChannels : public cConfig { +public: + cSkyChannel *GetSkyChannel(const cChannel *Channel); + }; + +cSkyChannel *cSkyChannels::GetSkyChannel(const cChannel *Channel) +{ + tChannelID ChannelID = Channel->GetChannelID(); + for (cSkyChannel *sc = First(); sc; sc = Next(sc)) { + if (ChannelID == sc->channelID) + return sc; + } + return NULL; +} + +cSkyChannels SkyChannels; + class cDigiboxDevice : public cDevice { private: int source; int digiboxChannelNumber; int fd_dvr; + int apid, vpid; cTSBuffer *tsBuffer; int fd_lirc; void LircSend(const char *s); @@ -47,6 +84,7 @@ cDigiboxDevice::cDigiboxDevice(void) source = cSource::FromString("S28.2E");//XXX parameter??? digiboxChannelNumber = 0; fd_dvr = -1; + apid = vpid = 0; struct sockaddr_un addr; addr.sun_family = AF_UNIX; strn0cpy(addr.sun_path, "/dev/lircd", sizeof(addr.sun_path));//XXX parameter??? @@ -93,7 +131,7 @@ void cDigiboxDevice::LircSend(int n) bool cDigiboxDevice::SetPid(cPidHandle *Handle, int Type, bool On) { - dsyslog("SetPid %d %d", Handle->pid, On); + //dsyslog("SetPid %d %d", Handle->pid, On); return true; } @@ -122,6 +160,16 @@ bool cDigiboxDevice::GetTSPacket(uchar *&Data) int r = tsBuffer->Read(); if (r >= 0) { Data = tsBuffer->Get(); + if (Data) { + // insert the actual PIDs: + int Pid = (((uint16_t)Data[1] & PID_MASK_HI) << 8) | Data[2]; + if (Pid == DUMMYAPID) + Pid = apid; + else if (Pid == DUMMYVPID) + Pid = vpid; + Data[1] = ((Pid >> 8) & 0xFF) | (Data[1] & ~PID_MASK_HI); + Data[2] = Pid & 0xFF; + } return true; } else if (FATALERRNO) { @@ -149,9 +197,10 @@ bool cDigiboxDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool bool hasPriority = Priority < 0 || Priority > this->Priority(); bool needsDetachReceivers = true; - if (ProvidesSource(Channel->Source()) && Channel->Ca() == 0x30) {//XXX + cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel); + if (SkyChannel) { if (Receiving()) { - if (digiboxChannelNumber == Channel->Frequency()) { + if (digiboxChannelNumber == SkyChannel->digiboxChannelNumber) { needsDetachReceivers = false; result = true; } @@ -169,15 +218,20 @@ bool cDigiboxDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool bool cDigiboxDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) { if (fd_lirc >= 0 && !Receiving()) { // if we are receiving the channel is already set! - digiboxChannelNumber = Channel->Frequency(); - //XXX only when recording??? -> faster channel switching! - LircSend("SKY"); // makes sure the Digibox is "on" - //XXX lircprint(fd_lirc, "BACKUP"); - //XXX lircprint(fd_lirc, "BACKUP"); - //XXX lircprint(fd_lirc, "BACKUP"); - LircSend(digiboxChannelNumber); + cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel); + if (SkyChannel) { + digiboxChannelNumber = SkyChannel->digiboxChannelNumber; + apid = Channel->Apid1(); + vpid = Channel->Vpid(); + //XXX only when recording??? -> faster channel switching! + LircSend("SKY"); // makes sure the Digibox is "on" + //XXX lircprint(fd_lirc, "BACKUP"); + //XXX lircprint(fd_lirc, "BACKUP"); + //XXX lircprint(fd_lirc, "BACKUP"); + LircSend(digiboxChannelNumber); + } } -return true; + return true; } // --- cPluginSky ------------------------------------------------------------ @@ -225,8 +279,16 @@ bool cPluginSky::ProcessArgs(int argc, char *argv[]) bool cPluginSky::Initialize(void) { // Initialize any background activities the plugin shall perform. - new cDigiboxDevice; - return true; + const char *ConfigDir = ConfigDirectory(Name()); + if (ConfigDir) { + if (SkyChannels.Load(AddDirectory(ConfigDir, "channels.conf.sky"), true)) { + new cDigiboxDevice; + return true; + } + } + else + esyslog("ERROR: can't get config directory"); + return false; } void cPluginSky::Housekeeping(void) diff --git a/eitscan.c b/eitscan.c index a2096af9..191a00e6 100644 --- a/eitscan.c +++ b/eitscan.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: eitscan.c 1.20 2004/01/17 15:38:11 kls Exp $ + * $Id: eitscan.c 1.21 2004/02/14 13:44:31 kls Exp $ */ #include "eitscan.h" @@ -146,8 +146,7 @@ void cEITScanner::Process(void) if (!(Device->Receiving(true) || Device->Replaying())) { const cChannel *Channel = ScanData->GetChannel(); if (Channel) { - //XXX if (Device->ProvidesTransponder(Channel)) { - if ((!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= 0x0100) && Device->ProvidesTransponder(Channel)) { //XXX temporary for the 'sky' plugin + if ((!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= 0x0100) && Device->ProvidesTransponder(Channel)) { if (Device == cDevice::PrimaryDevice() && !currentChannel) { currentChannel = Device->CurrentChannel(); Interface->Info("Starting EPG scan");