diff options
| -rw-r--r-- | HISTORY | 9 | ||||
| -rw-r--r-- | cutter.c | 4 | ||||
| -rw-r--r-- | menu.c | 61 | ||||
| -rw-r--r-- | menu.h | 4 | ||||
| -rw-r--r-- | recording.c | 132 | ||||
| -rw-r--r-- | recording.h | 15 | ||||
| -rw-r--r-- | svdrp.c | 6 | ||||
| -rw-r--r-- | tools.c | 10 | ||||
| -rw-r--r-- | tools.h | 3 | ||||
| -rw-r--r-- | vdr.1 | 6 | ||||
| -rw-r--r-- | vdr.c | 8 | 
11 files changed, 177 insertions, 81 deletions
| @@ -2893,7 +2893,7 @@ Video Disk Recorder Revision History    strings in order to avoid buffer overflows (thanks to Philip Lawatsch for    debugging a buffer overflow in eit.c). -2004-06-12: Version 1.3.11 +2004-06-13: Version 1.3.11  - In order to avoid problems on NPTL systems, VDR now checks for the presence    of NPTL at program start, and if it is, exists and tells the user to do @@ -2911,3 +2911,10 @@ Video Disk Recorder Revision History  - Fixed switching channels while an encrypted channel is being recorded, because the    channel was switched if the new channel was on the same transponder and was    a radio channel (thanks to Martin Dauskardt for reporting this one). +- The list of recordings is now kept statically in memory to avoid long delays +  when opening the "Recordings" menu. As a side effect, external modifications to +  the video directory are no longer immediately reflected in the "Recordings" menu. +  If a plugin manipulates the video directory in any way, it can call the function +  Recordings.TriggerUpdate() to trigger an update of the list of recordings. +  If some external tool manipulates the video directory, it can touch the file +  '.update' in the video directory to trigger an update of the list of recordings. @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: cutter.c 1.6 2003/10/18 11:29:37 kls Exp $ + * $Id: cutter.c 1.7 2004/06/13 16:04:08 kls Exp $   */  #include "cutter.h" @@ -205,6 +205,7 @@ bool cCutter::Start(const char *FileName)          // XXX          editedVersionName = strdup(evn);          Recording.WriteSummary(); +        Recordings.AddByName(editedVersionName);          cuttingThread = new cCuttingThread(FileName, editedVersionName);          return true;          } @@ -224,6 +225,7 @@ void cCutter::Stop(void)       if (Error)          esyslog("ERROR: '%s' during editing process", Error);       RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? +     Recordings.DelByName(editedVersionName);       }  } @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: menu.c 1.308 2004/06/06 09:47:44 kls Exp $ + * $Id: menu.c 1.309 2004/06/13 20:26:51 kls Exp $   */  #include "menu.h" @@ -1410,7 +1410,6 @@ void cMenuRecordingItem::IncrementCounter(bool New)  // --- cMenuRecordings ------------------------------------------------------- -cRecordings cMenuRecordings::Recordings;  int cMenuRecordings::helpKeys = -1;  cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus) @@ -1419,40 +1418,35 @@ cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus)    base = Base ? strdup(Base) : NULL;    level = Setup.RecordingDirs ? Level : -1;    Display(); // this keeps the higher level menus from showing up briefly when pressing 'Back' during replay +  const char *LastReplayed = cReplayControl::LastReplayed(); +  cMenuRecordingItem *LastItem = NULL; +  char *LastItemText = NULL;    if (!Base) -     Skins.Message(mtStatus, tr("scanning recordings...")); -  bool Loaded = Base || Recordings.Load(); -  if (!Base) -     Skins.Message(mtStatus, NULL); -  if (Loaded) { -     const char *LastReplayed = cReplayControl::LastReplayed(); -     cMenuRecordingItem *LastItem = NULL; -     char *LastItemText = NULL; -     for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { -         if (!Base || (strstr(recording->Name(), Base) == recording->Name() && recording->Name()[strlen(Base)] == '~')) { -            cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); -            if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { -               Add(Item); -               LastItem = Item; -               free(LastItemText); -               LastItemText = strdup(LastItem->Text()); // must use a copy because of the counters! -               } -            else -               delete Item; -            if (LastItem) { -               if (LastReplayed && strcmp(LastReplayed, recording->FileName()) == 0) -                  SetCurrent(LastItem); -               if (LastItem->IsDirectory()) -                  LastItem->IncrementCounter(recording->IsNew()); -               } +     Recordings.Sort(); +  for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { +      if (!Base || (strstr(recording->Name(), Base) == recording->Name() && recording->Name()[strlen(Base)] == '~')) { +         cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); +         if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { +            Add(Item); +            LastItem = Item; +            free(LastItemText); +            LastItemText = strdup(LastItem->Text()); // must use a copy because of the counters! +            } +         else +            delete Item; +         if (LastItem) { +            if (LastReplayed && strcmp(LastReplayed, recording->FileName()) == 0) +               SetCurrent(LastItem); +            if (LastItem->IsDirectory()) +               LastItem->IncrementCounter(recording->IsNew());              }           } -     free(LastItemText); -     if (Current() < 0) -        SetCurrent(First()); -     else if (OpenSubMenus && Open(true)) -        return; -     } +      } +  free(LastItemText); +  if (Current() < 0) +     SetCurrent(First()); +  else if (OpenSubMenus && Open(true)) +     return;    SetHelpKeys();  } @@ -2780,6 +2774,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)          cStatus::MsgRecording(device, Recording.Name());          if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()             cReplayControl::SetRecording(fileName, Recording.Name()); +        Recordings.AddByName(fileName);          }       else          DELETENULL(recorder); @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: menu.h 1.63 2004/05/23 09:47:26 kls Exp $ + * $Id: menu.h 1.64 2004/06/13 11:46:03 kls Exp $   */  #ifndef __MENU_H @@ -16,7 +16,6 @@  #include "osdbase.h"  #include "dvbplayer.h"  #include "recorder.h" -#include "recording.h"  #include "skins.h"  class cMenuText : public cOsdMenu { @@ -107,7 +106,6 @@ class cMenuRecordingItem;  class cMenuRecordings : public cOsdMenu {  private: -  static cRecordings Recordings;    char *base;    int level;    static int helpKeys; diff --git a/recording.c b/recording.c index 05efc440..cbc916a2 100644 --- a/recording.c +++ b/recording.c @@ -4,10 +4,11 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: recording.c 1.87 2004/05/07 14:24:18 kls Exp $ + * $Id: recording.c 1.88 2004/06/13 20:25:19 kls Exp $   */  #include "recording.h" +#include <dirent.h>  #include <errno.h>  #include <fcntl.h>  #include <stdio.h> @@ -25,7 +26,7 @@  #define RECEXT       ".rec"  #define DELEXT       ".del"  /* This was the original code, which works fine in a Linux only environment. -   Unfortunately, because of windows and its brain dead file system, we have +   Unfortunately, because of Windows and its brain dead file system, we have     to use a more complicated approach, in order to allow users who have enabled     the VFAT compile time option to see their recordings even if they forget to     enable VFAT when compiling a new version of VDR... Gee, do I hate Windows. @@ -47,8 +48,6 @@  #define SUMMARYFILESUFFIX "/summary.vdr"  #define MARKSFILESUFFIX   "/marks.vdr" -#define FINDCMD      "cd '%s' && find '%s' -follow -type d -name '%s' 2> /dev/null" -  #define MINDISKSPACE 1024 // MB  #define DELETEDLIFETIME     1 // hours after which a deleted recording will be actually removed @@ -70,14 +69,14 @@ void RemoveDeletedRecordings(void)       if (!LockFile.Lock())          return;       // Remove the oldest file that has been "deleted": -     cRecordings Recordings; -     if (Recordings.Load(true)) { -        cRecording *r = Recordings.First(); +     cRecordings DeletedRecordings(true); +     if (DeletedRecordings.Load()) { +        cRecording *r = DeletedRecordings.First();          cRecording *r0 = r;          while (r) {                if (r->start < r0->start)                   r0 = r; -              r = Recordings.Next(r); +              r = DeletedRecordings.Next(r);                }          if (r0 && time(NULL) - r0->start > DELETEDLIFETIME * 3600) {             r0->Remove(); @@ -105,14 +104,14 @@ void AssertFreeDiskSpace(int Priority)             return;          // Remove the oldest file that has been "deleted":          isyslog("low disk space while recording, trying to remove a deleted recording..."); -        cRecordings Recordings; -        if (Recordings.Load(true)) { -           cRecording *r = Recordings.First(); +        cRecordings DeletedRecordings(true); +        if (DeletedRecordings.Load()) { +           cRecording *r = DeletedRecordings.First();             cRecording *r0 = r;             while (r) {                   if (r->start < r0->start)                      r0 = r; -                 r = Recordings.Next(r); +                 r = DeletedRecordings.Next(r);                   }             if (r0 && r0->Remove()) {                LastFreeDiskCheck += REMOVELATENCY / Factor; @@ -121,7 +120,7 @@ void AssertFreeDiskSpace(int Priority)             }          // No "deleted" files to remove, so let's see if we can delete a recording:          isyslog("...no deleted recording found, trying to delete an old recording..."); -        if (Recordings.Load(false)) { +        if (Recordings.Load()) {             cRecording *r = Recordings.First();             cRecording *r0 = NULL;             while (r) { @@ -138,8 +137,10 @@ void AssertFreeDiskSpace(int Priority)                      }                   r = Recordings.Next(r);                   } -           if (r0 && r0->Delete()) +           if (r0 && r0->Delete()) { +              Recordings.Del(r0);                return; +              }             }          // Unable to free disk space, but there's nothing we can do about that...          isyslog("...no old recording found, giving up"); @@ -617,30 +618,75 @@ bool cRecording::Remove(void)  // --- cRecordings ----------------------------------------------------------- -bool cRecordings::Load(bool Deleted) +cRecordings Recordings; + +cRecordings::cRecordings(bool Deleted)  { -  Clear(); -  bool result = false; -  char *cmd = NULL; -  asprintf(&cmd, FINDCMD, VideoDirectory, VideoDirectory, Deleted ? "*" DELEXT : "*" RECEXT); -  FILE *p = popen(cmd, "r"); -  if (p) { -     char *s; -     while ((s = readline(p)) != NULL) { -           cRecording *r = new cRecording(s); -           if (r->Name()) -              Add(r); -           else -              delete r; +  deleted = Deleted; +  lastUpdate = 0; +} + +bool cRecordings::ScanVideoDir(const char *DirName) +{ +  DIR *d = opendir(DirName); +  if (d) { +     struct dirent *e; +     while ((e = readdir(d)) != NULL) { +           if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) { +              char *buffer; +              asprintf(&buffer, "%s/%s", DirName, e->d_name); +              struct stat st; +              if (stat(buffer, &st) == 0) { +                 if (S_ISLNK(st.st_mode)) { +                    free(buffer); +                    buffer = ReadLink(buffer); +                    if (!buffer) +                       return false; +                    if (stat(buffer, &st) != 0) { +                       LOG_ERROR_STR(DirName); +                       return false; +                       } +                    } +                 if (S_ISDIR(st.st_mode)) { +                    if (endswith(buffer, deleted ? DELEXT : RECEXT)) { +                       cRecording *r = new cRecording(buffer); +                       if (r->Name()) +                          Add(r); +                       else +                          delete r; +                       } +                    else if (!ScanVideoDir(buffer)) +                       return false; +                    } +                 } +              else { +                 LOG_ERROR_STR(DirName); +                 return false; +                 } +              free(buffer); +              }             } -     pclose(p); -     Sort(); -     result = Count() > 0; +     closedir(d);       } -  else -     Skins.Message(mtError, "Error while opening pipe!"); -  free(cmd); -  return result; +  else { +     LOG_ERROR_STR(DirName); +     return false; +     } +  return true; +} + +bool cRecordings::NeedsUpdate(void) +{ +  return lastUpdate <= LastModifiedTime(AddDirectory(VideoDirectory, ".update")); +} + +bool cRecordings::Load(void) +{ +  lastUpdate = time(NULL); // doing this first to make sure we don't miss anything +  Clear(); +  ScanVideoDir(VideoDirectory); +  Sort(); +  return Count() > 0;  }  cRecording *cRecordings::GetByName(const char *FileName) @@ -652,6 +698,22 @@ cRecording *cRecordings::GetByName(const char *FileName)    return NULL;  } +void cRecordings::AddByName(const char *FileName) +{ +  cRecording *recording = GetByName(FileName); +  if (!recording) { +     recording = new cRecording(FileName); +     Add(recording); +     } +} + +void cRecordings::DelByName(const char *FileName) +{ +  cRecording *recording = GetByName(FileName); +  if (recording) +     Del(recording); +} +  // --- cMark -----------------------------------------------------------------  char *cMark::buffer = NULL; diff --git a/recording.h b/recording.h index 01a25ab4..04a1885b 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.29 2004/05/07 14:24:22 kls Exp $ + * $Id: recording.h 1.30 2004/06/13 15:37:42 kls Exp $   */  #ifndef __RECORDING_H @@ -69,11 +69,22 @@ public:    };  class cRecordings : public cList<cRecording> { +private: +  bool deleted; +  time_t lastUpdate; +  bool ScanVideoDir(const char *DirName);  public: -  bool Load(bool Deleted = false); +  cRecordings(bool Deleted = false); +  bool Load(void); +  void TriggerUpdate(void) { lastUpdate = 0; } +  bool NeedsUpdate(void);    cRecording *GetByName(const char *FileName); +  void AddByName(const char *FileName); +  void DelByName(const char *FileName);    }; +extern cRecordings Recordings; +  class cMark : public cListObject {  private:    static char *buffer; @@ -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.62 2004/03/25 17:00:23 kls Exp $ + * $Id: svdrp.c 1.63 2004/06/13 13:38:38 kls Exp $   */  #include "svdrp.h" @@ -504,8 +504,10 @@ void cSVDRP::CmdDELR(const char *Option)       if (isnumber(Option)) {          cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1);          if (recording) { -           if (recording->Delete()) +           if (recording->Delete()) {                Reply(250, "Recording \"%s\" deleted", Option); +              ::Recordings.Load(); // must make sure the global recordings list is updated +              }             else                Reply(554, "Error while deleting recording!");             } @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: tools.c 1.79 2004/05/22 12:13:27 kls Exp $ + * $Id: tools.c 1.80 2004/06/13 14:36:41 kls Exp $   */  #include "tools.h" @@ -481,6 +481,14 @@ bool SpinUpDisk(const char *FileName)    return false;  } +time_t LastModifiedTime(const char *FileName) +{ +  struct stat fs; +  if (stat(FileName, &fs) == 0) +     return fs.st_mtime; +  return 0; +} +  const char *WeekDayName(int WeekDay)  {    static char buffer[4]; @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: tools.h 1.56 2004/05/22 12:11:44 kls Exp $ + * $Id: tools.h 1.57 2004/06/13 14:13:26 kls Exp $   */  #ifndef __TOOLS_H @@ -83,6 +83,7 @@ bool RemoveFileOrDir(const char *FileName, bool FollowSymlinks = false);  bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis = false);  char *ReadLink(const char *FileName);  bool SpinUpDisk(const char *FileName); +time_t LastModifiedTime(const char *FileName);  const char *WeekDayName(int WeekDay); ///< \warning returns a statically allocated string!  const char *WeekDayName(time_t t); ///< \warning returns a statically allocated string!  const char *DayDateTime(time_t t = 0); ///< \warning returns a statically allocated string! @@ -8,7 +8,7 @@  .\" License as specified in the file COPYING that comes with the  .\" vdr distribution.  .\" -.\" $Id: vdr.1 1.10 2004/05/16 12:10:52 kls Exp $ +.\" $Id: vdr.1 1.11 2004/06/13 14:48:03 kls Exp $  .\"  .TH vdr 1 "1 June 2003" "1.2.0" "Video Disk Recorder"  .SH NAME @@ -176,6 +176,10 @@ The actual data files of a recording.  .I epg.data  Contains all current EPG data. Can be used for external processing and will  also be read at program startup to have the full EPG data available immediately. +.TP +.I .update +If this file is present in the video directory, its last modification time will +be used to trigger an update of the list of recordings in the "Recordings" menu.  .SH SEE ALSO  .BR vdr (5)  .SH AUTHOR @@ -22,7 +22,7 @@   *   * The project's page is at http://www.cadsoft.de/vdr   * - * $Id: vdr.c 1.183 2004/06/12 10:07:17 kls Exp $ + * $Id: vdr.c 1.184 2004/06/13 13:52:09 kls Exp $   */  #include <getopt.h> @@ -475,6 +475,10 @@ int main(int argc, char *argv[])    else       cDevice::PrimaryDevice()->SetVolume(Setup.CurrentVolume, true); +  // Recordings: + +  Recordings.Load(); +    // Signal handlers:    if (signal(SIGHUP,  SignalHandler) == SIG_IGN) signal(SIGHUP,  SIG_IGN); @@ -606,6 +610,8 @@ int main(int argc, char *argv[])                    TimerInVpsMargin = true;                 }             } +        if (!Menu && Recordings.NeedsUpdate()) +           Recordings.Load();          // CAM control:          if (!Menu && !cOsd::IsOpen())             Menu = CamControl(); | 
