summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY9
-rw-r--r--cutter.c4
-rw-r--r--menu.c61
-rw-r--r--menu.h4
-rw-r--r--recording.c132
-rw-r--r--recording.h15
-rw-r--r--svdrp.c6
-rw-r--r--tools.c10
-rw-r--r--tools.h3
-rw-r--r--vdr.16
-rw-r--r--vdr.c8
11 files changed, 177 insertions, 81 deletions
diff --git a/HISTORY b/HISTORY
index 45b726dc..770a28f8 100644
--- a/HISTORY
+++ b/HISTORY
@@ -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.
diff --git a/cutter.c b/cutter.c
index 25169a2a..c8ed60ec 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.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);
}
}
diff --git a/menu.c b/menu.c
index 3fd39b15..95d72536 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.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);
diff --git a/menu.h b/menu.h
index 150f88de..5990a2ea 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.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;
diff --git a/svdrp.c b/svdrp.c
index 63126f51..87f146e5 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.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!");
}
diff --git a/tools.c b/tools.c
index 42193b2f..0f42182e 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.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];
diff --git a/tools.h b/tools.h
index 2132d001..071e35e0 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.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!
diff --git a/vdr.1 b/vdr.1
index b519f9d9..106b1d3f 100644
--- a/vdr.1
+++ b/vdr.1
@@ -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
diff --git a/vdr.c b/vdr.c
index 23f24957..fc1f9e09 100644
--- a/vdr.c
+++ b/vdr.c
@@ -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();