summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY20
-rw-r--r--MANUAL2
-rw-r--r--PLUGINS/src/skincurses/HISTORY4
-rw-r--r--PLUGINS/src/skincurses/skincurses.c29
-rw-r--r--cutter.c4
-rw-r--r--eit.c28
-rw-r--r--epg.c141
-rw-r--r--epg.h16
-rw-r--r--i18n.c23
-rw-r--r--menu.c161
-rw-r--r--menu.h4
-rw-r--r--recording.c146
-rw-r--r--recording.h26
-rw-r--r--skinclassic.c30
-rw-r--r--skins.h4
-rw-r--r--skinsttng.c36
-rwxr-xr-xsummary2info.pl47
-rw-r--r--svdrp.c18
-rw-r--r--tools.c21
-rw-r--r--tools.h4
-rw-r--r--vdr.510
21 files changed, 525 insertions, 249 deletions
diff --git a/HISTORY b/HISTORY
index 76a25e53..60663ed2 100644
--- a/HISTORY
+++ b/HISTORY
@@ -3513,7 +3513,7 @@ Video Disk Recorder Revision History
- Fixed a wrong inheritance in libsi's SubtitlingDescriptor::Subtitling (thanks to
Marco Schlüßler).
-2005-05-14: Version 1.3.25
+2005-05-16: Version 1.3.25
- Updated the Estonian OSD texts (thanks to Arthur Konovalov).
- Some cable providers don't mark short channel names according to the standard,
@@ -3526,3 +3526,21 @@ Video Disk Recorder Revision History
- Made cOsd::isOpen an integer counter to avoid problems with messages when a
cOsdObject uses the raw OSD (thanks to Andreas Regel for reporting this one).
- Updated the Danish OSD texts (thanks to Mogens Elneff).
+- The file 'summary.vdr' has been replaced with 'info.vdr' and now contains the
+ information about a recording, in the same format as the events are stored in
+ 'epg.data' (see man vdr(5) for details). Existing summary files can be converted
+ to the new format by running the Perl script 'summary2info.pl', as in
+
+ summary2info.pl /video
+
+ (the parameter given has to be the video directory).
+- The "Summary" button in the "Recordings" menu has been renamed to "Info", and
+ the page it brings up now shows the recording's information, much like the EPG
+ event page. Therefore it now no longer uses the skin's SetText() function, but
+ rather the SetRecording() function. Skin plugins may need to adjust that function
+ accordingly (see skinsttng.c, for instance).
+- The SVDRP command LSTR now lists the recording information in the same tagged
+ format as the LSTE command lists the EPG data.
+- The audio track menu now contains track descriptions when replaying (provided
+ such descriptions were available in the EPG data when the recording was made,
+ and are stored in the info.vdr file).
diff --git a/MANUAL b/MANUAL
index ebf8ce02..8a65809e 100644
--- a/MANUAL
+++ b/MANUAL
@@ -23,7 +23,7 @@ Version 1.2
Red - Record Edit Edit ABC/abc Play/Commands(2) Jump -
Green - Audio New New Ins/Ovr Rewind Skip -60s -
Yellow - Pause live Delete Delete Delete Delete Skip +60s -
- Blue - Stop/Resume Mark On/Off(1) - Summary Stop -
+ Blue - Stop/Resume Mark On/Off(1) - Info Stop -
0..9 Ch select - Sort(3) Day(4) Numeric inp. Exec cmd(2) Editing -
In a numerical input field (like the response to a CAM enquiry) the keys 0..9
diff --git a/PLUGINS/src/skincurses/HISTORY b/PLUGINS/src/skincurses/HISTORY
index 8ba4ae4e..33119f4a 100644
--- a/PLUGINS/src/skincurses/HISTORY
+++ b/PLUGINS/src/skincurses/HISTORY
@@ -13,3 +13,7 @@ VDR Plugin 'skincurses' Revision History
- Made several functions threadsafe.
- New audio track display.
+
+2005-05-16: Version 0.0.4
+
+- New "recording info" display.
diff --git a/PLUGINS/src/skincurses/skincurses.c b/PLUGINS/src/skincurses/skincurses.c
index a1c59540..ad1a26b4 100644
--- a/PLUGINS/src/skincurses/skincurses.c
+++ b/PLUGINS/src/skincurses/skincurses.c
@@ -3,7 +3,7 @@
*
* See the README file for copyright information and how to reach the author.
*
- * $Id: skincurses.c 1.5 2005/01/09 11:56:26 kls Exp $
+ * $Id: skincurses.c 1.6 2005/05/16 10:45:12 kls Exp $
*/
#include <ncurses.h>
@@ -11,7 +11,7 @@
#include <vdr/plugin.h>
#include <vdr/skins.h>
-static const char *VERSION = "0.0.3";
+static const char *VERSION = "0.0.4";
static const char *DESCRIPTION = "A text only skin";
static const char *MAINMENUENTRY = NULL;
@@ -407,7 +407,30 @@ void cSkinCursesDisplayMenu::SetEvent(const cEvent *Event)
void cSkinCursesDisplayMenu::SetRecording(const cRecording *Recording)
{
- SetText(Recording->Summary(), false); //TODO
+ if (!Recording)
+ return;
+ const cRecordingInfo *Info = Recording->Info();
+ int y = 2;
+ cTextScroller ts;
+ char t[32];
+ snprintf(t, sizeof(t), "%s %s", *DateString(Recording->start), *TimeString(Recording->start));
+ ts.Set(osd, 0, y, OsdWidth, OsdHeight - y - 2, t, &Font, clrYellow, clrBackground);
+ y += ts.Height();
+ y += 1;
+ const char *Title = Info->Title();
+ if (isempty(Title))
+ Title = Recording->Name();
+ ts.Set(osd, 0, y, OsdWidth, OsdHeight - y - 2, Title, &Font, clrCyan, clrBackground);
+ y += ts.Height();
+ if (!isempty(Info->ShortText())) {
+ ts.Set(osd, 0, y, OsdWidth, OsdHeight - y - 2, Info->ShortText(), &Font, clrYellow, clrBackground);
+ y += ts.Height();
+ }
+ y += 1;
+ if (!isempty(Info->Description())) {
+ textScroller.Set(osd, 0, y, OsdWidth - 2, OsdHeight - y - 2, Info->Description(), &Font, clrCyan, clrBackground);
+ SetScrollbar();
+ }
}
void cSkinCursesDisplayMenu::SetText(const char *Text, bool FixedFont)
diff --git a/cutter.c b/cutter.c
index c8ed60ec..82c7fe5b 100644
--- a/cutter.c
+++ b/cutter.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: cutter.c 1.7 2004/06/13 16:04:08 kls Exp $
+ * $Id: cutter.c 1.8 2005/05/15 14:21:08 kls Exp $
*/
#include "cutter.h"
@@ -204,7 +204,7 @@ bool cCutter::Start(const char *FileName)
free(s);
// XXX
editedVersionName = strdup(evn);
- Recording.WriteSummary();
+ Recording.WriteInfo();
Recordings.AddByName(editedVersionName);
cuttingThread = new cCuttingThread(FileName, editedVersionName);
return true;
diff --git a/eit.c b/eit.c
index 6c6381b1..9875f99b 100644
--- a/eit.c
+++ b/eit.c
@@ -8,7 +8,7 @@
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
*
- * $Id: eit.c 1.103 2005/03/20 12:33:51 kls Exp $
+ * $Id: eit.c 1.104 2005/05/15 10:36:04 kls Exp $
*/
#include "eit.h"
@@ -91,8 +91,7 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL;
SI::ShortEventDescriptor *ShortEventDescriptor = NULL;
cLinkChannels *LinkChannels = NULL;
- int NumComponents = 0;
- SI::ComponentDescriptor *ComponentDescriptors[MAXCOMPONENTS];
+ cComponents *Components = NULL;
for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) {
switch (d->getDescriptorTag()) {
case SI::ExtendedEventDescriptorTag: {
@@ -193,12 +192,10 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
uchar Stream = cd->getStreamContent();
uchar Type = cd->getComponentType();
if (1 <= Stream && Stream <= 2 && Type != 0) {
- if (NumComponents < MAXCOMPONENTS) {
- ComponentDescriptors[NumComponents++] = cd;
- d = NULL; // so that it is not deleted
- }
- else
- dsyslog("more than %d component descriptors!", MAXCOMPONENTS);
+ if (!Components)
+ Components = new cComponents;
+ char buffer[256];
+ Components->SetComponent(Components->NumComponents(), cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer)));
}
}
break;
@@ -221,18 +218,7 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
delete ExtendedEventDescriptors;
delete ShortEventDescriptor;
- if (NumComponents > 0) {
- cComponents *Components = new cComponents(NumComponents);
- for (int i = 0; i < NumComponents; i++) {
- char buffer[256];
- SI::ComponentDescriptor *cd = ComponentDescriptors[i];
- Components->SetComponent(i, cd->getStreamContent(), cd->getComponentType(), I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer)));
- delete cd;
- }
- pEvent->SetComponents(Components);
- }
- else
- pEvent->SetComponents(NULL);
+ pEvent->SetComponents(Components);
pEvent->FixEpgBugs();
if (LinkChannels)
diff --git a/epg.c b/epg.c
index 21bdeb5b..13a4ba81 100644
--- a/epg.c
+++ b/epg.c
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
- * $Id: epg.c 1.29 2005/05/05 13:53:19 kls Exp $
+ * $Id: epg.c 1.30 2005/05/16 14:12:00 kls Exp $
*/
#include "epg.h"
@@ -40,11 +40,10 @@ bool tComponent::FromString(const char *s)
// --- cComponents -----------------------------------------------------------
-cComponents::cComponents(int NumComponents)
+cComponents::cComponents(void)
{
- numComponents = NumComponents;
- components = MALLOC(tComponent, numComponents);
- memset(components, 0, sizeof(tComponent) * numComponents);
+ numComponents = 0;
+ components = NULL;
}
cComponents::~cComponents(void)
@@ -54,24 +53,30 @@ cComponents::~cComponents(void)
free(components);
}
-bool cComponents::SetComponent(int Index, const char *s)
+void cComponents::Realloc(int Index)
{
- if (Index < numComponents)
- return components[Index].FromString(s);
- return false;
+ if (Index >= numComponents) {
+ int n = numComponents;
+ numComponents = Index + 1;
+ components = (tComponent *)realloc(components, numComponents * sizeof(tComponent));
+ memset(&components[n], 0, sizeof(tComponent) * (numComponents - n));
+ }
}
-bool cComponents::SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description)
+void cComponents::SetComponent(int Index, const char *s)
{
- if (Index < numComponents) {
- tComponent *p = &components[Index];
- p->stream = Stream;
- p->type = Type;
- strn0cpy(p->language, Language, sizeof(p->language));
- p->description = strcpyrealloc(p->description, !isempty(Description) ? Description : NULL);
- return true;
- }
- return false;
+ Realloc(Index);
+ components[Index].FromString(s);
+}
+
+void cComponents::SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description)
+{
+ Realloc(Index);
+ tComponent *p = &components[Index];
+ p->stream = Stream;
+ p->type = Type;
+ strn0cpy(p->language, Language, sizeof(p->language));
+ p->description = strcpyrealloc(p->description, !isempty(Description) ? Description : NULL);
}
// --- cEvent ----------------------------------------------------------------
@@ -107,6 +112,11 @@ int cEvent::Compare(const cListObject &ListObject) const
return startTime - e->startTime;
}
+void cEvent::SetChannelID(tChannelID ChannelID)
+{
+ channelID = ChannelID;
+}
+
void cEvent::SetEventID(u_int16_t EventID)
{
eventID = EventID;
@@ -187,30 +197,17 @@ bool cEvent::IsRunning(bool OrAboutToStart) const
cString cEvent::GetDateString(void) const
{
- char buf[32];
- struct tm tm_r;
- tm *tm = localtime_r(&startTime, &tm_r);
- char *p = stpcpy(buf, WeekDayName(tm->tm_wday));
- *p++ = ' ';
- strftime(p, sizeof(buf) - (p - buf), "%d.%m.%Y", tm);
- return buf;
+ return DateString(startTime);
}
cString cEvent::GetTimeString(void) const
{
- char buf[25];
- struct tm tm_r;
- strftime(buf, sizeof(buf), "%R", localtime_r(&startTime, &tm_r));
- return buf;
+ return TimeString(startTime);
}
cString cEvent::GetEndTimeString(void) const
{
- char buf[25];
- time_t EndTime = startTime + duration;
- struct tm tm_r;
- strftime(buf, sizeof(buf), "%R", localtime_r(&EndTime, &tm_r));
- return buf;
+ return TimeString(startTime + duration);
}
cString cEvent::GetVpsString(void) const
@@ -221,10 +218,11 @@ cString cEvent::GetVpsString(void) const
return buf;
}
-void cEvent::Dump(FILE *f, const char *Prefix) const
+void cEvent::Dump(FILE *f, const char *Prefix, bool InfoOnly) const
{
- if (startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) {
- fprintf(f, "%sE %u %ld %d %X\n", Prefix, eventID, startTime, duration, tableID);
+ if (InfoOnly || startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) {
+ if (!InfoOnly)
+ fprintf(f, "%sE %u %ld %d %X\n", Prefix, eventID, startTime, duration, tableID);
if (!isempty(title))
fprintf(f, "%sT %s\n", Prefix, title);
if (!isempty(shortText))
@@ -240,18 +238,40 @@ void cEvent::Dump(FILE *f, const char *Prefix) const
fprintf(f, "%sX %s\n", Prefix, *p->ToString());
}
}
- if (vps)
+ if (!InfoOnly && vps)
fprintf(f, "%sV %ld\n", Prefix, vps);
- fprintf(f, "%se\n", Prefix);
+ if (!InfoOnly)
+ fprintf(f, "%se\n", Prefix);
}
}
+bool cEvent::Parse(char *s)
+{
+ char *t = skipspace(s + 1);
+ switch (*s) {
+ case 'T': SetTitle(t);
+ break;
+ case 'S': SetShortText(t);
+ break;
+ case 'D': strreplace(t, '|', '\n');
+ SetDescription(t);
+ break;
+ case 'X': if (!components)
+ components = new cComponents;
+ components->SetComponent(components->NumComponents(), t);
+ break;
+ case 'V': SetVps(atoi(t));
+ break;
+ default: esyslog("ERROR: unexpected tag while reading EPG data: %s", s);
+ return false;
+ }
+ return true;
+}
+
bool cEvent::Read(FILE *f, cSchedule *Schedule)
{
if (Schedule) {
cEvent *Event = NULL;
- int NumComponents = 0;
- char *ComponentStrings[MAXCOMPONENTS];
char *s;
cReadLine ReadLine;
while ((s = ReadLine.Read(f)) != NULL) {
@@ -273,45 +293,14 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
Event->SetDuration(Duration);
}
}
- NumComponents = 0;
- }
- break;
- case 'T': if (Event)
- Event->SetTitle(t);
- break;
- case 'S': if (Event)
- Event->SetShortText(t);
- break;
- case 'D': if (Event) {
- strreplace(t, '|', '\n');
- Event->SetDescription(t);
- }
- break;
- case 'X': if (Event) {
- if (NumComponents < MAXCOMPONENTS)
- ComponentStrings[NumComponents++] = strdup(t);
- else
- dsyslog("more than %d component descriptors!", MAXCOMPONENTS);
}
break;
- case 'V': if (Event)
- Event->SetVps(atoi(t));
- break;
- case 'e': if (Event && NumComponents > 0) {
- cComponents *Components = new cComponents(NumComponents);
- for (int i = 0; i < NumComponents; i++) {
- if (!Components->SetComponent(i, ComponentStrings[i]))
- esyslog("ERROR: faulty component string in EPG data: '%s'", ComponentStrings[i]);
- free(ComponentStrings[i]);
- }
- Event->SetComponents(Components);
- }
- Event = NULL;
+ case 'e': Event = NULL;
break;
case 'c': // to keep things simple we react on 'c' here
return true;
- default: esyslog("ERROR: unexpected tag while reading EPG data: %s", s);
- return false;
+ default: if (Event && !Event->Parse(s))
+ return false;
}
}
esyslog("ERROR: unexpected end of file while reading EPG data");
diff --git a/epg.h b/epg.h
index 6668a614..66d6cd43 100644
--- a/epg.h
+++ b/epg.h
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
- * $Id: epg.h 1.21 2005/03/20 12:32:36 kls Exp $
+ * $Id: epg.h 1.22 2005/05/16 14:11:28 kls Exp $
*/
#ifndef __EPG_H
@@ -18,7 +18,6 @@
#include "tools.h"
#define MAXEPGBUGFIXLEVEL 3
-#define MAXCOMPONENTS 32
enum eDumpMode { dmAll, dmPresent, dmFollowing, dmAtTime };
@@ -35,12 +34,13 @@ class cComponents {
private:
int numComponents;
tComponent *components;
+ void Realloc(int Index);
public:
- cComponents(int NumComponents);
+ cComponents(void);
~cComponents(void);
int NumComponents(void) const { return numComponents; }
- bool SetComponent(int Index, const char *s);
- bool SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description);
+ void SetComponent(int Index, const char *s);
+ void SetComponent(int Index, uchar Stream, uchar Type, const char *Language, const char *Description);
tComponent *Component(int Index) const { return (Index < numComponents) ? &components[Index] : NULL; }
};
@@ -56,7 +56,7 @@ private:
char *title; // Title of this event
char *shortText; // Short description of this event (typically the episode name in case of a series)
char *description; // Description of this event
- cComponents *components; // The stream components of this event (separated by '\n')
+ cComponents *components; // The stream components of this event
time_t startTime; // Start time of this event
int duration; // Duration of this event in seconds
time_t vps; // Video Programming Service timestamp (VPS, aka "Programme Identification Label", PIL)
@@ -86,6 +86,7 @@ public:
cString GetTimeString(void) const;
cString GetEndTimeString(void) const;
cString GetVpsString(void) const;
+ void SetChannelID(tChannelID ChannelID);
void SetEventID(u_int16_t EventID);
void SetTableID(uchar TableID);
void SetVersion(uchar Version);
@@ -98,7 +99,8 @@ public:
void SetDuration(int Duration);
void SetVps(time_t Vps);
void SetSeen(void);
- void Dump(FILE *f, const char *Prefix = "") const;
+ void Dump(FILE *f, const char *Prefix = "", bool InfoOnly = false) const;
+ bool Parse(char *s);
static bool Read(FILE *f, cSchedule *Schedule);
void FixEpgBugs(void);
};
diff --git a/i18n.c b/i18n.c
index b5a85a1b..e1a187de 100644
--- a/i18n.c
+++ b/i18n.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: i18n.c 1.190 2005/05/15 09:22:07 kls Exp $
+ * $Id: i18n.c 1.191 2005/05/15 14:37:59 kls Exp $
*
* Translations provided by:
*
@@ -399,6 +399,27 @@ const tI18nPhrase Phrases[] = {
"Kokkuvõte",
"Omtale",
},
+ { "Info",
+ "Info",
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ },
{ "Schedule - %s",
"Programm - %s",
"Program - %s",
diff --git a/menu.c b/menu.c
index 30183dfc..e36cc65f 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 1.348 2005/03/20 15:14:51 kls Exp $
+ * $Id: menu.c 1.349 2005/05/16 13:59:03 kls Exp $
*/
#include "menu.h"
@@ -872,7 +872,6 @@ eOSState cMenuTimers::Summary(void)
cTimer *ti = CurrentTimer();
if (ti && !isempty(ti->Summary()))
return AddSubMenu(new cMenuText(tr("Summary"), ti->Summary()));
- //XXX cSkin::SetRecording()???
return Edit(); // convenience for people not using the Summary feature ;-)
}
@@ -1297,8 +1296,12 @@ eOSState cMenuCommands::ProcessKey(eKeys Key)
if (state == osUnknown) {
switch (Key) {
- case kOk: return Execute();
- default: break;
+ case kRed:
+ case kGreen:
+ case kYellow:
+ case kBlue: return osContinue;
+ case kOk: return Execute();
+ default: break;
}
}
return state;
@@ -1430,6 +1433,63 @@ cOsdObject *CamControl(void)
return NULL;
}
+// --- cMenuRecording --------------------------------------------------------
+
+class cMenuRecording : public cOsdMenu {
+private:
+ const cRecording *recording;
+public:
+ cMenuRecording(const cRecording *Recording);
+ virtual void Display(void);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+cMenuRecording::cMenuRecording(const cRecording *Recording)
+:cOsdMenu(tr("Recording"))
+{
+ recording = Recording;
+ if (recording)
+ SetHelp(tr("Play"), tr("Rewind"));
+}
+
+void cMenuRecording::Display(void)
+{
+ cOsdMenu::Display();
+ DisplayMenu()->SetRecording(recording);
+ cStatus::MsgOsdTextItem(recording->Info()->Description());
+}
+
+eOSState cMenuRecording::ProcessKey(eKeys Key)
+{
+ switch (Key) {
+ case kUp|k_Repeat:
+ case kUp:
+ case kDown|k_Repeat:
+ case kDown:
+ case kLeft|k_Repeat:
+ case kLeft:
+ case kRight|k_Repeat:
+ case kRight:
+ DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight);
+ cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp);
+ return osContinue;
+ default: break;
+ }
+
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kRed: Key = kOk; // will play the recording, even if recording commands are defined
+ case kGreen: cRemote::Put(Key, true);
+ // continue with osBack to close the info menu and process the key
+ case kOk: return osBack;
+ default: break;
+ }
+ }
+ return state;
+}
+
// --- cMenuRecordingItem ----------------------------------------------------
class cMenuRecordingItem : public cOsdItem {
@@ -1530,7 +1590,7 @@ void cMenuRecordings::SetHelpKeys(void)
else {
NewHelpKeys = 2;
cRecording *recording = GetRecording(ri);
- if (recording && recording->Summary())
+ if (recording && recording->Info()->Title())
NewHelpKeys = 3;
}
}
@@ -1539,7 +1599,7 @@ void cMenuRecordings::SetHelpKeys(void)
case 0: SetHelp(NULL); break;
case 1: SetHelp(tr("Open")); break;
case 2:
- case 3: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Play"), tr("Rewind"), tr("Delete"), NewHelpKeys == 3 ? tr("Summary") : NULL);
+ case 3: SetHelp(RecordingCommands.Count() ? tr("Commands") : tr("Play"), tr("Rewind"), tr("Delete"), NewHelpKeys == 3 ? tr("Info") : NULL);
}
helpKeys = NewHelpKeys;
}
@@ -1644,15 +1704,15 @@ eOSState cMenuRecordings::Delete(void)
return osContinue;
}
-eOSState cMenuRecordings::Summary(void)
+eOSState cMenuRecordings::Info(void)
{
if (HasSubMenu() || Count() == 0)
return osContinue;
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri && !ri->IsDirectory()) {
cRecording *recording = GetRecording(ri);
- if (recording && recording->Summary() && *recording->Summary())
- return AddSubMenu(new cMenuText(tr("Summary"), recording->Summary()));
+ if (recording && recording->Info()->Title())
+ return AddSubMenu(new cMenuRecording(recording));
}
return osContinue;
}
@@ -1689,7 +1749,7 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
case kRed: return (helpKeys > 1 && RecordingCommands.Count()) ? Commands() : Play();
case kGreen: return Rewind();
case kYellow: return Delete();
- case kBlue: return Summary();
+ case kBlue: return Info();
case k1...k9: return Commands(Key);
default: break;
}
@@ -2568,36 +2628,43 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
// --- SetTrackDescriptions --------------------------------------------------
-static void SetTrackDescriptions(void)
+static void SetTrackDescriptions(bool Live)
{
cDevice::PrimaryDevice()->ClrAvailableTracks(true);
- cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel());
- if (Channel) {
- cSchedulesLock SchedulesLock;
- const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
- if (Schedules) {
- const cSchedule *Schedule = Schedules->GetSchedule(Channel->GetChannelID());
- if (Schedule) {
- const cEvent *Present = Schedule->GetPresentEvent(true);
- if (Present) {
- const cComponents *Components = Present->Components();
- if (Components) {
- int indexAudio = 0;
- int indexDolby = 0;
- for (int i = 0; i < Components->NumComponents(); i++) {
- const tComponent *p = Components->Component(i);
- if (p->stream == 2) {
- if (p->type == 0x05)
- cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, NULL, p->description);
- else
- cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, NULL, p->description);
- }
- }
- }
+ const cComponents *Components = NULL;
+ cSchedulesLock SchedulesLock;
+ if (Live) {
+ cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel());
+ if (Channel) {
+ const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
+ if (Schedules) {
+ const cSchedule *Schedule = Schedules->GetSchedule(Channel->GetChannelID());
+ if (Schedule) {
+ const cEvent *Present = Schedule->GetPresentEvent(true);
+ if (Present)
+ Components = Present->Components();
}
}
}
}
+ else if (cReplayControl::LastReplayed()) {
+ cRecording *Recording = Recordings.GetByName(cReplayControl::LastReplayed());
+ if (Recording)
+ Components = Recording->Info()->Components();
+ }
+ if (Components) {
+ int indexAudio = 0;
+ int indexDolby = 0;
+ for (int i = 0; i < Components->NumComponents(); i++) {
+ const tComponent *p = Components->Component(i);
+ if (p->stream == 2) {
+ if (p->type == 0x05)
+ cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, NULL, p->description);
+ else
+ cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, indexAudio++, 0, NULL, p->description);
+ }
+ }
+ }
}
// --- cDisplayChannel -------------------------------------------------------
@@ -2657,7 +2724,7 @@ void cDisplayChannel::DisplayInfo(void)
const cEvent *Present = Schedule->GetPresentEvent(true);
const cEvent *Following = Schedule->GetFollowingEvent(true);
if (Present != lastPresent || Following != lastFollowing) {
- SetTrackDescriptions();
+ SetTrackDescriptions(true);
displayChannel->SetEvents(Present, Following);
cStatus::MsgOsdProgramme(Present ? Present->StartTime() : 0, Present ? Present->Title() : NULL, Present ? Present->ShortText() : NULL, Following ? Following->StartTime() : 0, Following ? Following->Title() : NULL, Following ? Following->ShortText() : NULL);
lastPresent = Present;
@@ -2877,9 +2944,7 @@ cDisplayTracks::cDisplayTracks(void)
:cOsdObject(true)
{
cDevice::PrimaryDevice()->EnsureAudioTrack();
- // Get the actual audio track descriptions from the EPG if we're not replaying:
- if (!cDevice::PrimaryDevice()->Replaying() || cTransferControl::ReceiverDevice())
- SetTrackDescriptions();
+ SetTrackDescriptions(!cDevice::PrimaryDevice()->Replaying() || cTransferControl::ReceiverDevice());
currentDisplayTracks = this;
numTracks = track = 0;
audioChannel = cDevice::PrimaryDevice()->GetAudioChannel();
@@ -2994,6 +3059,11 @@ eOSState cDisplayTracks::ProcessKey(eKeys Key)
cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
{
+ // We're going to manipulate an event here, so we need to prevent
+ // others from modifying any EPG data:
+ cSchedulesLock SchedulesLock;
+ cSchedules::Schedules(SchedulesLock);
+
event = NULL;
instantId = NULL;
fileName = NULL;
@@ -3011,16 +3081,9 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
timer->SetRecording(true);
event = timer->Event();
- const char *Title = NULL;
- const char *Subtitle = NULL;
- const char *Summary = NULL;
- if (event || GetEvent()) {
- Title = event->Title();
- Subtitle = event->ShortText();
- Summary = event->Description();
- dsyslog("Title: '%s' Subtitle: '%s'", Title, Subtitle);
- }
- cRecording Recording(timer, Title, Subtitle, Summary);
+ if (event || GetEvent())
+ dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), event->ShortText());
+ cRecording Recording(timer, event);
fileName = strdup(Recording.FileName());
// crude attempt to avoid duplicate recordings:
@@ -3047,7 +3110,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
const cChannel *ch = timer->Channel();
recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids());
if (device->AttachReceiver(recorder)) {
- Recording.WriteSummary();
+ Recording.WriteInfo();
cStatus::MsgRecording(device, Recording.Name());
if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
cReplayControl::SetRecording(fileName, Recording.Name());
diff --git a/menu.h b/menu.h
index d142bbc4..93712e4e 100644
--- a/menu.h
+++ b/menu.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.h 1.69 2005/03/20 10:57:29 kls Exp $
+ * $Id: menu.h 1.70 2005/05/15 14:34:54 kls Exp $
*/
#ifndef __MENU_H
@@ -133,7 +133,7 @@ private:
eOSState Play(void);
eOSState Rewind(void);
eOSState Delete(void);
- eOSState Summary(void);
+ eOSState Info(void);
eOSState Commands(eKeys Key = kNone);
public:
cMenuRecordings(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false);
diff --git a/recording.c b/recording.c
index ed74c462..d20e9cbf 100644
--- a/recording.c
+++ b/recording.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.c 1.98 2005/05/07 15:25:15 kls Exp $
+ * $Id: recording.c 1.99 2005/05/16 14:19:38 kls Exp $
*/
#include "recording.h"
@@ -45,7 +45,7 @@
// end of implementation for brain dead systems
#define RESUMEFILESUFFIX "/resume%s%s.vdr"
-#define SUMMARYFILESUFFIX "/summary.vdr"
+#define INFOFILESUFFIX "/info.vdr"
#define MARKSFILESUFFIX "/marks.vdr"
#define MINDISKSPACE 1024 // MB
@@ -213,6 +213,58 @@ void cResumeFile::Delete(void)
}
}
+// --- cRecordingInfo --------------------------------------------------------
+
+cRecordingInfo::cRecordingInfo(const cEvent *Event)
+{
+ if (Event) {
+ event = Event;
+ ownEvent = NULL;
+ }
+ else
+ event = ownEvent = new cEvent(tChannelID(), 0);
+}
+
+cRecordingInfo::~cRecordingInfo()
+{
+ delete ownEvent;
+}
+
+bool cRecordingInfo::Read(FILE *f)
+{
+ if (ownEvent) {
+ cReadLine ReadLine;
+ char *s;
+ while ((s = ReadLine.Read(f)) != NULL) {
+ char *t = skipspace(s + 1);
+ switch (*s) {
+ case 'C': {
+ char *p = strchr(t, ' ');
+ if (p)
+ *p = 0; // strips optional channel name
+ if (*t)
+ ownEvent->SetChannelID(tChannelID::FromString(t));
+ }
+ break;
+ default: if (!ownEvent->Parse(s))
+ return false;
+ break;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool cRecordingInfo::Write(FILE *f, const char *Prefix) const
+{
+ cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true);
+ if (channel)
+ fprintf(f, "%sC %s %s\n", Prefix, *channel->GetChannelID().ToString(), channel->Name());
+ event->Dump(f, Prefix, true);
+ return true;
+}
+
// --- cRecording ------------------------------------------------------------
#define RESUME_NOT_INITIALIZED (-2)
@@ -308,7 +360,7 @@ static char *ExchangeChars(char *s, bool ToFileSystem)
return s;
}
-cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary)
+cRecording::cRecording(cTimer *Timer, const cEvent *Event)
{
resume = RESUME_NOT_INITIALIZED;
titleBuffer = NULL;
@@ -316,7 +368,8 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c
fileName = NULL;
name = NULL;
// set up the actual name:
- const char *OriginalSubtitle = Subtitle;
+ const char *Title = Event ? Event->Title() : NULL;
+ const char *Subtitle = Event ? Event->ShortText() : NULL;
char SubtitleBuffer[MAX_SUBTITLE_LENGTH];
if (isempty(Title))
Title = Timer->Channel()->Name();
@@ -347,17 +400,13 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c
start = Timer->StartTime();
priority = Timer->Priority();
lifetime = Timer->Lifetime();
- // handle summary:
- summary = !isempty(Timer->Summary()) ? strdup(Timer->Summary()) : NULL;
- if (!summary) {
- Subtitle = OriginalSubtitle;
- if (isempty(Subtitle))
- Subtitle = "";
- if (isempty(Summary))
- Summary = "";
- if (*Subtitle || *Summary)
- asprintf(&summary, "%s\n\n%s%s%s", Title, Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary);
- }
+ // handle info:
+ info = new cRecordingInfo(Event);
+ // this is a somewhat ugly hack to get the 'summary' information from the
+ // timer into the recording info, but it saves us from having to actually
+ // copy the entire event data:
+ if (!isempty(Timer->Summary()))
+ ((cEvent *)Event)->SetDescription(Timer->Summary());
}
cRecording::cRecording(const char *FileName)
@@ -370,7 +419,7 @@ cRecording::cRecording(const char *FileName)
char *p = strrchr(FileName, '/');
name = NULL;
- summary = NULL;
+ info = new cRecordingInfo;
if (p) {
time_t now = time(NULL);
struct tm tm_r;
@@ -386,39 +435,17 @@ cRecording::cRecording(const char *FileName)
name[p - FileName] = 0;
name = ExchangeChars(name, false);
}
- // 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 = MALLOC(char, size + 1); // +1 for terminating 0
- if (summary) {
- int rbytes = safe_read(f, summary, size);
- if (rbytes >= 0) {
- summary[rbytes] = 0;
- if (rbytes != size)
- esyslog("%s: expected %d bytes but read %d", SummaryFileName, size, rbytes);
- }
- else {
- LOG_ERROR_STR(SummaryFileName);
- free(summary);
- summary = NULL;
- }
-
- }
- else
- esyslog("can't allocate %d byte of memory for summary file '%s'", size + 1, SummaryFileName);
- close(f);
- }
- else
- LOG_ERROR_STR(SummaryFileName);
+ // read an optional info file:
+ char *InfoFileName = NULL;
+ asprintf(&InfoFileName, "%s%s", fileName, INFOFILESUFFIX);
+ FILE *f = fopen(InfoFileName, "r");
+ if (f) {
+ info->Read(f);
+ fclose(f);
}
else if (errno != ENOENT)
- LOG_ERROR_STR(SummaryFileName);
- free(SummaryFileName);
+ LOG_ERROR_STR(InfoFileName);
+ free(InfoFileName);
}
}
@@ -428,7 +455,7 @@ cRecording::~cRecording()
free(sortBuffer);
free(fileName);
free(name);
- free(summary);
+ delete info;
}
char *cRecording::StripEpisodeName(char *s)
@@ -568,21 +595,18 @@ bool cRecording::IsEdited(void) const
return *s == '%';
}
-bool cRecording::WriteSummary(void)
+bool cRecording::WriteInfo(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);
- free(SummaryFileName);
+ char *InfoFileName = NULL;
+ asprintf(&InfoFileName, "%s%s", fileName, INFOFILESUFFIX);
+ FILE *f = fopen(InfoFileName, "w");
+ if (f) {
+ info->Write(f);
+ fclose(f);
}
+ else
+ LOG_ERROR_STR(InfoFileName);
+ free(InfoFileName);
return true;
}
diff --git a/recording.h b/recording.h
index be1a5c44..12b07930 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.34 2005/01/16 15:11:31 kls Exp $
+ * $Id: recording.h 1.35 2005/05/16 14:18:43 kls Exp $
*/
#ifndef __RECORDING_H
@@ -12,6 +12,7 @@
#include <time.h>
#include "config.h"
+#include "epg.h"
#include "thread.h"
#include "timers.h"
#include "tools.h"
@@ -32,6 +33,21 @@ public:
void Delete(void);
};
+class cRecordingInfo {
+private:
+ const cEvent *event;
+ cEvent *ownEvent;
+public:
+ cRecordingInfo(const cEvent *Event = NULL);
+ ~cRecordingInfo();
+ const char *Title(void) const { return event->Title(); }
+ const char *ShortText(void) const { return event->ShortText(); }
+ const char *Description(void) const { return event->Description(); }
+ const cComponents *Components(void) const { return event->Components(); }
+ bool Read(FILE *f);
+ bool Write(FILE *f, const char *Prefix = "") const;
+ };
+
class cRecording : public cListObject {
private:
mutable int resume;
@@ -39,7 +55,7 @@ private:
mutable char *sortBuffer;
mutable char *fileName;
mutable char *name;
- char *summary;
+ cRecordingInfo *info;
static char *StripEpisodeName(char *s);
char *SortName(void) const;
int GetResume(void) const;
@@ -47,19 +63,19 @@ public:
time_t start;
int priority;
int lifetime;
- cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary);
+ cRecording(cTimer *Timer, const cEvent *Event);
cRecording(const char *FileName);
~cRecording();
virtual int Compare(const cListObject &ListObject) const;
const char *Name(void) const { return name; }
const char *FileName(void) const;
const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const;
- const char *Summary(void) const { return summary; }
+ const cRecordingInfo *Info(void) const { return info; }
const char *PrefixFileName(char Prefix);
int HierarchyLevels(void) const;
bool IsNew(void) const { return GetResume() <= 0; }
bool IsEdited(void) const;
- bool WriteSummary(void);
+ bool WriteInfo(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
diff --git a/skinclassic.c b/skinclassic.c
index 7eb0513b..fd3ab0b1 100644
--- a/skinclassic.c
+++ b/skinclassic.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: skinclassic.c 1.11 2005/01/09 11:56:29 kls Exp $
+ * $Id: skinclassic.c 1.12 2005/05/16 10:45:07 kls Exp $
*/
#include "skinclassic.h"
@@ -326,7 +326,33 @@ void cSkinClassicDisplayMenu::SetEvent(const cEvent *Event)
void cSkinClassicDisplayMenu::SetRecording(const cRecording *Recording)
{
- SetText(Recording->Summary(), false); //TODO
+ if (!Recording)
+ return;
+ const cRecordingInfo *Info = Recording->Info();
+ const cFont *font = cFont::GetFont(fontOsd);
+ int xl = x0 + 10;
+ int y = y2;
+ cTextScroller ts;
+ char t[32];
+ snprintf(t, sizeof(t), "%s %s", *DateString(Recording->start), *TimeString(Recording->start));
+ ts.Set(osd, xl, y, x1 - xl, y3 - y, t, font, Theme.Color(clrMenuEventTime), Theme.Color(clrBackground));
+ y += ts.Height();
+ y += font->Height();
+ const char *Title = Info->Title();
+ if (isempty(Title))
+ Title = Recording->Name();
+ ts.Set(osd, xl, y, x1 - xl, y3 - y, Title, font, Theme.Color(clrMenuEventTitle), Theme.Color(clrBackground));
+ y += ts.Height();
+ if (!isempty(Info->ShortText())) {
+ const cFont *font = cFont::GetFont(fontSml);
+ ts.Set(osd, xl, y, x1 - xl, y3 - y, Info->ShortText(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground));
+ y += ts.Height();
+ }
+ y += font->Height();
+ if (!isempty(Info->Description())) {
+ textScroller.Set(osd, xl, y, x1 - xl - 2 * ScrollWidth, y3 - y, Info->Description(), font, Theme.Color(clrMenuEventDescription), Theme.Color(clrBackground));
+ SetScrollbar();
+ }
}
void cSkinClassicDisplayMenu::SetText(const char *Text, bool FixedFont)
diff --git a/skins.h b/skins.h
index add8d56a..5fc63443 100644
--- a/skins.h
+++ b/skins.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: skins.h 1.7 2005/02/27 14:37:37 kls Exp $
+ * $Id: skins.h 1.8 2005/05/15 14:41:41 kls Exp $
*/
#ifndef __SKINS_H
@@ -150,7 +150,7 @@ public:
///< that text if necessary.
virtual void SetRecording(const cRecording *Recording) = 0;
///< Sets the Recording that shall be displayed, using the entire central area
- ///< of the menu. The Recording's 'summary' shall be displayed using a
+ ///< of the menu. The Recording's 'description' shall be displayed using a
///< cTextScroller, and the Scroll() function will be called to drive scrolling
///< that text if necessary.
virtual void SetText(const char *Text, bool FixedFont) = 0;
diff --git a/skinsttng.c b/skinsttng.c
index 3760ad4d..b9d9ccbb 100644
--- a/skinsttng.c
+++ b/skinsttng.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: skinsttng.c 1.13 2005/02/27 14:45:19 kls Exp $
+ * $Id: skinsttng.c 1.14 2005/05/16 10:44:58 kls Exp $
*/
// Star Trek: The Next Generation® is a registered trademark of Paramount Pictures
@@ -576,7 +576,39 @@ void cSkinSTTNGDisplayMenu::SetEvent(const cEvent *Event)
void cSkinSTTNGDisplayMenu::SetRecording(const cRecording *Recording)
{
- SetText(Recording->Summary(), false); //XXX
+ if (!Recording)
+ return;
+ const cRecordingInfo *Info = Recording->Info();
+ const cFont *font = cFont::GetFont(fontOsd);
+ int xl = x3 + 5;
+ int y = y3;
+ cTextScroller ts;
+ char t[32];
+ snprintf(t, sizeof(t), "%s %s", *DateString(Recording->start), *TimeString(Recording->start));
+ ts.Set(osd, xl, y, x4 - xl, y4 - y, t, font, Theme.Color(clrMenuEventTime), Theme.Color(clrBackground));
+ y += ts.Height();
+ y += font->Height();
+ const char *Title = Info->Title();
+ if (isempty(Title))
+ Title = Recording->Name();
+ ts.Set(osd, xl, y, x4 - xl, y4 - y, Title, font, Theme.Color(clrMenuEventTitle), Theme.Color(clrBackground));
+ y += ts.Height();
+ if (!isempty(Info->ShortText())) {
+ const cFont *font = cFont::GetFont(fontSml);
+ ts.Set(osd, xl, y, x4 - xl, y4 - y, Info->ShortText(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground));
+ y += ts.Height();
+ }
+ y += font->Height();
+ if (!isempty(Info->Description())) {
+ int yt = y;
+ int yb = y4 - Roundness;
+ textScroller.Set(osd, xl, yt, x4 - xl, yb - yt, Info->Description(), font, Theme.Color(clrMenuEventDescription), Theme.Color(clrBackground));
+ yb = yt + textScroller.Height();
+ osd->DrawEllipse (x1, yt - Roundness, x2, yt, frameColor, -3);
+ osd->DrawRectangle(x1, yt, x2, yb, frameColor);
+ osd->DrawEllipse (x1, yb, x2, yb + Roundness, frameColor, -2);
+ SetScrollbar();
+ }
}
void cSkinSTTNGDisplayMenu::SetText(const char *Text, bool FixedFont)
diff --git a/summary2info.pl b/summary2info.pl
new file mode 100755
index 00000000..4bf70624
--- /dev/null
+++ b/summary2info.pl
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+# Convert 'summary.vdr' files to 'info.vdr'
+#
+# Converts all 'summary.vdr' files in the video directory to the
+# 'info.vdr' format as used from VDR version 1.3.25 upward.
+#
+# Usage: summary2info.pl /video
+#
+# See the main source file 'vdr.c' for copyright information and
+# how to reach the author.
+#
+# $Id: summary2info.pl 1.1 2005/05/15 16:03:10 kls Exp $
+
+$VideoDir = $ARGV[0] || die "please provide the name of the video directory\n";
+
+@SummaryFiles = `find "$VideoDir" -name summary.vdr`;
+
+for $SummaryFile (@SummaryFiles) {
+ chomp($SummaryFile);
+ print STDERR "converting $SummaryFile...";
+ open(F, $SummaryFile) || die "$SummaryFile: $!\n";
+ $line = 0;
+ @data = ();
+ while (<F>) {
+ chomp;
+ if ($_) {
+ $data[$line] .= '|' if ($data[$line]);
+ $data[$line] .= $_;
+ }
+ else {
+ $line++ unless ($_);
+ }
+ }
+ close(F);
+ if ($line == 1) {
+ $data[2] = $data[1];
+ $data[1] = "";
+ }
+ ($InfoFile = $SummaryFile) =~ s/summary\.vdr$/info.vdr/;
+ open(F, ">$InfoFile") || die "$InfoFile: $!\n";
+ print F "T $data[0]\n" if ($data[0]);
+ print F "S $data[1]\n" if ($data[1]);
+ print F "D $data[2]\n" if ($data[2]);
+ close(F);
+ print STDERR "done.\n";
+ }
diff --git a/svdrp.c b/svdrp.c
index 5104026f..30b4adfb 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
- * $Id: svdrp.c 1.70 2005/05/06 13:47:39 kls Exp $
+ * $Id: svdrp.c 1.71 2005/05/16 14:20:25 kls Exp $
*/
#include "svdrp.h"
@@ -214,7 +214,7 @@ const char *HelpPages[] = {
" events at the given time (which must be in time_t form).",
"LSTR [ <number> ]\n"
" List recordings. Without option, all recordings are listed. Otherwise\n"
- " the summary for the given recording is listed.",
+ " the information for the given recording is listed.",
"LSTT [ <number> ]\n"
" List timers. Without option, all timers are listed. Otherwise\n"
" only the given timer is listed.",
@@ -281,7 +281,7 @@ const char *HelpPages[] = {
/* SVDRP Reply Codes:
214 Help message
- 215 EPG data record
+ 215 EPG or recording data record
220 VDR service ready
221 VDR service closing transmission channel
250 Requested VDR action okay, completed
@@ -800,13 +800,15 @@ void cSVDRP::CmdLSTR(const char *Option)
if (isnumber(Option)) {
cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1);
if (recording) {
- if (recording->Summary()) {
- char *summary = strdup(recording->Summary());
- Reply(250, "%s", strreplace(summary,'\n','|'));
- free(summary);
+ FILE *f = fdopen(file, "w");
+ if (f) {
+ recording->Info()->Write(f, "215-");
+ fflush(f);
+ Reply(215, "End of recording information");
+ // don't 'fclose(f)' here!
}
else
- Reply(550, "No summary available");
+ Reply(451, "Can't open file connection");
}
else
Reply(550, "Recording \"%s\" not found", Option);
diff --git a/tools.c b/tools.c
index 28ea2afc..075be185 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.91 2005/03/20 14:44:33 kls Exp $
+ * $Id: tools.c 1.92 2005/05/16 09:55:26 kls Exp $
*/
#include "tools.h"
@@ -571,6 +571,25 @@ cString TimeToString(time_t t)
return "???";
}
+cString DateString(time_t t)
+{
+ char buf[32];
+ struct tm tm_r;
+ tm *tm = localtime_r(&t, &tm_r);
+ char *p = stpcpy(buf, WeekDayName(tm->tm_wday));
+ *p++ = ' ';
+ strftime(p, sizeof(buf) - (p - buf), "%d.%m.%Y", tm);
+ return buf;
+}
+
+cString TimeString(time_t t)
+{
+ char buf[25];
+ struct tm tm_r;
+ strftime(buf, sizeof(buf), "%R", localtime_r(&t, &tm_r));
+ return buf;
+}
+
// --- cReadLine -------------------------------------------------------------
char *cReadLine::Read(FILE *f)
diff --git a/tools.h b/tools.h
index d9e85f3e..31a88d45 100644
--- a/tools.h
+++ b/tools.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.h 1.68 2005/03/20 14:44:24 kls Exp $
+ * $Id: tools.h 1.69 2005/05/16 09:55:19 kls Exp $
*/
#ifndef __TOOLS_H
@@ -102,6 +102,8 @@ cString WeekDayName(int WeekDay);
cString WeekDayName(time_t t);
cString DayDateTime(time_t t = 0);
cString TimeToString(time_t t);
+cString DateString(time_t t);
+cString TimeString(time_t t);
class cTimeMs {
private:
diff --git a/vdr.5 b/vdr.5
index 96136a1a..5be6da8c 100644
--- a/vdr.5
+++ b/vdr.5
@@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
-.\" $Id: vdr.5 1.36 2005/05/07 10:40:23 kls Exp $
+.\" $Id: vdr.5 1.37 2005/05/16 14:16:48 kls Exp $
.\"
.TH vdr 5 "19 Mar 2005" "1.3.23" "Video Disk Recorder Files"
.SH NAME
@@ -578,11 +578,13 @@ the current position within the recording, and to implement skipping
and fast forward/back functions.
See the definition of the \fBcIndexFile\fR class for details about the
actual contents of this file.
-.SS SUMMARY
-The file \fIsummary.vdr\fR (if present in a recording directory) contains
+.SS INFO
+The file \fIinfo.vdr\fR (if present in a recording directory) contains
a description of the recording, derived from the EPG data at recording time
(if such data was available) or the \fBSummary\fR field of the corresponding
-timer. This is a plain ASCII file and can contain arbitrary text.
+timer. This is a plain ASCII file and contains tagged lines like the \fBEPG DATA\fR
+file (see the description of the \fIepg.data\fR file). Note that the tags
+c, E, e and V will not appear in an \fIinfo.vdr\fR file.
.SS RESUME
The file \fIresume.vdr\fR (if present in a recording directory) contains
the position within the recording where the last replay session left off.