mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Recordings now have unique ids
This commit is contained in:
		| @@ -3469,6 +3469,8 @@ Aitugan Sarbassov <isarbassov@gmail.com> | ||||
| Sergey Chernyavskiy <glenvt18@gmail.com> | ||||
|  for reporting truncated date/time strings in the skins on multi-byte UTF-8 | ||||
|  for adding a short sleep to cTSBuffer::Action() to avoid high CPU usage | ||||
|  for making the SVDRP commands that deal with recordings use a unique id for each | ||||
|  recording | ||||
|  | ||||
| Frank Richter <kulpstur@t-online.de> | ||||
|  for adding 'S3W ABS-3A' to sources.conf | ||||
|   | ||||
							
								
								
									
										6
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								HISTORY
									
									
									
									
									
								
							| @@ -8953,3 +8953,9 @@ Video Disk Recorder Revision History | ||||
|   an "SVDRP default host" has been set for normal timer recordings. | ||||
| - cOsdMenu::Display() now checks whether the OSD size has changed and if so calls | ||||
|   SetDisplayMenu(). | ||||
| - The SVDRP commands that deal with recordings (DELR, EDIT, LSTR, MOVR, and PLAY) | ||||
|   now use a unique id for each recording, which remains valid as long as this | ||||
|   instance of VDR is running. This means that recordings are no longer continuously | ||||
|   numbered from 1 to N in LSTR. There may be gaps in the sequence, in case recordings | ||||
|   have been deleted, and they are not necessarily listed in numeric order. | ||||
|   Thanks to Sergey Chernyavskiy. | ||||
|   | ||||
							
								
								
									
										25
									
								
								recording.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								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 4.7 2017/01/01 17:52:51 kls Exp $ | ||||
|  * $Id: recording.c 4.8 2017/04/03 13:34:30 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "recording.h" | ||||
| @@ -753,6 +753,7 @@ char *LimitNameLengths(char *s, int PathMax, int NameMax) | ||||
|  | ||||
| cRecording::cRecording(cTimer *Timer, const cEvent *Event) | ||||
| { | ||||
|   id = 0; | ||||
|   resume = RESUME_NOT_INITIALIZED; | ||||
|   titleBuffer = NULL; | ||||
|   sortBufferName = sortBufferTime = NULL; | ||||
| @@ -808,6 +809,7 @@ cRecording::cRecording(cTimer *Timer, const cEvent *Event) | ||||
|  | ||||
| cRecording::cRecording(const char *FileName) | ||||
| { | ||||
|   id = 0; | ||||
|   resume = RESUME_NOT_INITIALIZED; | ||||
|   fileSizeMB = -1; // unknown | ||||
|   channel = -1; | ||||
| @@ -1000,6 +1002,11 @@ void cRecording::ClearSortName(void) | ||||
|   sortBufferName = sortBufferTime = NULL; | ||||
| } | ||||
|  | ||||
| void cRecording::SetId(int Id) | ||||
| { | ||||
|   id = Id; | ||||
| } | ||||
|  | ||||
| int cRecording::GetResume(void) const | ||||
| { | ||||
|   if (resume == RESUME_NOT_INITIALIZED) { | ||||
| @@ -1456,6 +1463,7 @@ void cVideoDirectoryScannerThread::ScanVideoDir(const char *DirName, int LinkLev | ||||
|  | ||||
| cRecordings cRecordings::recordings; | ||||
| cRecordings cRecordings::deletedRecordings(true); | ||||
| int cRecordings::lastRecordingId = 0; | ||||
| char *cRecordings::updateFileName = NULL; | ||||
| cVideoDirectoryScannerThread *cRecordings::videoDirectoryScannerThread = NULL; | ||||
| time_t cRecordings::lastUpdate = 0; | ||||
| @@ -1507,6 +1515,15 @@ void cRecordings::Update(bool Wait) | ||||
|      } | ||||
| } | ||||
|  | ||||
| const cRecording *cRecordings::GetById(int Id) const | ||||
| { | ||||
|   for (const cRecording *Recording = First(); Recording; Recording = Next(Recording)) { | ||||
|       if (Recording->Id() == Id) | ||||
|          return Recording; | ||||
|       } | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| const cRecording *cRecordings::GetByName(const char *FileName) const | ||||
| { | ||||
|   if (FileName) { | ||||
| @@ -1518,6 +1535,12 @@ const cRecording *cRecordings::GetByName(const char *FileName) const | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| void cRecordings::Add(cRecording *Recording) | ||||
| { | ||||
|   Recording->SetId(++lastRecordingId); | ||||
|   cList<cRecording>::Add(Recording); | ||||
| } | ||||
|  | ||||
| void cRecordings::AddByName(const char *FileName, bool TriggerUpdate) | ||||
| { | ||||
|   if (!GetByName(FileName)) { | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: recording.h 4.4 2016/12/13 13:12:12 kls Exp $ | ||||
|  * $Id: recording.h 4.5 2017/04/03 13:31:16 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __RECORDING_H | ||||
| @@ -97,6 +97,7 @@ public: | ||||
| class cRecording : public cListObject { | ||||
|   friend class cRecordings; | ||||
| private: | ||||
|   int id; | ||||
|   mutable int resume; | ||||
|   mutable char *titleBuffer; | ||||
|   mutable char *sortBufferName; | ||||
| @@ -116,6 +117,7 @@ private: | ||||
|   static char *StripEpisodeName(char *s, bool Strip); | ||||
|   char *SortName(void) const; | ||||
|   void ClearSortName(void); | ||||
|   void SetId(int Id); // should only be set by cRecordings | ||||
|   time_t start; | ||||
|   int priority; | ||||
|   int lifetime; | ||||
| @@ -124,6 +126,7 @@ public: | ||||
|   cRecording(cTimer *Timer, const cEvent *Event); | ||||
|   cRecording(const char *FileName); | ||||
|   virtual ~cRecording(); | ||||
|   int Id(void) const { return id; } | ||||
|   time_t Start(void) const { return start; } | ||||
|   int Priority(void) const { return priority; } | ||||
|   int Lifetime(void) const { return lifetime; } | ||||
| @@ -222,6 +225,7 @@ class cRecordings : public cList<cRecording> { | ||||
| private: | ||||
|   static cRecordings recordings; | ||||
|   static cRecordings deletedRecordings; | ||||
|   static int lastRecordingId; | ||||
|   static char *updateFileName; | ||||
|   static time_t lastUpdate; | ||||
|   static cVideoDirectoryScannerThread *videoDirectoryScannerThread; | ||||
| @@ -254,8 +258,11 @@ public: | ||||
|   static bool NeedsUpdate(void); | ||||
|   void ResetResume(const char *ResumeFileName = NULL); | ||||
|   void ClearSortNames(void); | ||||
|   const cRecording *GetById(int Id) const; | ||||
|   cRecording *GetById(int Id) { return const_cast<cRecording *>(static_cast<const cRecordings *>(this)->GetById(Id)); }; | ||||
|   const cRecording *GetByName(const char *FileName) const; | ||||
|   cRecording *GetByName(const char *FileName) { return const_cast<cRecording *>(static_cast<const cRecordings *>(this)->GetByName(FileName)); } | ||||
|   void Add(cRecording *Recording); | ||||
|   void AddByName(const char *FileName, bool TriggerUpdate = true); | ||||
|   void DelByName(const char *FileName); | ||||
|   void UpdateByName(const char *FileName); | ||||
|   | ||||
							
								
								
									
										53
									
								
								svdrp.c
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								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 4.11 2016/12/08 10:48:53 kls Exp $ | ||||
|  * $Id: svdrp.c 4.12 2017/04/03 13:56:52 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "svdrp.h" | ||||
| @@ -723,18 +723,19 @@ const char *HelpPages[] = { | ||||
|   "    interfere with data from the broadcasters.", | ||||
|   "DELC <number>\n" | ||||
|   "    Delete channel.", | ||||
|   "DELR <number>\n" | ||||
|   "    Delete the recording with the given number. Before a recording can be\n" | ||||
|   "    deleted, an LSTR command must have been executed in order to retrieve\n" | ||||
|   "    the recording numbers. The numbers don't change during subsequent DELR\n" | ||||
|   "    commands. CAUTION: THERE IS NO CONFIRMATION PROMPT WHEN DELETING A\n" | ||||
|   "DELR <id>\n" | ||||
|   "    Delete the recording with the given id. Before a recording can be\n" | ||||
|   "    deleted, an LSTR command should have been executed in order to retrieve\n" | ||||
|   "    the recording ids. The ids are unique and don't change while this\n" | ||||
|   "    instance of VDR is running.\n" | ||||
|   "    CAUTION: THERE IS NO CONFIRMATION PROMPT WHEN DELETING A\n" | ||||
|   "    RECORDING - BE SURE YOU KNOW WHAT YOU ARE DOING!", | ||||
|   "DELT <number>\n" | ||||
|   "    Delete timer.", | ||||
|   "EDIT <number>\n" | ||||
|   "    Edit the recording with the given number. Before a recording can be\n" | ||||
|   "    edited, an LSTR command must have been executed in order to retrieve\n" | ||||
|   "    the recording numbers.", | ||||
|   "EDIT <id>\n" | ||||
|   "    Edit the recording with the given id. Before a recording can be\n" | ||||
|   "    edited, an LSTR command should have been executed in order to retrieve\n" | ||||
|   "    the recording ids.", | ||||
|   "GRAB <filename> [ <quality> [ <sizex> <sizey> ] ]\n" | ||||
|   "    Grab the current frame and save it to the given file. Images can\n" | ||||
|   "    be stored as JPEG or PNM, depending on the given file name extension.\n" | ||||
| @@ -764,11 +765,13 @@ const char *HelpPages[] = { | ||||
|   "    only data for that channel is listed. 'now', 'next', or 'at <time>'\n" | ||||
|   "    restricts the returned data to present events, following events, or\n" | ||||
|   "    events at the given time (which must be in time_t form).", | ||||
|   "LSTR [ <number> [ path ] ]\n" | ||||
|   "LSTR [ <id> [ path ] ]\n" | ||||
|   "    List recordings. Without option, all recordings are listed. Otherwise\n" | ||||
|   "    the information for the given recording is listed. If a recording\n" | ||||
|   "    number and the keyword 'path' is given, the actual file name of that\n" | ||||
|   "    recording's directory is listed.", | ||||
|   "    id and the keyword 'path' is given, the actual file name of that\n" | ||||
|   "    recording's directory is listed.\n" | ||||
|   "    Note that the ids of the recordings are not necessarily given in\n" | ||||
|   "    numeric order.", | ||||
|   "LSTT [ <number> ] [ id ]\n" | ||||
|   "    List timers. Without option, all timers are listed. Otherwise\n" | ||||
|   "    only the given timer is listed. If the keyword 'id' is given, the\n" | ||||
| @@ -787,10 +790,10 @@ const char *HelpPages[] = { | ||||
|   "    used to easily activate or deactivate a timer.", | ||||
|   "MOVC <number> <to>\n" | ||||
|   "    Move a channel to a new position.", | ||||
|   "MOVR <number> <new name>\n" | ||||
|   "    Move the recording with the given number. Before a recording can be\n" | ||||
|   "    moved, an LSTR command must have been executed in order to retrieve\n" | ||||
|   "    the recording numbers. The numbers don't change during subsequent MOVR\n" | ||||
|   "MOVR <id> <new name>\n" | ||||
|   "    Move the recording with the given id. Before a recording can be\n" | ||||
|   "    moved, an LSTR command should have been executed in order to retrieve\n" | ||||
|   "    the recording ids. The ids don't change during subsequent MOVR\n" | ||||
|   "    commands.\n", | ||||
|   "NEWC <settings>\n" | ||||
|   "    Create a new channel. Settings must be in the same format as returned\n" | ||||
| @@ -812,10 +815,10 @@ const char *HelpPages[] = { | ||||
|   "    Used by peer-to-peer connections between VDRs to keep the connection\n" | ||||
|   "    from timing out. May be used at any time and simply returns a line of\n" | ||||
|   "    the form '<hostname> is alive'.", | ||||
|   "PLAY <number> [ begin | <position> ]\n" | ||||
|   "    Play the recording with the given number. Before a recording can be\n" | ||||
|   "    played, an LSTR command must have been executed in order to retrieve\n" | ||||
|   "    the recording numbers.\n" | ||||
|   "PLAY <id> [ begin | <position> ]\n" | ||||
|   "    Play the recording with the given id. Before a recording can be\n" | ||||
|   "    played, an LSTR command should have been executed in order to retrieve\n" | ||||
|   "    the recording ids.\n" | ||||
|   "    The keyword 'begin' plays the recording from its very beginning, while\n" | ||||
|   "    a <position> (given as hh:mm:ss[.ff] or framenumber) starts at that\n" | ||||
|   "    position. If neither 'begin' nor a <position> are given, replay is resumed\n" | ||||
| @@ -1280,7 +1283,7 @@ void cSVDRPServer::CmdDELR(const char *Option) | ||||
|      if (isnumber(Option)) { | ||||
|         LOCK_RECORDINGS_WRITE; | ||||
|         Recordings->SetExplicitModify(); | ||||
|         if (cRecording *Recording = Recordings->Get(strtol(Option, NULL, 10) - 1)) { | ||||
|         if (cRecording *Recording = Recordings->GetById(strtol(Option, NULL, 10))) { | ||||
|            if (int RecordingInUse = Recording->IsInUse()) | ||||
|               Reply(550, "%s", *RecordingInUseMessage(RecordingInUse, Option, Recording)); | ||||
|            else { | ||||
| @@ -1707,7 +1710,7 @@ void cSVDRPServer::CmdLSTR(const char *Option) | ||||
|            p = strtok_r(NULL, delim, &strtok_next); | ||||
|            } | ||||
|      if (Number) { | ||||
|         if (const cRecording *Recording = Recordings->Get(strtol(Option, NULL, 10) - 1)) { | ||||
|         if (const cRecording *Recording = Recordings->GetById(strtol(Option, NULL, 10))) { | ||||
|            FILE *f = fdopen(file, "w"); | ||||
|            if (f) { | ||||
|               if (Path) | ||||
| @@ -1729,7 +1732,7 @@ void cSVDRPServer::CmdLSTR(const char *Option) | ||||
|   else if (Recordings->Count()) { | ||||
|      const cRecording *Recording = Recordings->First(); | ||||
|      while (Recording) { | ||||
|            Reply(Recording == Recordings->Last() ? 250 : -250, "%d %s", Recording->Index() + 1, Recording->Title(' ', true)); | ||||
|            Reply(Recording == Recordings->Last() ? 250 : -250, "%d %s", Recording->Id(), Recording->Title(' ', true)); | ||||
|            Recording = Recordings->Next(Recording); | ||||
|            } | ||||
|      } | ||||
| @@ -1940,7 +1943,7 @@ void cSVDRPServer::CmdMOVR(const char *Option) | ||||
|      if (isnumber(num)) { | ||||
|         LOCK_RECORDINGS_WRITE; | ||||
|         Recordings->SetExplicitModify(); | ||||
|         if (cRecording *Recording = Recordings->Get(strtol(num, NULL, 10) - 1)) { | ||||
|         if (cRecording *Recording = Recordings->GetById(strtol(num, NULL, 10))) { | ||||
|            if (int RecordingInUse = Recording->IsInUse()) | ||||
|               Reply(550, "%s", *RecordingInUseMessage(RecordingInUse, Option, Recording)); | ||||
|            else { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user