diff --git a/FORMATS b/FORMATS index 7cc4333d..46fd543e 100644 --- a/FORMATS +++ b/FORMATS @@ -72,6 +72,11 @@ Video Disk Recorder File Formats any ':' characters, these have to be replaced with '|'. If the name shall contain subdirectories, these have to be delimited by '~' (since the '/' character may be part of a regular programme name). + The special keywords TITLE and EPISODE, if present, will be replaced + with the title and episode information from the EPG data at the time of + recording (if that data is available). If at the time of recording either + of these cannot be determined, TITLE will default to the channel name, and + EPISODE will default to a blank. - Summary (any newline characters in the summary have to be replaced with '|'; the summary may contain ':' characters) diff --git a/HISTORY b/HISTORY index 75966ef0..87a2eb80 100644 --- a/HISTORY +++ b/HISTORY @@ -931,7 +931,7 @@ Video Disk Recorder Revision History - Fixed handling improperly formatted EIT data (thanks to Rolf Hakenes). -2002-02-02: Version 0.99pre5 +2002-02-03: Version 0.99pre5 - Updated channel settings for 'N24' (thanks to Andreas Gebel). - Fixed handling hierarchical recordings menu in case of directories starting @@ -953,3 +953,12 @@ Video Disk Recorder Revision History - The new configuration file 'svdrphosts.conf' is now used to define which hosts may access the SVDRP port (by default only 'localhost' has access). See FORMATS for details. +- The special keywords TITLE and EPISODE can now be used in timer file names + (see MANUAL and FORMATS for details). +- The new setup parameter NameInstantRecord can be used to define how an + instant recording will be named (see MANUAL for details). +- When looking for the EPG record of the timer that starts a recording, now + that record is taken which covers the time calculated as + 'start + (Setup.MarginStart * 2) + 1)' in order to have a better chance of + hitting the right record in case of an instant recording. Timers that start + further in the future should always be programmed via the "Schedules" menu. diff --git a/MANUAL b/MANUAL index a564786d..d0ce7a2c 100644 --- a/MANUAL +++ b/MANUAL @@ -385,6 +385,14 @@ Video Disk Recorder User's Manual 0 = instant recordings will not be marked 1 = instant recordings will be marked. + NameInstantRecord = TITLE-EPISODE + Defines how to name an instant recording. If the keywords + TITLE and/or EPISODE are present, they will be replaced + with the title and episode information from the EPG data + at the time of recording (if that data is available). + If this parameter is empty, the channel name will be used + by default. + LnbSLOF = 11700 The switching frequency (in MHz) between low and high LOF LnbFrequLo = 9750 The LNB's low and high local oscillator frequencies (in MHz) LnbFrequHi = 10600 (these have no meaning for DVB-C receivers) diff --git a/config.c b/config.c index 9a2ab7a0..974aed0c 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.81 2002/02/02 17:15:03 kls Exp $ + * $Id: config.c 1.82 2002/02/03 15:25:44 kls Exp $ */ #include "config.h" @@ -340,7 +340,7 @@ cTimer::cTimer(bool Instant) *file = 0; summary = NULL; if (Instant && ch) - snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", ch->name); + snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : ch->name); } cTimer::cTimer(const cEventInfo *EventInfo) @@ -539,6 +539,13 @@ time_t cTimer::SetTime(time_t t, int SecondsFromMidnight) return mktime(&tm); } +char *cTimer::SetFile(const char *File) +{ + if (!isempty(File)) + strn0cpy(file, File, sizeof(file)); + return file; +} + bool cTimer::Matches(time_t t) { startTime = stopTime = 0; @@ -840,6 +847,7 @@ cSetup::cSetup(void) ShowInfoOnChSwitch = 1; MenuScrollPage = 1; MarkInstantRecord = 1; + strcpy(NameInstantRecord, "TITLE-EPISODE"); LnbSLOF = 11700; LnbFrequLo = 9750; LnbFrequHi = 10600; @@ -873,47 +881,51 @@ cSetup::cSetup(void) bool cSetup::Parse(char *s) { - const char *Delimiters = " \t\n="; - char *Name = strtok(s, Delimiters); - char *Value = strtok(NULL, Delimiters); - if (Name && Value) { - if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value); - else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); - else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); - else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); - else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); - else if (!strcasecmp(Name, "LnbSLOF")) LnbSLOF = atoi(Value); - else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); - else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); - else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value); - else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); - else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); - else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); - else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); - else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); - else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); - else if (!strcasecmp(Name, "SortTimers")) SortTimers = atoi(Value); - else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); - else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); - else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); - else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); - else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); - else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); - else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); - else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); - else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); - else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); - else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); - else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); - else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); - else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); - else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); - else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); - else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); - else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); - else - return false; - return true; + char *p = strchr(s, '='); + if (p) { + *p = 0; + char *Name = compactspace(s); + char *Value = compactspace(p + 1); + if (*Name && *Value) { + if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value); + else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); + else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); + else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value); + else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value); + else if (!strcasecmp(Name, "NameInstantRecord")) strn0cpy(NameInstantRecord, Value, MaxFileName); + else if (!strcasecmp(Name, "LnbSLOF")) LnbSLOF = atoi(Value); + else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value); + else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value); + else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value); + else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value); + else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value); + else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value); + else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value); + else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value); + else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value); + else if (!strcasecmp(Name, "SortTimers")) SortTimers = atoi(Value); + else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value); + else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value); + else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value); + else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); + else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); + else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); + else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); + else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value); + else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value); + else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value); + else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); + else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); + else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); + else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); + else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); + else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); + else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); + else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); + else + return false; + return true; + } } return false; } @@ -930,6 +942,7 @@ bool cSetup::Load(const char *FileName) bool result = true; while (fgets(buffer, sizeof(buffer), f) > 0) { line++; + stripspace(buffer); if (!isempty(buffer)) { if (*buffer != '#' && !Parse(buffer)) { esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line); @@ -959,6 +972,7 @@ bool cSetup::Save(const char *FileName) fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch); fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage); fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord); + fprintf(f, "NameInstantRecord = %s\n", NameInstantRecord); fprintf(f, "LnbSLOF = %d\n", LnbSLOF); fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo); fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi); diff --git a/config.h b/config.h index 06cd583d..325f4ef2 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.92 2002/02/02 15:59:18 kls Exp $ + * $Id: config.h 1.93 2002/02/03 15:16:21 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "eit.h" #include "tools.h" -#define VDRVERSION "0.99pre4" +#define VDRVERSION "0.99pre5" #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -66,6 +66,8 @@ enum eKeys { // "Up" and "Down" must be the first two keys! #define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) #define NORMALKEY(k) (eKeys((k) & ~k_Repeat)) +#define MaxFileName 256 + struct tKey { eKeys type; char *name; @@ -123,7 +125,6 @@ private: static char *buffer; static const char *ToText(cTimer *Timer); public: - enum { MaxFileName = 256 }; bool recording, pending; int active; int channel; @@ -149,6 +150,7 @@ public: bool DayMatches(time_t t); time_t IncDay(time_t t, int Days); time_t SetTime(time_t t, int SecondsFromMidnight); + char *SetFile(const char *File); bool Matches(time_t t = 0); time_t StartTime(void); time_t StopTime(void); @@ -301,6 +303,7 @@ public: int ShowInfoOnChSwitch; int MenuScrollPage; int MarkInstantRecord; + char NameInstantRecord[MaxFileName]; int LnbSLOF; int LnbFrequLo; int LnbFrequHi; diff --git a/i18n.c b/i18n.c index 7977fcd4..3d9089ae 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.50 2002/01/27 15:52:32 kls Exp $ + * $Id: i18n.c 1.51 2002/02/03 14:34:33 kls Exp $ * * Slovenian translations provided by Miha Setina * Italian translations provided by Alberto Carraro @@ -776,6 +776,15 @@ const tPhrase Phrases[] = { "Enregistrement immédiat", "Markere direkteopptak", }, + { "NameInstantRecord", + "Direktaufz. benennen", + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + "", // TODO + }, { "LnbSLOF", "LnbSLOF", "LnbSLOF", diff --git a/menu.c b/menu.c index abc8d45f..40ac1859 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.147 2002/02/01 15:08:44 kls Exp $ + * $Id: menu.c 1.148 2002/02/03 15:42:38 kls Exp $ */ #include "menu.h" @@ -1829,6 +1829,7 @@ void cMenuSetup::Set(void) Add(new cMenuEditBoolItem(tr("ShowInfoOnChSwitch"), &data.ShowInfoOnChSwitch)); Add(new cMenuEditBoolItem(tr("MenuScrollPage"), &data.MenuScrollPage)); Add(new cMenuEditBoolItem(tr("MarkInstantRecord"), &data.MarkInstantRecord)); + Add(new cMenuEditStrItem( tr("NameInstantRecord"), data.NameInstantRecord, sizeof(data.NameInstantRecord), FileNameChars)); Add(new cMenuEditIntItem( tr("LnbSLOF"), &data.LnbSLOF)); Add(new cMenuEditIntItem( tr("LnbFrequLo"), &data.LnbFrequLo)); Add(new cMenuEditIntItem( tr("LnbFrequHi"), &data.LnbFrequHi)); @@ -2309,14 +2310,16 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) timer->SetPending(true); timer->SetRecording(true); if (Channels.SwitchTo(timer->channel, dvbApi)) { + const char *Title = NULL; const char *Subtitle = NULL; const char *Summary = NULL; if (GetEventInfo()) { - dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", eventInfo->GetTitle(), eventInfo->GetSubtitle()); + Title = eventInfo->GetTitle(); Subtitle = eventInfo->GetSubtitle(); Summary = eventInfo->GetExtendedDescription(); + dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", Title, Subtitle); } - cRecording Recording(timer, Subtitle, Summary); + cRecording Recording(timer, Title, Subtitle, Summary); fileName = strdup(Recording.FileName()); cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); if (dvbApi->StartRecord(fileName, Channels.GetByNumber(timer->channel)->ca, timer->priority)) @@ -2337,7 +2340,7 @@ cRecordControl::~cRecordControl() bool cRecordControl::GetEventInfo(void) { cChannel *channel = Channels.GetByNumber(timer->channel); - time_t Time = timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2; + time_t Time = timer->StartTime() + ((Setup.MarginStart * 2) + 1) * 60; for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) { { cThreadLock ThreadLock; diff --git a/recording.c b/recording.c index acdf264c..7a55e1a7 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.48 2002/01/27 15:14:45 kls Exp $ + * $Id: recording.c 1.49 2002/02/03 15:46:42 kls Exp $ */ #include "recording.h" @@ -41,6 +41,9 @@ #define DISKCHECKDELTA 100 // seconds between checks for free disk space #define REMOVELATENCY 10 // seconds to wait until next check after removing a file +#define TIMERMACRO_TITLE "TITLE" +#define TIMERMACRO_EPISODE "EPISODE" + void RemoveDeletedRecordings(void) { static time_t LastRemoveCheck = 0; @@ -214,19 +217,33 @@ char *ExchangeChars(char *s, bool ToFileSystem) return s; } -cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary) +cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary) { resume = RESUME_NOT_INITIALIZED; titleBuffer = NULL; sortBuffer = NULL; fileName = NULL; - if (Timer->IsSingleEvent() || !Setup.UseSubtitle) + name = NULL; + // set up the actual name: + if (isempty(Title)) + Title = Channels.GetChannelNameByNumber(Timer->channel); + if (isempty(Subtitle)) + Subtitle = " "; + char *macroTITLE = strstr(Timer->file, TIMERMACRO_TITLE); + char *macroEPISODE = strstr(Timer->file, TIMERMACRO_EPISODE); + if (macroTITLE || macroEPISODE) { name = strdup(Timer->file); - else { - if (isempty(Subtitle)) - Subtitle = " "; - asprintf(&name, "%s~%s", Timer->file, Subtitle); + name = strreplace(name, TIMERMACRO_TITLE, Title); + name = strreplace(name, TIMERMACRO_EPISODE, Subtitle); + if (Timer->IsSingleEvent()) { + Timer->SetFile(name); // this was an instant recording, so let's set the actual data + Timers.Save(); + } } + else if (Timer->IsSingleEvent() || !Setup.UseSubtitle) + name = strdup(Timer->file); + else + asprintf(&name, "%s~%s", Timer->file, Subtitle); // substitute characters that would cause problems in file names: strreplace(name, '\n', ' '); start = Timer->StartTime(); diff --git a/recording.h b/recording.h index 478ad0b7..38626f85 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.21 2002/01/26 15:28:41 kls Exp $ + * $Id: recording.h 1.22 2002/02/03 11:59:49 kls Exp $ */ #ifndef __RECORDING_H @@ -43,7 +43,7 @@ public: time_t start; int priority; int lifetime; - cRecording(cTimer *Timer, const char *Subtitle, const char *Summary); + cRecording(cTimer *Timer, const char *Title, const char *Subtitle, const char *Summary); cRecording(const char *FileName); ~cRecording(); virtual bool operator< (const cListObject &ListObject); diff --git a/tools.c b/tools.c index 0aedad8d..f55935bd 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.54 2002/02/02 13:03:40 kls Exp $ + * $Id: tools.c 1.55 2002/02/03 13:35:38 kls Exp $ */ #include "tools.h" @@ -100,6 +100,23 @@ char *strreplace(char *s, char c1, char c2) return s; } +char *strreplace(char *s, const char *s1, const char *s2) +{ + char *p = strstr(s, s1); + if (p) { + int of = p - s; + int l = strlen(s); + int l1 = strlen(s1); + int l2 = strlen(s2); + if (l2 > l1) + s = (char *)realloc(s, strlen(s) + l2 - l1 + 1); + if (l2 != l1) + memmove(s + of + l2, s + of + l1, l - of - l1 + 1); + strncpy(s + of, s2, l2); + } + return s; +} + char *skipspace(const char *s) { while (*s && isspace(*s)) diff --git a/tools.h b/tools.h index 4a1132ef..9663a8ed 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.40 2002/02/02 13:16:47 kls Exp $ + * $Id: tools.h 1.41 2002/02/03 12:36:25 kls Exp $ */ #ifndef __TOOLS_H @@ -47,6 +47,7 @@ char *readline(FILE *f); char *strcpyrealloc(char *dest, const char *src); char *strn0cpy(char *dest, const char *src, size_t n); char *strreplace(char *s, char c1, char c2); +char *strreplace(char *s, const char *s1, const char *s2); // re-allocates 's' and deletes the original string if necessary! char *skipspace(const char *s); char *stripspace(char *s); char *compactspace(char *s);