summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave <vdr@pickles.me.uk>2012-07-19 10:23:27 +0100
committerDave <vdr@pickles.me.uk>2012-07-19 10:23:27 +0100
commit4962076536f4b2509c21ce9561c2ddcd81a7b4f0 (patch)
tree08650c3a2b8e058830999d25ab4b5395099e59fd
parent6e11578e4e317b41497b89085efec58e9b8317f0 (diff)
downloadvdrtva-0.3.0.tar.gz
vdrtva-0.3.0.tar.bz2
Provide OSD to manage Series Links.v0.3.0
-rw-r--r--HISTORY9
-rw-r--r--README20
-rw-r--r--TODO2
-rw-r--r--vdr-1.7.29-rsvps.patch (renamed from vdr-1.7.28-rsvps.patch)30
-rw-r--r--vdrtva.c225
-rw-r--r--vdrtva.h52
6 files changed, 260 insertions, 78 deletions
diff --git a/HISTORY b/HISTORY
index 423b342..44875e1 100644
--- a/HISTORY
+++ b/HISTORY
@@ -71,3 +71,12 @@ VDR Plugin 'vdrtva' Revision History
- Check for changed events now works without VPS.
- Start CRID data collection at VDR startup.
- Inhibit some functions if initial CRID capture still in progress.
+
+2012-07-19: Version 0.3.0
+- Manage series links via OSD.
+- Delay CRID collection a few seconds to allow other plugins to start.
+- Don't use "housekeeping" hook to trigger time-sensitive tasks.
+- Deleting a series link now deletes any timers for the series.
+- Remove leading 'crid://' from Default Authority if found (corrupts links file).
+- Use builtin VDR function to sort timers, if available.
+- Update VPS patch for VDR 1.7.29.
diff --git a/README b/README
index a050112..5fd623b 100644
--- a/README
+++ b/README
@@ -102,6 +102,8 @@ LSTL Print the series links list
LSTS Print the 'suggested' events list
+LSTT Print the list of timers with suggestions for each event
+
LSTY Print the CRIDs for each event
LSTZ Print the Default Authority data for each channel
@@ -112,15 +114,27 @@ STRT
UPDT Trigger an update of the series links.
+OSD
+
+The plugin adds an entry to the VDR Main Menu called "Series Links". This shows
+the title of the first programme in the series and the date (DD.MM) of the most
+recent timer - if the series is still running this date will usually be in the
+future. From this menu you can view further information on a selected series, or
+delete a series together with any remaining timers.
+
+The configuration settings described above can also be set using the "Setup"
+menu in the OSD.
+
+
Files
The plugin stores details of series links in the file links.data which is in the
-VIDEODIR/plugins directory. Entries in this file have the format:
+VIDEODIR/plugins/vdrtva directory. Entries in this file have the format:
<scrid>,<modtime>;<icrids>;<path>;<title>
scrid The series CRID.
-modtime The start time of the last event in this series.
+modtime The start time of the latest event in this series.
icrids The CRIDS of the events in the series, separated by colons.
path The subdirectory to store recordings in this series, taken from the first
timer, or the string (NULL) if no subdirectory was given.
@@ -142,7 +156,7 @@ Points to remember:
- A series link is created for every timer whether you want one or not.
- This plugin has not been tested with multiple tuner cards or with mixed DVB-T
- and DVB-S setups.
+ and DVB-S setups. It will try to collect CRID data from the Primary DVB device.
- The 'suggested' events list may have CRIDs which do not appear in the events
list.
diff --git a/TODO b/TODO
index d343fb5..5dd9ebb 100644
--- a/TODO
+++ b/TODO
@@ -12,8 +12,6 @@ Delete a series link if the only timer is manually deleted.
Display suggestions for timers which don't have series CRIDs.
-OSD for managing series links (work in progress).
-
Option to select which device to use for CRID collection.
Remove reliance on VDR "Housekeeping" callback - causes problems when VDR is busy.
diff --git a/vdr-1.7.28-rsvps.patch b/vdr-1.7.29-rsvps.patch
index 5964764..0a7fa23 100644
--- a/vdr-1.7.28-rsvps.patch
+++ b/vdr-1.7.29-rsvps.patch
@@ -1,6 +1,6 @@
-diff -u vdr-1.7.28/config.c vdr-1.7/config.c
---- vdr-1.7.28/config.c 2012-05-11 12:06:57.000000000 +0100
-+++ vdr-1.7/config.c 2012-06-08 11:03:58.670418555 +0100
+diff -ur vdrtest/config.c vdr-1.7/config.c
+--- vdrtest/config.c 2012-06-17 13:27:07.000000000 +0100
++++ vdr-1.7/config.c 2012-07-14 15:06:41.138878534 +0100
@@ -415,6 +415,7 @@
UseSubtitle = 1;
UseVps = 0;
@@ -9,7 +9,7 @@ diff -u vdr-1.7.28/config.c vdr-1.7/config.c
RecordingDirs = 1;
FoldersInTimerMenu = 1;
NumberKeysForChars = 1;
-@@ -610,6 +611,7 @@
+@@ -611,6 +612,7 @@
else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value);
else if (!strcasecmp(Name, "UseVps")) UseVps = atoi(Value);
else if (!strcasecmp(Name, "VpsMargin")) VpsMargin = atoi(Value);
@@ -17,7 +17,7 @@ diff -u vdr-1.7.28/config.c vdr-1.7/config.c
else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value);
else if (!strcasecmp(Name, "FoldersInTimerMenu")) FoldersInTimerMenu = atoi(Value);
else if (!strcasecmp(Name, "NumberKeysForChars")) NumberKeysForChars = atoi(Value);
-@@ -708,6 +710,7 @@
+@@ -710,6 +712,7 @@
Store("UseSubtitle", UseSubtitle);
Store("UseVps", UseVps);
Store("VpsMargin", VpsMargin);
@@ -25,9 +25,9 @@ diff -u vdr-1.7.28/config.c vdr-1.7/config.c
Store("RecordingDirs", RecordingDirs);
Store("FoldersInTimerMenu", FoldersInTimerMenu);
Store("NumberKeysForChars", NumberKeysForChars);
-diff -u vdr-1.7.28/config.h vdr-1.7/config.h
---- vdr-1.7.28/config.h 2012-04-15 11:45:32.000000000 +0100
-+++ vdr-1.7/config.h 2012-06-08 11:03:58.672418431 +0100
+diff -ur vdrtest/config.h vdr-1.7/config.h
+--- vdrtest/config.h 2012-06-17 12:14:50.000000000 +0100
++++ vdr-1.7/config.h 2012-07-14 15:06:41.138878534 +0100
@@ -285,6 +285,7 @@
int UseSubtitle;
int UseVps;
@@ -36,10 +36,10 @@ diff -u vdr-1.7.28/config.h vdr-1.7/config.h
int RecordingDirs;
int FoldersInTimerMenu;
int NumberKeysForChars;
-diff -u vdr-1.7.28/menu.c vdr-1.7/menu.c
---- vdr-1.7.28/menu.c 2012-05-12 14:08:23.000000000 +0100
-+++ vdr-1.7/menu.c 2012-06-08 11:03:58.675418246 +0100
-@@ -3076,6 +3076,7 @@
+diff -ur vdrtest/menu.c vdr-1.7/menu.c
+--- vdrtest/menu.c 2012-06-17 12:12:25.000000000 +0100
++++ vdr-1.7/menu.c 2012-07-14 15:06:41.143878229 +0100
+@@ -3107,6 +3107,7 @@
Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps));
Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0));
@@ -47,9 +47,9 @@ diff -u vdr-1.7.28/menu.c vdr-1.7/menu.c
Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord)));
Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME));
-diff -u vdr-1.7.28/timers.c vdr-1.7/timers.c
---- vdr-1.7.28/timers.c 2012-04-25 10:02:03.000000000 +0100
-+++ vdr-1.7/timers.c 2012-06-08 11:03:58.676418184 +0100
+diff -ur vdrtest/timers.c vdr-1.7/timers.c
+--- vdrtest/timers.c 2012-06-09 15:37:24.000000000 +0100
++++ vdr-1.7/timers.c 2012-07-14 15:06:41.144878168 +0100
@@ -431,7 +431,7 @@
deferred = 0;
diff --git a/vdrtva.c b/vdrtva.c
index 86b6a5b..9b95d3e 100644
--- a/vdrtva.c
+++ b/vdrtva.c
@@ -24,9 +24,9 @@ cLinks Links;
cTvaLog tvalog;
char *configDir;
-static const char *VERSION = "0.2.2";
+static const char *VERSION = "0.3.0";
static const char *DESCRIPTION = "Series Record plugin";
-//static const char *MAINMENUENTRY = "Series Links";
+static const char *MAINMENUENTRY = "Series Links";
int collectionperiod; // Time to collect all CRID data (default 10 minutes)
int lifetime; // Lifetime of series link recordings (default 99)
@@ -36,7 +36,6 @@ int updatetime; // Time to carry out the series link update HHMM (default 03:0
bool captureComplete; // Flag set if initial CRID capture has completed.
time_t startTime; // Time the plugin was initialised.
-
class cPluginvdrTva : public cPlugin {
private:
// Add any member variables or functions you may need here.
@@ -76,7 +75,7 @@ public:
virtual void MainThreadHook(void);
virtual cString Active(void);
virtual time_t WakeupTime(void);
-// virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); }
+ virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); }
virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value);
@@ -296,7 +295,7 @@ time_t cPluginvdrTva::WakeupTime(void)
cOsdObject *cPluginvdrTva::MainMenuAction(void)
{
// Perform the action when selected from the main VDR menu.
- return NULL;
+ return new cMenuLinks;
}
cMenuSetupPage *cPluginvdrTva::SetupMenu(void)
@@ -511,12 +510,14 @@ void cPluginvdrTva::Report()
{
if ((Timers.Count() == 0) || (!captureComplete)) return;
REPORT(" \nTimers and Suggestions\n----------------------\n ");
- cTvaTimers tvatimers;
- for (cTvaTimerItem *ti = tvatimers.First(); ti; ti = tvatimers.Next(ti)) {
- const cEvent *event = ti->Timer()->Event();
- if (event && ti->Timer()->HasFlags(tfActive)) {
- REPORT("'%s' (%s %s)", event->Title(), ti->Timer()->Channel()->Name(), *DayDateTime(event->StartTime()));
- FindSuggestions(event);
+ cSortedTimers SortedTimers;
+ for (int i = 0; i < SortedTimers.Size(); i++) {
+ if (const cTimer *ti = SortedTimers[i]) {
+ const cEvent *event = ti->Event();
+ if (event && ti->HasFlags(tfActive)) {
+ REPORT("'%s' (%s %s)", event->Title(), ti->Channel()->Name(), *DayDateTime(event->StartTime()));
+ FindSuggestions(event);
+ }
}
}
}
@@ -1010,37 +1011,6 @@ char mailcmd[256];
/*
- cTvaTimerItem - the things we need to do just to list the timers in order...
-*/
-
-
-cTvaTimerItem::cTvaTimerItem(cTimer *Timer)
-{
- timer = Timer;
-}
-
-int cTvaTimerItem::Compare(const cListObject &ListObject) const
-{
- return timer->Compare(*((cTvaTimerItem *)&ListObject)->timer);
-}
-
-
-/*
- cTvaTimers
-*/
-
-
-cTvaTimers::cTvaTimers(void)
-{
- for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
-// timer->SetEventFromSchedule(); // make sure the event is current
- Add(new cTvaTimerItem(timer));
- }
- Sort();
-}
-
-
-/*
cTvaFilter - capture the CRID data from EIT.
*/
@@ -1550,4 +1520,175 @@ void cLinks::SetUpdated(void)
}
+
+/*
+ cMenuLinkItem - Series Link OSD menu item
+*/
+
+cMenuLinkItem::cMenuLinkItem(cLinkItem *LinkItem)
+{
+ linkitem = LinkItem;
+ Set();
+}
+
+
+void cMenuLinkItem::Set(void)
+{
+ cString buffer;
+ char tim[32];
+ struct tm tm_r;
+ time_t t = linkitem->ModTime();
+ tm *tm = localtime_r(&t, &tm_r);
+ strftime(tim, sizeof(tim), "%d.%m", tm);
+ if (linkitem->Title()) {
+ buffer = cString::sprintf("%s\t%s", tim, linkitem->Title());
+ }
+ else {
+ buffer = cString::sprintf("%s\t(No Title)", tim);
+ }
+ SetText(buffer);
+}
+
+int cMenuLinkItem::Compare(const cListObject &ListObject) const
+{
+ cMenuLinkItem *p = (cMenuLinkItem *)&ListObject;
+ return linkitem->ModTime() - p->linkitem->ModTime();
+}
+
+// How many active timers are there for this series?
+
+int cMenuLinkItem::TimerCount(void) {
+ int count = 0;
+ if ((Timers.Count() == 0) || (!captureComplete)) return 99;
+ for (cTimer *ti = Timers.First(); ti; ti = Timers.Next(ti)) {
+ const cEvent *event = ti->Event();
+ if (event && ti->HasFlags(tfActive) && (ti->WeekDays() == 0)) {
+ cChannel *channel = Channels.GetByChannelID(event->ChannelID());
+ cChanDA *chanda = ChanDAs.GetByChannelID(channel->Number());
+ cEventCRID *eventcrid = EventCRIDs.GetByID(channel->Number(), event->EventID());
+ if (eventcrid && chanda) {
+ cString scrid = cString::sprintf("%s%s", chanda->DA(),eventcrid->sCRID());
+ if (!strcmp(scrid, sCRID())) count++;
+ }
+ }
+ }
+ return count;
+}
+
+
+/*
+ cMenuLinks - Series Link OSD menu
+*/
+
+cMenuLinks::cMenuLinks(void):cOsdMenu(tr("Series Links"), 6)
+{
+ Clear();
+ for (cLinkItem *LinkItem = Links.First(); LinkItem; LinkItem = Links.Next(LinkItem)) {
+ cMenuLinkItem *item = new cMenuLinkItem(LinkItem);
+ Add(item);
+ }
+ Sort();
+ SetHelp(tr("Delete"), tr("Info"), tr(""), tr(""));
+ Display();
+}
+
+void cMenuLinks::Propagate(void)
+{
+ for (cMenuLinkItem *ci = (cMenuLinkItem *)First(); ci; ci = (cMenuLinkItem *)ci->Next())
+ ci->Set();
+ Display();
+}
+
+eOSState cMenuLinks::ProcessKey(eKeys Key)
+{
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kRed: return Delete();
+ case kGreen: return Info();
+ case kYellow:
+ case kBlue:
+ case kOk:
+ default: state = osContinue;
+ }
+ }
+ return state;
+}
+
+eOSState cMenuLinks::Delete(void)
+{
+ if (HasSubMenu() || Count() == 0) return osContinue;
+ if (!captureComplete) {
+ Skins.Message(mtError, tr("Data capture still in progress"));
+ return osContinue;
+ }
+ int Index = Current();
+ cMenuLinkItem *item = (cMenuLinkItem *)Get(Index);
+ int timercount = item->TimerCount();
+ cString prompt;
+ if (timercount > 1) {
+ prompt = cString::sprintf(tr("Delete series link & %d timers?"), timercount);
+ }
+ else if (timercount == 1) {
+ prompt = cString::sprintf(tr("Delete series link & 1 timer?"));
+ }
+ else {
+ prompt = cString::sprintf(tr("Delete series link?"));
+ }
+ if (Interface->Confirm(prompt)) {
+ char *linkCRID = item->sCRID();
+ cOsdMenu::Del(Index);
+ Propagate();
+ isyslog("vdrtva: series link %s deleted by OSD", linkCRID);
+ Links.DeleteItem(linkCRID);
+ }
+ return osContinue;
+}
+
+eOSState cMenuLinks::Info(void)
+{
+ if (HasSubMenu() || Count() == 0) return osContinue;
+ if (!captureComplete) {
+ Skins.Message(mtError, tr("Data capture still in progress"));
+ return osContinue;
+ }
+ int Index = Current();
+ cMenuLinkItem *menuitem = (cMenuLinkItem *)Get(Index);
+ cLinkItem *linkitem = menuitem->LinkItem();
+ char *icrids = linkitem->iCRIDs();
+ int eventcount = 1;
+ while (icrids = strchr(icrids, ':')) {
+ eventcount++;
+ icrids++;
+ }
+ cString message = cString::sprintf("Series CRID: %s\nTotal Events: %d\nActive Timers: %d",
+ menuitem->sCRID(), eventcount, menuitem->TimerCount());
+ if (linkitem->Title()) {
+ return AddSubMenu(new cMenuText(linkitem->Title(), message, fontOsd));
+ }
+ else {
+ return AddSubMenu(new cMenuText(tr("(No Title)"), message, fontOsd));
+ }
+}
+
+
+#if VDRVERSNUM < 10728
+
+// --- cSortedTimers (copied from timers.c v1.7.29) ---
+
+static int CompareTimers(const void *a, const void *b)
+{
+ return (*(const cTimer **)a)->Compare(**(const cTimer **)b);
+}
+
+cSortedTimers::cSortedTimers(void)
+:cVector<const cTimer *>(Timers.Count())
+{
+ for (const cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer))
+ Append(Timer);
+ Sort(CompareTimers);
+}
+#endif
+
VDRPLUGINCREATOR(cPluginvdrTva); // Don't touch this!
diff --git a/vdrtva.h b/vdrtva.h
index c824db6..3f5de1a 100644
--- a/vdrtva.h
+++ b/vdrtva.h
@@ -1,6 +1,9 @@
#include <vdr/filter.h>
#include <vdr/device.h>
#include <vdr/status.h>
+#include <vdr/interface.h>
+#include <vdr/menu.h>
+
class cTvaFilter : public cFilter {
private:
@@ -65,22 +68,6 @@ class cTvaLog {
};
-class cTvaTimerItem : public cListObject {
-private:
- cTimer *timer;
-public:
- cTvaTimerItem(cTimer *Timer);
- virtual int Compare(const cListObject &ListObject) const;
- cTimer *Timer(void) { return timer; }
-};
-
-
-class cTvaTimers : public cConfig<cTvaTimerItem> {
-public:
- cTvaTimers(void);
-};
-
-
class cChanDA : public cListObject {
private:
int cid;
@@ -195,3 +182,36 @@ class cLinks : public cRwLock, public cConfig<cLinkItem> {
void SetUpdated(void);
void DeleteTimersForSCRID(const char *sCRID);
};
+
+
+class cMenuLinks : public cOsdMenu {
+private:
+ void Propagate(void);
+ eOSState Delete(void);
+ eOSState Info(void);
+public:
+ cMenuLinks(void);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+class cMenuLinkItem : public cOsdItem {
+private:
+ cLinkItem *linkitem;
+public:
+ cMenuLinkItem(cLinkItem *LinkItem);
+ char * sCRID(void) { return linkitem->sCRID(); }
+ cLinkItem * LinkItem(void) { return linkitem; }
+ int TimerCount(void);
+ virtual void Set(void);
+ virtual int Compare(const cListObject &ListObject) const;
+};
+
+#if VDRVERSNUM < 10728
+
+// Copied from timers.c v1.7.29
+
+class cSortedTimers : public cVector<const cTimer *> {
+public:
+ cSortedTimers(void);
+ };
+#endif