Adapted the 'sky' plugin to use the actual channel IDs, and to fetch EPG data from www.bleb.org

This commit is contained in:
Klaus Schmidinger 2004-02-15 13:35:52 +01:00
parent ce882e5cf0
commit 955d5eb012
7 changed files with 221 additions and 87 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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 (<CHANNELS>) {
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><tr /) {
# extract information:
my ($time, $title, $episode, $descr) = ($line =~ /^.*?<b>(.*?)<\/b>.*?<b>(.*?)<\/b> *(<i>.*?<\/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 =~ /<programme>/) {
$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);

View File

@ -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 <sys/socket.h>
@ -14,16 +14,53 @@
#include <vdr/plugin.h>
#include <vdr/sources.h>
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<cSkyChannel> {
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)

View File

@ -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");