summaryrefslogtreecommitdiff
path: root/recording.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2005-09-25 18:00:00 +0200
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2005-09-25 18:00:00 +0200
commitc16bbf7422f37108580e559ca849e5aafbdac672 (patch)
tree8ee8d17a971364a9231a83abf5bcff4e30bed9b3 /recording.c
parentd5c85f5ff84ffea666c63eca5dbe04632283cb04 (diff)
downloadvdr-patch-lnbsharing-c16bbf7422f37108580e559ca849e5aafbdac672.tar.gz
vdr-patch-lnbsharing-c16bbf7422f37108580e559ca849e5aafbdac672.tar.bz2
Version 1.3.33vdr-1.3.33
- Fixed two errors in 'newplugin' (thanks to Alexander Rieger). - Fixed converting arbitrarily formatted summary.vdr files (thanks to Thomas Günther). - Fixed handling color buttons in cMenuEditStrItem (thanks to Alexander Rieger). - Added cChannel::LinkChannels() and cChannel::RefChannel() (suggested by Helmut Auer). Note that VDR itself doesn't actually use the linked channels, yet, so there is no guarantee that this really works under all circumstances. - Added a missing include statement to the 'sky' plugin (thanks to Alfred Zastrow for reporting this one). - Fixed handling key macros with keys after @plugin (thanks to Rolf Ahrenberg for reporting this one). - Fixed error handling in cCiTransportConnection::RecvTPDU() (thanks to Georg Acher for reporting this one). - Removed obsolete 'shift' code in device.[hc]. - The SVDRP command DELR no longer triggers a complete reload of the global Recordings list, but rather deletes that particular entry. - The list of recordings is now read in a separate thread, resulting in a faster startup if there are a great many of recordings, or the disk(s) have to spin up. If the Recordings menu is opened while the list of recordings is still being read, the menu will be updated accordingly. Plugins that access the global Recordings variable should lock the thread by putting something like cThreadLock RecordingsLock(&Recordings); into the respective code block. Thanks to Carsten Koch for his help in testing and debugging this. - The 'new' indicator in the Recordings menu is now kept up-to-date (thanks to Thomas Günther). - Updated the Romanian OSD texts (thanks to Lucian Muresan). - Updated the Russian OSD texts (thanks to Oleg Roitburd). - The '.update' file in the video directory is now touched when a recording is added or deleted, so that other VDR instances can update their lists (thanks to Alexander Rieger). - Made the function ExchangeChars() public (suggested by Lucian Muresan).
Diffstat (limited to 'recording.c')
-rw-r--r--recording.c129
1 files changed, 107 insertions, 22 deletions
diff --git a/recording.c b/recording.c
index 3640a8e..8b21cdd 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.113 2005/09/10 12:36:48 kls Exp $
+ * $Id: recording.c 1.119 2005/09/25 14:29:49 kls Exp $
*/
#include "recording.h"
@@ -60,17 +60,23 @@
bool VfatFileSystem = false;
+static cRecordings DeletedRecordings(true);
+
void RemoveDeletedRecordings(void)
{
static time_t LastRemoveCheck = 0;
- if (time(NULL) - LastRemoveCheck > REMOVECHECKDELTA) {
+ if (LastRemoveCheck == 0) {
+ DeletedRecordings.Update();
+ LastRemoveCheck = time(NULL) - REMOVECHECKDELTA * 9 / 10;
+ }
+ else if (time(NULL) - LastRemoveCheck > REMOVECHECKDELTA) {
// Make sure only one instance of VDR does this:
cLockFile LockFile(VideoDirectory);
if (!LockFile.Lock())
return;
// Remove the oldest file that has been "deleted":
- cRecordings DeletedRecordings(true);
- if (DeletedRecordings.Load()) {
+ cThreadLock DeletedRecordingsLock(&DeletedRecordings);
+ if (DeletedRecordings.Count()) {
cRecording *r = DeletedRecordings.First();
cRecording *r0 = r;
while (r) {
@@ -80,11 +86,14 @@ void RemoveDeletedRecordings(void)
}
if (r0 && time(NULL) - r0->start > DELETEDLIFETIME * 3600) {
r0->Remove();
+ DeletedRecordings.Del(r0);
RemoveEmptyVideoDirectories();
LastRemoveCheck += REMOVELATENCY;
return;
}
}
+ else
+ DeletedRecordings.Update();
LastRemoveCheck = time(NULL);
}
}
@@ -104,8 +113,8 @@ 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 DeletedRecordings(true);
- if (DeletedRecordings.Load()) {
+ cThreadLock DeletedRecordingsLock(&DeletedRecordings);
+ if (DeletedRecordings.Count()) {
cRecording *r = DeletedRecordings.First();
cRecording *r0 = r;
while (r) {
@@ -114,13 +123,20 @@ void AssertFreeDiskSpace(int Priority)
r = DeletedRecordings.Next(r);
}
if (r0 && r0->Remove()) {
+ DeletedRecordings.Del(r0);
LastFreeDiskCheck += REMOVELATENCY / Factor;
return;
}
}
+ // DeletedRecordings was empty, so to be absolutely sure there are no
+ // deleted recordings we need to double check:
+ DeletedRecordings.Update(true);
+ if (DeletedRecordings.Count())
+ return; // the next call will actually remove it
// 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()) {
+ cThreadLock RecordingsLock(&Recordings);
+ if (Recordings.Count()) {
cRecording *r = Recordings.First();
cRecording *r0 = NULL;
while (r) {
@@ -199,6 +215,7 @@ bool cResumeFile::Save(int Index)
if (safe_write(f, &Index, sizeof(Index)) < 0)
LOG_ERROR_STR(fileName);
close(f);
+ Recordings.ResetResume(fileName);
return true;
}
}
@@ -210,6 +227,7 @@ void cResumeFile::Delete(void)
if (fileName) {
if (remove(fileName) < 0 && errno != ENOENT)
LOG_ERROR_STR(fileName);
+ Recordings.ResetResume(fileName);
}
}
@@ -288,7 +306,7 @@ tCharExchange CharExchange[] = {
{ 0, 0 }
};
-static char *ExchangeChars(char *s, bool ToFileSystem)
+char *ExchangeChars(char *s, bool ToFileSystem)
{
char *p = s;
while (*p) {
@@ -454,6 +472,7 @@ cRecording::cRecording(const char *FileName)
name[p - FileName] = 0;
name = ExchangeChars(name, false);
}
+ GetResume();
// read an optional info file:
char *InfoFileName = NULL;
asprintf(&InfoFileName, "%s%s", fileName, INFOFILESUFFIX);
@@ -492,11 +511,11 @@ cRecording::cRecording(const char *FileName)
line++;
}
fclose(f);
- if (line == 1) {
+ if (!data[2]) {
data[2] = data[1];
data[1] = NULL;
}
- else if (line == 2) {
+ else if (data[1] && data[2]) {
// if line 1 is too long, it can't be the short text,
// so assume the short text is missing and concatenate
// line 1 and line 2 to be the long text:
@@ -715,21 +734,50 @@ bool cRecording::Remove(void)
return RemoveVideoFile(FileName());
}
+void cRecording::ResetResume(void) const
+{
+ resume = RESUME_NOT_INITIALIZED;
+}
+
// --- cRecordings -----------------------------------------------------------
cRecordings Recordings;
cRecordings::cRecordings(bool Deleted)
+:cThread("video directory scanner")
{
+ updateFileName = strdup(AddDirectory(VideoDirectory, ".update"));
deleted = Deleted;
lastUpdate = 0;
+ state = 0;
+}
+
+cRecordings::~cRecordings()
+{
+ Cancel(3);
+ free(updateFileName);
+}
+
+void cRecordings::Action(void)
+{
+ Refresh();
+}
+
+void cRecordings::Refresh(bool Foreground)
+{
+ lastUpdate = time(NULL); // doing this first to make sure we don't miss anything
+ Lock();
+ Clear();
+ ChangeState();
+ Unlock();
+ ScanVideoDir(VideoDirectory, Foreground);
}
-void cRecordings::ScanVideoDir(const char *DirName)
+void cRecordings::ScanVideoDir(const char *DirName, bool Foreground)
{
cReadDir d(DirName);
struct dirent *e;
- while ((e = d.Next()) != NULL) {
+ while ((Foreground || Running()) && (e = d.Next()) != NULL) {
if (strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) {
char *buffer;
asprintf(&buffer, "%s/%s", DirName, e->d_name);
@@ -749,13 +797,17 @@ void cRecordings::ScanVideoDir(const char *DirName)
if (S_ISDIR(st.st_mode)) {
if (endswith(buffer, deleted ? DELEXT : RECEXT)) {
cRecording *r = new cRecording(buffer);
- if (r->Name())
+ if (r->Name()) {
+ Lock();
Add(r);
+ ChangeState();
+ Unlock();
+ }
else
delete r;
}
else
- ScanVideoDir(buffer);
+ ScanVideoDir(buffer, Foreground);
}
}
free(buffer);
@@ -763,18 +815,34 @@ void cRecordings::ScanVideoDir(const char *DirName)
}
}
+bool cRecordings::StateChanged(int &State)
+{
+ int NewState = state;
+ bool Result = State != NewState;
+ State = state;
+ return Result;
+}
+
+void cRecordings::TouchUpdate(void)
+{
+ TouchFile(updateFileName);
+ lastUpdate = time(NULL); // make sure we don't tigger ourselves
+}
+
bool cRecordings::NeedsUpdate(void)
{
- return lastUpdate <= LastModifiedTime(AddDirectory(VideoDirectory, ".update"));
+ return lastUpdate < LastModifiedTime(updateFileName);
}
-bool cRecordings::Load(void)
+bool cRecordings::Update(bool Wait)
{
- lastUpdate = time(NULL); // doing this first to make sure we don't miss anything
- Clear();
- ScanVideoDir(VideoDirectory);
- Sort();
- return Count() > 0;
+ if (Wait) {
+ Refresh(true);
+ return Count() > 0;
+ }
+ else
+ Start();
+ return false;
}
cRecording *cRecordings::GetByName(const char *FileName)
@@ -788,18 +856,35 @@ cRecording *cRecordings::GetByName(const char *FileName)
void cRecordings::AddByName(const char *FileName)
{
+ LOCK_THREAD;
cRecording *recording = GetByName(FileName);
if (!recording) {
recording = new cRecording(FileName);
Add(recording);
+ ChangeState();
+ TouchUpdate();
}
}
void cRecordings::DelByName(const char *FileName)
{
+ LOCK_THREAD;
cRecording *recording = GetByName(FileName);
- if (recording)
+ if (recording) {
Del(recording);
+ ChangeState();
+ TouchUpdate();
+ }
+}
+
+void cRecordings::ResetResume(const char *ResumeFileName)
+{
+ LOCK_THREAD;
+ for (cRecording *recording = First(); recording; recording = Next(recording)) {
+ if (!ResumeFileName || strncmp(ResumeFileName, recording->FileName(), strlen(recording->FileName())) == 0)
+ recording->ResetResume();
+ }
+ ChangeState();
}
// --- cMark -----------------------------------------------------------------