summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY7
-rw-r--r--README27
-rw-r--r--TODO4
-rw-r--r--vdrtva.c192
-rw-r--r--vdrtva.h26
5 files changed, 148 insertions, 108 deletions
diff --git a/HISTORY b/HISTORY
index 013b5db..ea02994 100644
--- a/HISTORY
+++ b/HISTORY
@@ -50,3 +50,10 @@ VDR Plugin 'vdrtva' Revision History
- Start capturing CRID data soon after VDR startup.
- COPYING file omitted from distribution.
- Update time wrong after DST change.
+
+2012-04-20: Version 0.2.0
+- Improvements suggested by Richard Scobie:
+ - Ignore repeating timers.
+ - Handle timers recording into subdirectories.
+ - Gather CRID data continuously.
+- Plugin now compatible with New Zealand DVB-S.
diff --git a/README b/README
index 3a55e54..de63b5f 100644
--- a/README
+++ b/README
@@ -16,7 +16,9 @@ standard is ETSI TS 102 323.
In the UK a subset of the TV-Anytime specification is broadcast on the DTV
service under the trade name "FreeView Plus". This plugin is written for the UK
-version but should work with the full specification (untested).
+version, has been tested on New Zealand DVB-S and is believed to be compatible
+with the NorDig standard used in Scandanavian countries plus Eire. It should
+also work with the full specification (untested).
TV-Anytime data is contained in Content Reference Identifiers (CRIDs). The
syntax of a CRID is described in RFC 4078; it is a URI-compliant string of the
@@ -53,8 +55,9 @@ Operation:
The use of the 'Accurate Recording' feature is described in README-vps.
-The plugin runs every 24 hours at a time set by the '-u' parameter or in VDR's
-OSD (default 03:00). It captures CRID data for a time (default 10 minutes) then:
+The plugin captures CRID data continuously, beginning 5 minutes after VDR
+startup. A maintenance task runs every 24 hours at a time set by the '-u'
+parameter or in VDR's OSD (default 03:00) which:
- Checks for new manually-created timers and adds series links for them.
@@ -66,9 +69,13 @@ OSD (default 03:00). It captures CRID data for a time (default 10 minutes) then:
- Checks that the event being recorded by each timer is the same as when the
timer was set (ie that the EPG has not changed in the meantime)
-- Flags any split events (eg a long programme with a news summary in the middle).
- At present a manual check is needed that all parts of the programme are set to
- be recorded.
+- Flags any split events (eg a long programme with a news summary in the
+ middle). At present a manual check is needed that all parts of the programme
+ are set to be recorded.
+
+- Optionally sends a mail report listing new timers which have been
+ automatically created, any timer clash warnings, and a complete list of timers
+ and any suggestions for them.
The plugin takes the following parameters:
@@ -121,8 +128,8 @@ Points to remember:
- The 'suggested' events list may have CRIDs which do not appear in the events
list.
-The plugin is compatible with VDR version >= 1.7.19. The patch version will work
-with VDR 1.6.
+The plugin is compatible with VDR version >= 1.7.19. The patch version will
+work with VDR 1.6.
-Although I use this software on my VDR installation, this is Beta-quality code
-- USE AT YOUR OWN RISK!!
+Although I use this software day-to-day on my VDR installation, this is
+Beta-quality code - USE AT YOUR OWN RISK!!
diff --git a/TODO b/TODO
index ce1b69a..3758672 100644
--- a/TODO
+++ b/TODO
@@ -10,5 +10,7 @@ Some events have a series CRID but no item CRID - how to handle these?
Delete a series link if the only timer is manually deleted.
+Display suggestions for timers which don't have series CRIDs.
+
Bugs:
- Very rare crash 'pure virtual method called' in plugin.
+ Very rare crash 'pure virtual method called' in plugin - possibly solved.
diff --git a/vdrtva.c b/vdrtva.c
index 8e23fc3..6ca5dec 100644
--- a/vdrtva.c
+++ b/vdrtva.c
@@ -22,7 +22,7 @@ cEventCRIDs *EventCRIDs;
cSuggestCRIDs *SuggestCRIDs;
cLinks *Links;
-static const char *VERSION = "0.1.3";
+static const char *VERSION = "0.2.0";
static const char *DESCRIPTION = "Series Record plugin";
//static const char *MAINMENUENTRY = "vdrTva";
@@ -58,6 +58,7 @@ private:
void Update(void);
void Check(void);
void Report(void);
+ void Expire(void);
void tvasyslog(const char *Fmt, ...);
time_t NextUpdateTime(void);
@@ -229,18 +230,15 @@ void cPluginvdrTva::Housekeeping(void)
state++;
break;
case 1:
- StopDataCapture();
- state++;
- break;
- case 2:
+ Expire();
Update();
state++;
break;
- case 3:
+ case 2:
Check();
Report();
nextactiontime = NextUpdateTime();
- state = 0;
+ state = 1;
tvalog.MailLog();
break;
}
@@ -463,24 +461,22 @@ void cPluginvdrTva::StartDataCapture()
void cPluginvdrTva::StopDataCapture()
{
if (Filter) {
- cDevice::ActualDevice()->Detach(Filter);
delete Filter;
Filter = NULL;
- if (SuggestCRIDs && (SuggestCRIDs->MaxNumber() >= 1)) { // De-dup the suggestions list.
- SuggestCRIDs->Sort();
- cSuggestCRID *suggest = SuggestCRIDs->First();
- while (suggest) {
- cSuggestCRID *next = SuggestCRIDs->Next(suggest);
- if (next && !strcmp(next->iCRID(), suggest->iCRID()) && !strcmp(next->gCRID(), suggest->gCRID())) {
- SuggestCRIDs->Del(suggest);
- }
- suggest = next;
- }
- }
isyslog("vdrtva: Data capture stopped");
}
}
+void cPluginvdrTva::Expire()
+{
+ if (!EventCRIDs) return;
+ EventCRIDs->Expire();
+ if (SuggestCRIDs) {
+ SuggestCRIDs->DeDup();
+ SuggestCRIDs->Expire();
+ }
+}
+
void cPluginvdrTva::Update()
{
bool status = UpdateLinksFromTimers();
@@ -1103,11 +1099,11 @@ void cTvaFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
sectionSyncer.Reset();
SI::SDT sdt(Data, false);
if (!sdt.CheckCRCAndParse()) {
- dsyslog ("vdrtva: SDT Parse / CRC error\n");
+ dsyslog ("vdrtva: SDT Parse / CRC error");
return;
}
if (!sectionSyncer.Sync(sdt.getVersionNumber(), sdt.getSectionNumber(), sdt.getLastSectionNumber())) {
- dsyslog ("vdrtva: SDT Syncer error\n");
+ dsyslog ("vdrtva: SDT Syncer error");
return;
}
SI::SDT::Service SiSdtService;
@@ -1123,8 +1119,7 @@ void cTvaFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
SI::DefaultAuthorityDescriptor *da = (SI::DefaultAuthorityDescriptor *)d;
char DaBuf[Utf8BufSize(1024)];
da->DefaultAuthority.getText(DaBuf, sizeof(DaBuf));
- chanDA = ChanDAs->NewChanDA(chan->Number());
- chanDA->SetDA(DaBuf);
+ chanDA = ChanDAs->NewChanDA(chan->Number(), DaBuf);
}
break;
default: ;
@@ -1140,7 +1135,7 @@ void cTvaFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
// sectionSyncer.Reset();
SI::EIT eit(Data, false);
if (!eit.CheckCRCAndParse()) {
- dsyslog ("vdrtva: EIT Parse / CRC error\n");
+ dsyslog ("vdrtva: EIT Parse / CRC error");
return;
}
@@ -1175,12 +1170,12 @@ void cTvaFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
// There can be more than one type 0x33 descriptor per event (each with one CRID).
case 0x03:
case 0x33:
- cde.identifier.getText(gCRIDBuf, sizeof(gCRIDBuf)); // FIXME Rashly assuming that a 0x31 CRID will always precede a 0x33 CRID.
- if (iCRIDBuf[0]) SuggestCRIDs->NewSuggestCRID(chan->Number(), iCRIDBuf, gCRIDBuf);
+ cde.identifier.getText(gCRIDBuf, sizeof(gCRIDBuf)); // FIXME Rashly assuming that 0x31 & 0x32 CRIDs will always precede a 0x33 CRID.
+ if (iCRIDBuf[0] && sCRIDBuf[0]) SuggestCRIDs->NewSuggestCRID(chan->Number(), iCRIDBuf, gCRIDBuf);
}
}
else {
- dsyslog ("vdrtva: Incorrect CRID Loc %x\n", cde.getCridLocation());
+ dsyslog ("vdrtva: Incorrect CRID Loc %x", cde.getCridLocation());
}
}
}
@@ -1190,8 +1185,7 @@ void cTvaFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
delete d;
}
if (iCRIDBuf[0] && sCRIDBuf[0]) { // Only log events which are part of a series.
- eventCRID = EventCRIDs->NewEventCRID(chan->Number(), SiEitEvent.getEventId());
- eventCRID->SetCRIDs(iCRIDBuf, sCRIDBuf);
+ eventCRID = EventCRIDs->NewEventCRID(chan->Number(), SiEitEvent.getEventId(), iCRIDBuf, sCRIDBuf);
}
}
}
@@ -1206,9 +1200,10 @@ void cTvaFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
cChanDA - Default Authority for a channel.
*/
-cChanDA::cChanDA(void)
+cChanDA::cChanDA(int Cid, char *DA)
{
- defaultAuthority = NULL;
+ cid = Cid;
+ defaultAuthority = strcpyrealloc(NULL, DA);
}
cChanDA::~cChanDA(void)
@@ -1216,15 +1211,6 @@ cChanDA::~cChanDA(void)
free(defaultAuthority);
}
-
-void cChanDA::Set(int Cid) {
- cid = Cid;
-}
-
-void cChanDA::SetDA(char *DA) {
- defaultAuthority = strcpyrealloc(defaultAuthority, DA);
-}
-
/*
cChanDAs - in-memory list of channels and Default Authorities.
*/
@@ -1252,13 +1238,12 @@ cChanDA *cChanDAs::GetByChannelID(int cid)
return NULL;
}
-cChanDA *cChanDAs::NewChanDA(int Cid)
+cChanDA *cChanDAs::NewChanDA(int Cid, char *DA)
{
- cChanDA *NewChanDA = new cChanDA;
- NewChanDA->Set(Cid);
+ cChanDA *NewChanDA = new cChanDA(Cid, DA);
Add(NewChanDA);
chanDAHash.Add(NewChanDA, Cid);
- ChanDAs->SetMaxNumber(ChanDAs->MaxNumber()+1);
+ maxNumber++;
return NewChanDA;
}
@@ -1267,9 +1252,12 @@ cChanDA *cChanDAs::NewChanDA(int Cid)
cEventCRID - CRIDs for an event.
*/
-cEventCRID::cEventCRID(void)
+cEventCRID::cEventCRID(int Cid, tEventID Eid, char *iCRID, char *sCRID)
{
- iCrid = sCrid = NULL;
+ eid = Eid;
+ cid = Cid;
+ iCrid = strcpyrealloc(NULL, iCRID);
+ sCrid = strcpyrealloc(NULL, sCRID);
}
cEventCRID::~cEventCRID(void)
@@ -1278,16 +1266,6 @@ cEventCRID::~cEventCRID(void)
free (sCrid);
}
-void cEventCRID::Set(int Cid, tEventID Eid) {
- eid = Eid;
- cid = Cid;
-}
-
-void cEventCRID::SetCRIDs(char *iCRID, char *sCRID) {
- iCrid = strcpyrealloc(iCrid, iCRID);
- sCrid = strcpyrealloc(sCrid, sCRID);
-}
-
/*
cEventCRIDs - in-memory list of events and CRIDs.
@@ -1316,24 +1294,49 @@ cEventCRID *cEventCRIDs::GetByID(int Cid, tEventID Eid)
return NULL;
}
-cEventCRID *cEventCRIDs::NewEventCRID(int Cid, tEventID Eid)
+cEventCRID *cEventCRIDs::NewEventCRID(int Cid, tEventID Eid, char *iCRID, char *sCRID)
{
- cEventCRID *NewEventCRID = new cEventCRID;
- NewEventCRID->Set(Cid, Eid);
+ cEventCRID *NewEventCRID = new cEventCRID(Cid, Eid, iCRID, sCRID);
Add(NewEventCRID);
EventCRIDHash.Add(NewEventCRID, Eid + Cid*33000);
- EventCRIDs->SetMaxNumber(EventCRIDs->MaxNumber()+1);
+ maxNumber++;
return NewEventCRID;
}
+void cEventCRIDs::Expire(void)
+{
+ int i = 0;
+ cSchedulesLock SchedulesLock;
+ const cSchedules *schedules = cSchedules::Schedules(SchedulesLock);
+ if (schedules) {
+ cEventCRID *crid = First();
+ while (crid) {
+ cEventCRID *next = Next(crid);
+ cChannel *channel = Channels.GetByNumber(crid->Cid());
+ const cSchedule *schedule = schedules->GetSchedule(channel);
+ if (schedule) {
+ const cEvent *event = schedule->GetEvent(crid->Eid(), 0);
+ if (!event) {
+ Del(crid);
+ i++;
+ }
+ }
+ crid = next;
+ }
+ }
+ dsyslog("vdrtva: %d expired CRIDs removed", i);
+}
+
/*
cSuggestCRID - CRIDs of suggested items for an event.
*/
-cSuggestCRID::cSuggestCRID(void)
+cSuggestCRID::cSuggestCRID(int Cid, char *iCRID, char *gCRID)
{
- iCrid = gCrid = NULL;
+ iCrid = strcpyrealloc(NULL, iCRID);
+ gCrid = strcpyrealloc(NULL, gCRID);
+ cid = Cid;
}
cSuggestCRID::~cSuggestCRID(void)
@@ -1342,12 +1345,6 @@ cSuggestCRID::~cSuggestCRID(void)
free (gCrid);
}
-void cSuggestCRID::Set(int Cid, char *iCRID, char *gCRID) {
- iCrid = strcpyrealloc(iCrid, iCRID);
- gCrid = strcpyrealloc(gCrid, gCRID);
- cid = Cid;
-}
-
int cSuggestCRID::Compare(const cListObject &ListObject) const
{
cSuggestCRID *s = (cSuggestCRID *) &ListObject;
@@ -1367,27 +1364,63 @@ cSuggestCRIDs::cSuggestCRIDs(void)
maxNumber = 0;
}
-cSuggestCRIDs::~cSuggestCRIDs(void)
-{
-}
-
cSuggestCRID *cSuggestCRIDs::NewSuggestCRID(int cid, char *icrid, char *gcrid)
{
- cSuggestCRID *NewSuggestCRID = new cSuggestCRID;
- NewSuggestCRID->Set(cid, icrid, gcrid);
+ cSuggestCRID *NewSuggestCRID = new cSuggestCRID(cid, icrid, gcrid);
Add(NewSuggestCRID);
- SuggestCRIDs->SetMaxNumber(SuggestCRIDs->MaxNumber()+1);
+ maxNumber++;
return NewSuggestCRID;
}
+void cSuggestCRIDs::DeDup(void) {
+ if (maxNumber < 2) return;
+ int i = 0;
+ Sort();
+ cSuggestCRID *suggest = First();
+ while (suggest) {
+ cSuggestCRID *next = Next(suggest);
+ if (next && !strcmp(next->iCRID(), suggest->iCRID()) && !strcmp(next->gCRID(), suggest->gCRID())) {
+ Del(suggest);
+ i++;
+ }
+ suggest = next;
+ }
+ dsyslog("vdrtva: %d duplicate suggestions removed", i);
+}
+
+void cSuggestCRIDs::Expire(void) {
+ if (maxNumber == 0) return;
+ int i = 0;
+ cSuggestCRID *suggest = First();
+ while (suggest) {
+ cSuggestCRID *next = Next(suggest);
+ bool found = false;
+ for (cEventCRID *crid = EventCRIDs->First(); crid; crid = EventCRIDs->Next(crid)) {
+ if (!strcmp(suggest->iCRID(), crid->iCRID())) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ Del(suggest);
+ i++;
+ }
+ suggest = next;
+ }
+ dsyslog("vdrtva: %d expired suggestions removed", i);
+}
+
/*
cLinkItem - Entry from the links file
*/
-cLinkItem::cLinkItem(void)
+cLinkItem::cLinkItem(const char *sCRID, int ModTime, const char *iCRIDs, const char *Path)
{
- sCrid = iCrids = path = NULL;
+ sCrid = strcpyrealloc(NULL, sCRID);
+ modtime = ModTime;
+ iCrids = strcpyrealloc(NULL, iCRIDs);
+ path = strcpyrealloc(NULL, Path);
}
cLinkItem::~cLinkItem(void)
@@ -1416,10 +1449,9 @@ cLinks::cLinks(void)
cLinkItem *cLinks::NewLinkItem(const char *sCRID, int ModTime, const char *iCRIDs, const char *path)
{
- cLinkItem *NewLinkItem = new cLinkItem;
- NewLinkItem->Set(sCRID, ModTime, iCRIDs, path);
+ cLinkItem *NewLinkItem = new cLinkItem(sCRID, ModTime, iCRIDs, path);
Add(NewLinkItem);
- Links->SetMaxNumber(Links->MaxNumber()+1);
+ maxNumber++;
return NewLinkItem;
}
diff --git a/vdrtva.h b/vdrtva.h
index dff9f9c..2c3502d 100644
--- a/vdrtva.h
+++ b/vdrtva.h
@@ -86,12 +86,10 @@ class cChanDA : public cListObject {
int cid;
char *defaultAuthority;
public:
- cChanDA(void);
+ cChanDA(int Cid, char *DA);
~cChanDA(void);
int Cid(void) { return cid; }
- void Set(int Cid);
char * DA(void) { return defaultAuthority; }
- void SetDA(char *DA);
};
class cChanDAs : public cRwLock, public cConfig<cChanDA> {
@@ -102,9 +100,8 @@ class cChanDAs : public cRwLock, public cConfig<cChanDA> {
cChanDAs(void);
~cChanDAs(void);
int MaxNumber(void) { return maxNumber; }
- void SetMaxNumber(int number) { maxNumber = number; }
cChanDA *GetByChannelID(int cid);
- cChanDA *NewChanDA(int Cid);
+ cChanDA *NewChanDA(int Cid, char *DA);
};
@@ -115,13 +112,11 @@ class cEventCRID : public cListObject {
char *iCrid;
char *sCrid;
public:
- cEventCRID(void);
+ cEventCRID(int Cid, tEventID Eid, char *iCRID, char *sCRID);
~cEventCRID(void);
tEventID Eid(void) { return eid; }
- void Set(int Cid, tEventID Eid);
char * iCRID(void) { return iCrid; }
char * sCRID(void) { return sCrid; }
- void SetCRIDs(char *iCRID, char *sCRID);
int Cid(void) { return cid; }
};
@@ -133,9 +128,9 @@ class cEventCRIDs : public cRwLock, public cConfig<cEventCRID> {
cEventCRIDs(void);
~cEventCRIDs(void);
int MaxNumber(void) { return maxNumber; }
- void SetMaxNumber(int number) { maxNumber = number; }
cEventCRID *GetByID(int Cid, tEventID Eid);
- cEventCRID *NewEventCRID(int Cid, tEventID Eid);
+ cEventCRID *NewEventCRID(int Cid, tEventID Eid, char *iCRID, char *sCRID);
+ void Expire(void);
};
@@ -145,12 +140,11 @@ class cSuggestCRID : public cListObject {
char *gCrid;
int cid;
public:
- cSuggestCRID(void);
+ cSuggestCRID(int Cid, char *iCRID, char *gCRID);
~cSuggestCRID(void);
char * iCRID(void) { return iCrid; }
char * gCRID(void) { return gCrid; }
int Cid(void) { return cid; }
- void Set(int Cid, char *iCRID, char *gCRID);
virtual int Compare(const cListObject &ListObject) const;
};
@@ -160,10 +154,10 @@ class cSuggestCRIDs : public cRwLock, public cConfig<cSuggestCRID> {
int maxNumber;
public:
cSuggestCRIDs(void);
- ~cSuggestCRIDs(void);
int MaxNumber(void) { return maxNumber; }
- void SetMaxNumber(int number) { maxNumber = number; }
cSuggestCRID *NewSuggestCRID(int Cid, char *icrid, char *gcrid);
+ void DeDup(void);
+ void Expire(void);
};
@@ -174,7 +168,7 @@ class cLinkItem : public cListObject {
char *iCrids;
char *path;
public:
- cLinkItem(void);
+ cLinkItem(const char *sCRID, int ModTime, const char *iCRIDs, const char *Path);
~cLinkItem(void);
void Set(const char *sCRID, int ModTime, const char *iCRIDs, const char *Path);
char * iCRIDs(void) { return iCrids; }
@@ -188,8 +182,6 @@ class cLinks : public cRwLock, public cConfig<cLinkItem> {
int maxNumber;
public:
cLinks(void);
-// ~cLinks(void);
int MaxNumber(void) { return maxNumber; }
- void SetMaxNumber(int number) { maxNumber = number; }
cLinkItem *NewLinkItem(const char *sCRID, int ModTime, const char *iCRIDs, const char *Path);
};