From 07d92eaee7d1ff37a6abfe873275b2f82a979271 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Mon, 24 Jul 2000 16:43:04 +0200 Subject: [PATCH] Implemented 'summary' feature --- CONTRIBUTORS | 1 + HISTORY | 12 +++++++- config.c | 22 +++++++++++++-- config.h | 7 +++-- menu.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++--- recording.c | 72 ++++++++++++++++++++++++++++++++++++++++-------- recording.h | 6 ++-- 7 files changed, 175 insertions(+), 23 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index de4cae20..44980137 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -3,6 +3,7 @@ Thanks go to the following people for patches and contributions: Carsten Koch for adding LIRC support for making the 'Recordings' menu be listed alphabetically + for implementing the 'Summary' feature Plamen Ganev for fixing the frequency offset for Hotbird channels diff --git a/HISTORY b/HISTORY index 10154cfe..41f8697f 100644 --- a/HISTORY +++ b/HISTORY @@ -56,7 +56,7 @@ Video Disk Recorder Revision History the PC keyboard to better resemble the "up-down-left-right-ok" layout on menu controlling remote control units. -2000-07-23: Version 0.06 +2000-07-24: Version 0.6 - Added support for LIRC remote control (thanks to Carsten Koch!). There are now three different remote control modes: KBD (PC-Keyboard), RCU @@ -87,3 +87,13 @@ Video Disk Recorder Revision History the VDR over a network connection. - Implemented command line option handling. - The program can now run in full background mode by using the --daemon option. +- Added a "summary" field to the timers (thanks to Carsten Koch!). + This field can contain a descriptive text of the programme and will be + displayed when the "Blue" key is pressed on a recording that was created by + this timer. If the text contains the special character '|', a newline will + be inserted at that place. When pressing "Ok" on a timer that contains a + summary field, the summary will be displayed. To edit such a timer the "Red" + key must be pressed. Timers without a summary still go into Edit mode when + pressing "Ok". The summary field can only be filled in directly by editing + the 'timers.conf' file with a text editor, or by defining/modifying the timer + via the SVDRP interface. diff --git a/config.c b/config.c index 72043c13..d77d07e7 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.13 2000/07/23 11:56:06 kls Exp $ + * $Id: config.c 1.14 2000/07/23 17:22:08 kls Exp $ */ #include "config.h" @@ -274,13 +274,27 @@ cTimer::cTimer(bool Instant) priority = 99; lifetime = 99; *file = 0; + summary = NULL; if (Instant) snprintf(file, sizeof(file), "@%s", cChannel::GetChannelName(CurrentChannel)); } +cTimer::~cTimer() +{ + delete summary; +} + +cTimer& cTimer::operator= (const cTimer &Timer) +{ + memcpy(this, &Timer, sizeof(*this)); + if (summary) + summary = strdup(summary); + return *this; +} + const char *cTimer::ToText(cTimer *Timer) { - asprintf(&buffer, "%d:%d:%s:%d:%d:%d:%d:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file); + asprintf(&buffer, "%d:%d:%s:%d:%d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); return buffer; } @@ -344,7 +358,9 @@ bool cTimer::Parse(const char *s) { char *buffer1 = NULL; char *buffer2 = NULL; - if (8 == sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2)) { + delete summary; + summary = NULL; + if (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) { //TODO add more plausibility checks day = ParseDay(buffer1); strncpy(file, buffer2, MaxFileName - 1); diff --git a/config.h b/config.h index 28d07edf..be1c7ec7 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.10 2000/07/23 11:54:53 kls Exp $ + * $Id: config.h 1.11 2000/07/23 17:17:10 kls Exp $ */ #ifndef __CONFIG_H @@ -17,7 +17,7 @@ #include "dvbapi.h" #include "tools.h" -#define MaxBuffer 1000 +#define MaxBuffer 10000 enum eKeys { // "Up" and "Down" must be the first two keys! kUp, @@ -100,7 +100,10 @@ public: int priority; int lifetime; char file[MaxFileName]; + char *summary; cTimer(bool Instant = false); + ~cTimer(); + cTimer& operator= (const cTimer &Timer); const char *ToText(void); bool Parse(const char *s); bool Save(FILE *f); diff --git a/menu.c b/menu.c index 1a8103ce..17a9b0b5 100644 --- a/menu.c +++ b/menu.c @@ -4,10 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.19 2000/07/16 14:52:48 kls Exp $ + * $Id: menu.c 1.20 2000/07/24 16:25:53 kls Exp $ */ #include "menu.h" +#include #include #include #include @@ -707,6 +708,51 @@ eOSState cMenuChannels::ProcessKey(eKeys Key) return state; } +// --- cMenuSummary -------------------------------------------------------- + +class cMenuSummary : public cOsdMenu { +public: + cMenuSummary(const char *Text); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuSummary::cMenuSummary(const char *Text) +:cOsdMenu("Summary") +{ + while (*Text) { + char line[MenuColumns + 1]; + char *p = line; + const char *b = NULL; + *p++ = ' '; + while (*Text && p - line < MenuColumns - 2) { + if (isspace(*Text)) + b = Text; // remember the blank + if (*Text == '\n') + break; + *p++ = *Text++; + } + if (*Text) { + if (b && Text - b > 0) { + p -= Text - b; + Text = b + 1; + } + else + Text++; + } + *p = 0; + Add(new cOsdItem(line, osBack)); + } +} + +eOSState cMenuSummary::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) + state = osContinue; + return state; +} + // --- cMenuEditTimer -------------------------------------------------------- class cMenuEditTimer : public cOsdMenu { @@ -799,6 +845,7 @@ private: eOSState New(void); eOSState Del(void); virtual void Move(int From, int To); + eOSState Summary(void); public: cMenuTimers(void); virtual eOSState ProcessKey(eKeys Key); @@ -880,6 +927,16 @@ void cMenuTimers::Move(int From, int To) isyslog(LOG_INFO, "timer %d moved to %d", From + 1, To + 1); } +eOSState cMenuTimers::Summary(void) +{ + if (HasSubMenu() || Count() == 0) + return osContinue; + cTimer *ti = Timers.Get(Current()); + if (ti && ti->summary && *ti->summary) + return AddSubMenu(new cMenuSummary(ti->summary)); + return Edit(); // convenience for people not using the Summary feature ;-) +} + eOSState cMenuTimers::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); @@ -888,7 +945,7 @@ eOSState cMenuTimers::ProcessKey(eKeys Key) switch (Key) { case kLeft: case kRight: return Activate(Key == kRight); - case kOk: + case kOk: return Summary(); case kRed: return Edit(); case kGreen: return New(); case kYellow: return Del(); @@ -926,6 +983,7 @@ private: cRecordings Recordings; eOSState Play(void); eOSState Del(void); + eOSState Summary(void); public: cMenuRecordings(void); virtual eOSState ProcessKey(eKeys Key); @@ -941,7 +999,7 @@ cMenuRecordings::cMenuRecordings(void) recording = Recordings.Next(recording); } } - SetHelp("Play", NULL/*XXX"Resume"*/, "Delete"); + SetHelp("Play", NULL/*XXX"Resume"*/, "Delete", "Summary"); } eOSState cMenuRecordings::Play(void) @@ -975,6 +1033,16 @@ eOSState cMenuRecordings::Del(void) return osContinue; } +eOSState cMenuRecordings::Summary(void) +{ + if (HasSubMenu() || Count() == 0) + return osContinue; + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri && ri->recording->Summary() && *ri->recording->Summary()) + return AddSubMenu(new cMenuSummary(ri->recording->Summary())); + return osContinue; +} + eOSState cMenuRecordings::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); @@ -984,6 +1052,7 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) case kOk: case kRed: return Play(); case kYellow: return Del(); + case kBlue: return Summary(); default: break; } } @@ -1061,7 +1130,8 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer->SetRecording(true); cChannel::SwitchTo(timer->channel - 1, dvbApi); cRecording Recording(timer); - dvbApi->StartRecord(Recording.FileName()); + if (dvbApi->StartRecord(Recording.FileName())) + Recording.WriteSummary(); Interface.DisplayRecording(dvbApi->Index(), true); } diff --git a/recording.c b/recording.c index 3e9df374..e37ccd85 100644 --- a/recording.c +++ b/recording.c @@ -4,14 +4,16 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.11 2000/07/16 14:21:37 kls Exp $ + * $Id: recording.c 1.12 2000/07/24 16:31:07 kls Exp $ */ #define _GNU_SOURCE #include "recording.h" #include +#include #include #include +#include #include "interface.h" #include "tools.h" @@ -20,6 +22,8 @@ #define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT #define NAMEFORMAT "%s/%s/" DATAFORMAT +#define SUMMARYFILESUFFIX "/summary.vdr" + #define FINDCMD "find %s -type d -name '%s' | sort -df" #define DFCMD "df -m %s" @@ -102,21 +106,14 @@ void AssertFreeDiskSpace(void) // --- cRecording ------------------------------------------------------------ -cRecording::cRecording(const char *Name, time_t Start, int Priority, int LifeTime) -{ - titleBuffer = NULL; - fileName = NULL; - name = strdup(Name); - start = Start; - priority = Priority; - lifetime = LifeTime; -} - cRecording::cRecording(cTimer *Timer) { titleBuffer = NULL; fileName = NULL; name = strdup(Timer->file); + summary = Timer->summary ? strdup(Timer->summary) : NULL; + if (summary) + strreplace(summary, '|', '\n'); start = Timer->StartTime(); priority = Timer->priority; lifetime = Timer->lifetime; @@ -130,6 +127,7 @@ cRecording::cRecording(const char *FileName) char *p = strrchr(FileName, '/'); name = NULL; + summary = NULL; if (p) { time_t now = time(NULL); struct tm t = *localtime(&now); // this initializes the time zone in 't' @@ -143,6 +141,39 @@ cRecording::cRecording(const char *FileName) name[p - FileName] = 0; strreplace(name, '_', ' '); } + // read an optional summary file: + char *SummaryFileName = NULL; + asprintf(&SummaryFileName, "%s%s", fileName, SUMMARYFILESUFFIX); + int f = open(SummaryFileName, O_RDONLY); + if (f >= 0) { + struct stat buf; + if (fstat(f, &buf) == 0) { + int size = buf.st_size; + summary = new char[size + 1]; // +1 for terminating 0 + if (summary) { + int rbytes = read(f, summary, size); + if (rbytes >= 0) { + summary[rbytes] = 0; + if (rbytes != size) + esyslog(LOG_ERR, "%s: expected %d bytes but read %d", SummaryFileName, size, rbytes); + } + else { + LOG_ERROR_STR(SummaryFileName); + delete summary; + summary = NULL; + } + + } + else + esyslog(LOG_ERR, "can't allocate %d byte of memory for summary file '%s'", size + 1, SummaryFileName); + close(f); + } + else + LOG_ERROR_STR(SummaryFileName); + } + else if (errno != ENOENT) + LOG_ERROR_STR(SummaryFileName); + delete SummaryFileName; } } @@ -151,6 +182,7 @@ cRecording::~cRecording() delete titleBuffer; delete fileName; delete name; + delete summary; } const char *cRecording::FileName(void) @@ -181,6 +213,24 @@ const char *cRecording::Title(char Delimiter) return titleBuffer; } +bool cRecording::WriteSummary(void) +{ + if (summary) { + char *SummaryFileName = NULL; + asprintf(&SummaryFileName, "%s%s", fileName, SUMMARYFILESUFFIX); + FILE *f = fopen(SummaryFileName, "w"); + if (f) { + if (fputs(summary, f) < 0) + LOG_ERROR_STR(SummaryFileName); + fclose(f); + } + else + LOG_ERROR_STR(SummaryFileName); + delete SummaryFileName; + } + return true; +} + bool cRecording::Delete(void) { bool result = true; diff --git a/recording.h b/recording.h index eeea5609..e501af82 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.6 2000/04/24 09:45:49 kls Exp $ + * $Id: recording.h 1.7 2000/07/23 19:06:14 kls Exp $ */ #ifndef __RECORDING_H @@ -22,16 +22,18 @@ private: char *titleBuffer; char *fileName; char *name; + char *summary; public: time_t start; int priority; int lifetime; - cRecording(const char *Name, time_t Start, int Priority, int LifeTime); cRecording(cTimer *Timer); cRecording(const char *FileName); ~cRecording(); const char *FileName(void); const char *Title(char Delimiter = ' '); + const char *Summary(void) { return summary; } + bool WriteSummary(void); bool Delete(void); // Changes the file name so that it will no longer be visible in the "Recordings" menu // Returns false in case of error