mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
The list of recordings is now kept statically in memory
This commit is contained in:
parent
1369239b53
commit
5ed57fa1c5
9
HISTORY
9
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.
|
||||
|
4
cutter.c
4
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
61
menu.c
61
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);
|
||||
|
4
menu.h
4
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;
|
||||
|
132
recording.c
132
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;
|
||||
|
15
recording.h
15
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;
|
||||
|
6
svdrp.c
6
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!");
|
||||
}
|
||||
|
10
tools.c
10
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];
|
||||
|
3
tools.h
3
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!
|
||||
|
6
vdr.1
6
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
|
||||
|
8
vdr.c
8
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();
|
||||
|
Loading…
Reference in New Issue
Block a user