From c16bbf7422f37108580e559ca849e5aafbdac672 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 25 Sep 2005 18:00:00 +0200 Subject: =?UTF-8?q?Version=201.3.33=20-=20Fixed=20two=20errors=20in=20'new?= =?UTF-8?q?plugin'=20(thanks=20to=20Alexander=20Rieger).=20-=20Fixed=20con?= =?UTF-8?q?verting=20arbitrarily=20formatted=20summary.vdr=20files=20(than?= =?UTF-8?q?ks=20to=20Thomas=20G=C3=BCnther).=20-=20Fixed=20handling=20colo?= =?UTF-8?q?r=20buttons=20in=20cMenuEditStrItem=20(thanks=20to=20Alexander?= =?UTF-8?q?=20Rieger).=20-=20Added=20cChannel::LinkChannels()=20and=20cCha?= =?UTF-8?q?nnel::RefChannel()=20(suggested=20by=20Helmut=20Auer).=20=20=20?= =?UTF-8?q?Note=20that=20VDR=20itself=20doesn't=20actually=20use=20the=20l?= =?UTF-8?q?inked=20channels,=20yet,=20so=20there=20is=20=20=20no=20guarant?= =?UTF-8?q?ee=20that=20this=20really=20works=20under=20all=20circumstances?= =?UTF-8?q?.=20-=20Added=20a=20missing=20include=20statement=20to=20the=20?= =?UTF-8?q?'sky'=20plugin=20(thanks=20to=20Alfred=20Zastrow=20=20=20for=20?= =?UTF-8?q?reporting=20this=20one).=20-=20Fixed=20handling=20key=20macros?= =?UTF-8?q?=20with=20keys=20after=20@plugin=20(thanks=20to=20Rolf=20Ahrenb?= =?UTF-8?q?erg=20for=20=20=20reporting=20this=20one).=20-=20Fixed=20error?= =?UTF-8?q?=20handling=20in=20cCiTransportConnection::RecvTPDU()=20(thanks?= =?UTF-8?q?=20to=20Georg=20Acher=20=20=20for=20reporting=20this=20one).=20?= =?UTF-8?q?-=20Removed=20obsolete=20'shift'=20code=20in=20device.[hc].=20-?= =?UTF-8?q?=20The=20SVDRP=20command=20DELR=20no=20longer=20triggers=20a=20?= =?UTF-8?q?complete=20reload=20of=20the=20global=20Recordings=20=20=20list?= =?UTF-8?q?,=20but=20rather=20deletes=20that=20particular=20entry.=20-=20T?= =?UTF-8?q?he=20list=20of=20recordings=20is=20now=20read=20in=20a=20separa?= =?UTF-8?q?te=20thread,=20resulting=20in=20a=20faster=20=20=20startup=20if?= =?UTF-8?q?=20there=20are=20a=20great=20many=20of=20recordings,=20or=20the?= =?UTF-8?q?=20disk(s)=20have=20to=20spin=20up.=20=20=20If=20the=20Recordin?= =?UTF-8?q?gs=20menu=20is=20opened=20while=20the=20list=20of=20recordings?= =?UTF-8?q?=20is=20still=20being=20read,=20=20=20the=20menu=20will=20be=20?= =?UTF-8?q?updated=20accordingly.=20=20=20Plugins=20that=20access=20the=20?= =?UTF-8?q?global=20Recordings=20variable=20should=20lock=20the=20thread?= =?UTF-8?q?=20=20=20by=20putting=20something=20like?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- recording.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 107 insertions(+), 22 deletions(-) (limited to 'recording.c') 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 ----------------------------------------------------------------- -- cgit v1.2.3