diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/channelfilter.c vdr-plugin-vnsiserver-1.5.2+git2017-02-25/channelfilter.c --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/channelfilter.c 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/channelfilter.c 2017-02-25 17:14:09.000000000 +0000 @@ -37,6 +37,11 @@ } +cVNSIProvider::cVNSIProvider(const cVNSIProvider &provider) + :m_name(provider.m_name), m_caid(provider.m_caid) +{ +} + cVNSIProvider::cVNSIProvider(std::string name, int caid) :m_name(name), m_caid(caid) { diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/channelfilter.h vdr-plugin-vnsiserver-1.5.2+git2017-02-25/channelfilter.h --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/channelfilter.h 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/channelfilter.h 2017-02-25 17:14:09.000000000 +0000 @@ -35,6 +35,7 @@ public: cVNSIProvider(); cVNSIProvider(std::string name, int caid); + cVNSIProvider(const cVNSIProvider &provider); bool operator==(const cVNSIProvider &rhs) const; std::string m_name; int m_caid; diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/debian/changelog vdr-plugin-vnsiserver-1.5.2+git2017-02-25/debian/changelog --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/debian/changelog 2016-10-04 07:23:10.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/debian/changelog 2017-03-04 11:54:42.000000000 +0000 @@ -1,3 +1,20 @@ +vdr-plugin-vnsiserver (2:1.5.2+git2017-02-25-0yavdr0~trusty) trusty; urgency=medium + + * new upstream snapshot + - make grouping of series recordings configurable + + -- Alexander Grothe Sat, 04 Mar 2017 12:54:16 +0100 + +vdr-plugin-vnsiserver (2:1.5.2-0yavdr0~trusty) trusty; urgency=medium + + * new upstream release + - group recordings + - fixes for epg updates + - fixes for searchtimers + - see github history + + -- Alexander Grothe Sun, 29 Jan 2017 13:13:49 +0100 + vdr-plugin-vnsiserver (2:1.5.1+git20160927-9b19e98-0yavdr0~trusty) trusty; urgency=medium * new upstream snapshot diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/HISTORY vdr-plugin-vnsiserver-1.5.2+git2017-02-25/HISTORY --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/HISTORY 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/HISTORY 2017-02-25 17:14:09.000000000 +0000 @@ -1,5 +1,12 @@ VDR Plugin 'vnsiserver' Revision History ---------------------------------------- +2017-01-14: Version 1.5.2 + +- group recordings +- fixes for epg updates +- fixes for searchtimers +- see github history + 2016-09-25: Version 1.5.1 - see github history for fixes diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/setup.c vdr-plugin-vnsiserver-1.5.2+git2017-02-25/setup.c --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/setup.c 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/setup.c 2017-02-25 17:14:09.000000000 +0000 @@ -31,6 +31,7 @@ int TimeshiftBufferFileSize = 6; char TimeshiftBufferDir[PATH_MAX] = "\0"; int PlayRecording = 0; +int GroupRecordings = 1; int AvoidEPGScan = 1; int DisableScrambleTimeout = 0; int DisableCamBlacklist = 0; @@ -55,6 +56,9 @@ newPlayRecording = PlayRecording; Add(new cMenuEditBoolItem( tr("Play Recording instead of live"), &newPlayRecording)); + newGroupRecordings = GroupRecordings; + Add(new cMenuEditBoolItem( tr("Group series recordings"), &newGroupRecordings)); + newAvoidEPGScan = AvoidEPGScan; Add(new cMenuEditBoolItem( tr("Avoid EPG scan while streaming"), &newAvoidEPGScan)); @@ -94,6 +98,8 @@ SetupStore(CONFNAME_PLAYRECORDING, PlayRecording = newPlayRecording); + SetupStore(CONFNAME_GROUPRECORDINGS, GroupRecordings = newGroupRecordings); + SetupStore(CONFNAME_AVOIDEPGSCAN, AvoidEPGScan = newAvoidEPGScan); SetupStore(CONFNAME_DISABLESCRAMBLETIMEOUT, DisableScrambleTimeout = newDisableScrambleTimeout); diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/setup.h vdr-plugin-vnsiserver-1.5.2+git2017-02-25/setup.h --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/setup.h 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/setup.h 2017-02-25 17:14:09.000000000 +0000 @@ -37,6 +37,7 @@ int newTimeshiftBufferFileSize; char newTimeshiftBufferDir[PATH_MAX]; int newPlayRecording; + int newGroupRecordings; int newAvoidEPGScan; int newDisableScrambleTimeout; int newDisableCamBlacklist; diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/status.c vdr-plugin-vnsiserver-1.5.2+git2017-02-25/status.c --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/status.c 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/status.c 2017-02-25 17:14:09.000000000 +0000 @@ -247,19 +247,23 @@ if (epg->Lock(epgState)) { epgState.Remove(false); - INFOLOG("Requesting clients to load epg"); - bool callAgain = false; + DEBUGLOG("Requesting clients to load epg"); + int callAgain = 0; for (auto &i : m_clients) { callAgain |= i.EpgChange(); } - if (callAgain) + if (callAgain & VNSI_EPG_AGAIN) { epgTimer.Set(100); epgState.Reset(); } else { + if (callAgain & VNSI_EPG_PAUSE) + { + epgState.Reset(); + } epgTimer.Set(5000); m_vnsiTimers->Scan(); } diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsi.c vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsi.c --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsi.c 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsi.c 2017-02-25 17:14:09.000000000 +0000 @@ -154,8 +154,11 @@ if (*TimeshiftBufferDir && TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] == '/') /* strip trailing slash */ TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] = 0; - } else if (!strcasecmp(Name, CONFNAME_PLAYRECORDING)) + } + else if (!strcasecmp(Name, CONFNAME_PLAYRECORDING)) PlayRecording = atoi(Value); + else if (!strcasecmp(Name, CONFNAME_GROUPRECORDINGS)) + GroupRecordings = atoi(Value); else if (!strcasecmp(Name, CONFNAME_AVOIDEPGSCAN)) AvoidEPGScan = atoi(Value); else if (!strcasecmp(Name, CONFNAME_DISABLESCRAMBLETIMEOUT)) diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsiclient.c vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsiclient.c --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsiclient.c 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsiclient.c 2017-02-25 17:14:09.000000000 +0000 @@ -37,11 +37,13 @@ #include "hash.h" #include "channelfilter.h" #include "channelscancontrol.h" - +#include +#include #include #include #include #include +#include #include #include @@ -214,9 +216,9 @@ m_socket.write(resp.getPtr(), resp.getLen()); } -bool cVNSIClient::EpgChange() +int cVNSIClient::EpgChange() { - bool callAgain = false; + int callAgain = 0; cMutexLock lock(&m_msgLock); @@ -269,7 +271,7 @@ time_t now = time(nullptr); if ((now - it->second.lastTrigger) < 5) { - callAgain = true; + callAgain = VNSI_EPG_PAUSE; continue; } @@ -284,7 +286,7 @@ resp.finalise(); m_socket.write(resp.getPtr(), resp.getLen()); - callAgain = true; + callAgain = VNSI_EPG_AGAIN; break; } @@ -1437,20 +1439,20 @@ { cMutexLock lock(&m_timerLock); - uint32_t number = req.extract_U32(); + uint32_t id = req.extract_U32(); cResponsePacket resp; resp.init(req.getRequestID()); - if (number & m_vnsiTimers.INDEX_MASK) + if (id & m_vnsiTimers.VNSITIMER_MASK) { CVNSITimer timer; - if (m_vnsiTimers.GetTimer(number, timer)) + if (m_vnsiTimers.GetTimer(id, timer)) { resp.add_U32(VNSI_RET_OK); resp.add_U32(VNSI_TIMER_TYPE_EPG_SEARCH); - resp.add_U32(number); + resp.add_U32(id); resp.add_U32(timer.m_enabled); resp.add_U32(0); resp.add_U32(0); @@ -1464,6 +1466,10 @@ resp.add_U32(0); resp.add_String(timer.m_name.c_str()); resp.add_String(timer.m_search.c_str()); + if (m_protocolVersion >= 10) + { + resp.add_U32(0); + } } else { @@ -1477,12 +1483,12 @@ int numTimers = Timers->Count(); if (numTimers > 0) { - const cTimer *timer = Timers->Get(number-1); + const cTimer *timer = Timers->GetById(id); #else int numTimers = Timers.Count(); if (numTimers > 0) { - cTimer *timer = Timers.Get(number-1); + cTimer *timer = Timers.Get(id-1); #endif if (timer) { @@ -1497,7 +1503,11 @@ type = VNSI_TIMER_TYPE_MAN; resp.add_U32(type); } +#if VDRVERSNUM >= 20301 + resp.add_U32(timer->Id()); +#else resp.add_U32(timer->Index()+1); +#endif resp.add_U32(timer->HasFlags(tfActive)); resp.add_U32(timer->Recording()); resp.add_U32(timer->Pending()); @@ -1514,6 +1524,10 @@ { resp.add_String(""); } + if (m_protocolVersion >= 10) + { + resp.add_U32(m_vnsiTimers.GetParent(timer)); + } } else resp.add_U32(VNSI_RET_DATAUNKNOWN); @@ -1561,7 +1575,11 @@ type = VNSI_TIMER_TYPE_MAN; resp.add_U32(type); } +#if VDRVERSNUM >= 20301 + resp.add_U32(timer->Id()); +#else resp.add_U32(timer->Index()+1); +#endif resp.add_U32(timer->HasFlags(tfActive)); resp.add_U32(timer->Recording()); resp.add_U32(timer->Pending()); @@ -1578,14 +1596,17 @@ { resp.add_String(""); } + if (m_protocolVersion >= 10) + { + resp.add_U32(m_vnsiTimers.GetParent(timer)); + } } std::vector vnsitimers = m_vnsiTimers.GetTimers(); - int idx = m_vnsiTimers.INDEX_MASK; for (auto &vnsitimer : vnsitimers) { resp.add_U32(VNSI_TIMER_TYPE_EPG_SEARCH); - resp.add_U32(idx); + resp.add_U32(vnsitimer.m_id | m_vnsiTimers.VNSITIMER_MASK); resp.add_U32(vnsitimer.m_enabled); resp.add_U32(0); resp.add_U32(0); @@ -1599,7 +1620,10 @@ resp.add_U32(0); resp.add_String(vnsitimer.m_name.c_str()); resp.add_String(vnsitimer.m_search.c_str()); - idx++; + if (m_protocolVersion >= 10) + { + resp.add_U32(0); + } } resp.finalise(); m_socket.write(resp.getPtr(), resp.getLen()); @@ -1629,6 +1653,14 @@ if (m_protocolVersion >= 9) epgsearch = req.extract_String(); + uint32_t marginStart = 0; + uint32_t marginEnd = 0; + if (m_protocolVersion >= 10) + { + marginStart = req.extract_U32(); + marginEnd = req.extract_U32(); + } + // handle instant timers if(startTime == -1 || startTime == 0) { @@ -1663,7 +1695,10 @@ vnsitimer.m_channelUID = channelid; vnsitimer.m_search = epgsearch; vnsitimer.m_enabled = flags; + vnsitimer.m_priority = priority; vnsitimer.m_lifetime = lifetime; + vnsitimer.m_marginStart = marginStart; + vnsitimer.m_marginEnd = marginEnd; m_vnsiTimers.Add(std::move(vnsitimer)); resp.add_U32(VNSI_RET_OK); } @@ -1720,17 +1755,17 @@ { cMutexLock lock(&m_timerLock); - uint32_t number = req.extract_U32(); - bool force = req.extract_U32(); + uint32_t id = req.extract_U32(); + bool force = req.extract_U32(); cResponsePacket resp; resp.init(req.getRequestID()); - if (number & m_vnsiTimers.INDEX_MASK) + if (id & m_vnsiTimers.VNSITIMER_MASK) { - if (m_vnsiTimers.DeleteTimer(number)) + if (m_vnsiTimers.DeleteTimer(id)) { - INFOLOG("Deleting vnsitimer %d", number); + INFOLOG("Deleting vnsitimer %d", id); resp.add_U32(VNSI_RET_OK); } else @@ -1743,85 +1778,84 @@ { #if VDRVERSNUM >= 20301 LOCK_TIMERS_WRITE; - int timersCount = Timers->Count(); + cTimer *timer = Timers->GetById(id); + if (timer) + { + Timers->SetExplicitModify(); + { + if (timer->Recording()) + { + if (force) + { + timer->Skip(); + cRecordControls::Process(Timers, time(NULL)); + } + else + { + ERRORLOG("Timer \"%i\" is recording and can be deleted (use force=1 to stop it)", id); + resp.add_U32(VNSI_RET_RECRUNNING); + resp.finalise(); + m_socket.write(resp.getPtr(), resp.getLen()); + return true; + } + } + INFOLOG("Deleting timer %s", *timer->ToDescr()); + Timers->Del(timer); + Timers->SetModified(); + resp.add_U32(VNSI_RET_OK); + } + } + else + { + ERRORLOG("Error in timer settings"); + resp.add_U32(VNSI_RET_DATAINVALID); + } #else int timersCount = Timers.Count(); -#endif - - if (number <= 0 || number > (uint32_t)timersCount) + if (id <= 0 || id > (uint32_t)timersCount) { ERRORLOG("Unable to delete timer - invalid timer identifier"); resp.add_U32(VNSI_RET_DATAINVALID); } - else + cTimer *timer = Timers.Get(id-1); + if (timer) { -#if VDRVERSNUM >= 20301 - cTimer *timer = Timers->Get(number-1); - if (timer) + if (!Timers.BeingEdited()) { - Timers->SetExplicitModify(); + if (timer->Recording()) { - if (timer->Recording()) + if (force) { - if (force) - { - timer->Skip(); - cRecordControls::Process(Timers, time(NULL)); - } - else - { - ERRORLOG("Timer \"%i\" is recording and can be deleted (use force=1 to stop it)", number); - resp.add_U32(VNSI_RET_RECRUNNING); - resp.finalise(); - m_socket.write(resp.getPtr(), resp.getLen()); - return true; - } + timer->Skip(); + cRecordControls::Process(time(NULL)); } - INFOLOG("Deleting timer %s", *timer->ToDescr()); - Timers->Del(timer); - Timers->SetModified(); - resp.add_U32(VNSI_RET_OK); - } -#else - cTimer *timer = Timers.Get(number-1); - if (timer) - { - if (!Timers.BeingEdited()) - { - if (timer->Recording()) + else { - if (force) - { - timer->Skip(); - cRecordControls::Process(time(NULL)); - } - else - { - ERRORLOG("Timer \"%i\" is recording and can be deleted (use force=1 to stop it)", number); - resp.add_U32(VNSI_RET_RECRUNNING); - resp.finalise(); - m_socket.write(resp.getPtr(), resp.getLen()); - return true; - } + ERRORLOG("Timer \"%i\" is recording and can be deleted (use force=1 to stop it)", id); + resp.add_U32(VNSI_RET_RECRUNNING); + resp.finalise(); + m_socket.write(resp.getPtr(), resp.getLen()); + return true; } - INFOLOG("Deleting timer %s", *timer->ToDescr()); - Timers.Del(timer); - Timers.SetModified(); - resp.add_U32(VNSI_RET_OK); - } - else - { - ERRORLOG("Unable to delete timer - timers being edited at VDR"); - resp.add_U32(VNSI_RET_DATALOCKED); } -#endif + INFOLOG("Deleting timer %s", *timer->ToDescr()); + Timers.Del(timer); + Timers.SetModified(); + resp.add_U32(VNSI_RET_OK); } else { - ERRORLOG("Unable to delete timer - invalid timer identifier"); - resp.add_U32(VNSI_RET_DATAINVALID); + ERRORLOG("Unable to delete timer - timers being edited at VDR"); + resp.add_U32(VNSI_RET_DATALOCKED); } } + else + { + ERRORLOG("Error in timer settings"); + resp.add_U32(VNSI_RET_DATAINVALID); + } +#endif + } resp.finalise(); m_socket.write(resp.getPtr(), resp.getLen()); @@ -1840,7 +1874,7 @@ const char *aux; std::string epgsearch; - uint32_t index = req.extract_U32(); + uint32_t id = req.extract_U32(); cResponsePacket resp; resp.init(req.getRequestID()); @@ -1864,7 +1898,7 @@ epgsearch = req.extract_String(); } - if (index & m_vnsiTimers.INDEX_MASK) + if (id & m_vnsiTimers.VNSITIMER_MASK) { CVNSITimer vnsitimer; vnsitimer.m_name = aux; @@ -1873,9 +1907,9 @@ vnsitimer.m_enabled = active; vnsitimer.m_priority = priority; vnsitimer.m_lifetime = lifetime; - if (!m_vnsiTimers.UpdateTimer(index, vnsitimer)) + if (!m_vnsiTimers.UpdateTimer(id, vnsitimer)) { - ERRORLOG("Timer \"%u\" not defined", index); + ERRORLOG("Timer \"%u\" not defined", id); resp.add_U32(VNSI_RET_DATAUNKNOWN); resp.finalise(); m_socket.write(resp.getPtr(), resp.getLen()); @@ -1886,14 +1920,14 @@ { #if VDRVERSNUM >= 20301 LOCK_TIMERS_WRITE; - cTimer *timer = Timers->Get(index - 1); + cTimer *timer = Timers->GetById(id); #else - cTimer *timer = Timers.Get(index - 1); + cTimer *timer = Timers.Get(id - 1); #endif if (!timer) { - ERRORLOG("Timer \"%u\" not defined", index); + ERRORLOG("Timer \"%u\" not defined", id); resp.add_U32(VNSI_RET_DATAUNKNOWN); resp.finalise(); m_socket.write(resp.getPtr(), resp.getLen()); @@ -2098,7 +2132,7 @@ char* fullname = strdup(recording->Name()); char* recname = strrchr(fullname, FOLDERDELIMCHAR); - char* directory = NULL; + char* directory = nullptr; if(recname == NULL) { @@ -2130,15 +2164,50 @@ if(directory != NULL) { char* p = directory; - while(*p != 0) { - if(*p == FOLDERDELIMCHAR) *p = '/'; - if(*p == '_') *p = ' '; + while(*p != 0) + { + if (*p == FOLDERDELIMCHAR) + *p = '/'; + else if (*p == '_') + *p = ' '; p++; } - while(*directory == '/') directory++; + while(*directory == '/') + directory++; + } + + std::string strDirectory; + if (directory) + strDirectory = directory; + + if (GroupRecordings) + { + int noOfEntries = 1; + char* filename = strdup(recording->FileName()); + char *pch = strrchr(filename, '/'); + if (pch) + { + int noOfRecs = 0; + *pch = 0; + char* foldername = filename; + struct dirent **fileListTemp; + noOfEntries = scandir(foldername, &fileListTemp, NULL, alphasort); + for (int i=0; id_name); + if (name.find(".rec") != std::string::npos) + noOfRecs++; + } + if (noOfRecs > 1) + { + strDirectory += "/"; + strDirectory += recname; + } + } + free(filename); } - resp.add_String((isempty(directory)) ? "" : m_toUTF8.Convert(directory)); + resp.add_String(strDirectory.empty() ? "" : m_toUTF8.Convert(strDirectory.c_str())); // filename / uid of recording uint32_t uid = cRecordingsCache::GetInstance().Register(recording, false); diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsiclient.h vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsiclient.h --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsiclient.h 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsiclient.h 2017-02-25 17:14:09.000000000 +0000 @@ -23,8 +23,7 @@ * */ -#ifndef VNSI_CLIENT_H -#define VNSI_CLIENT_H +#pragma once #include #include @@ -38,6 +37,9 @@ #include #include +#define VNSI_EPG_AGAIN 1 +#define VNSI_EPG_PAUSE 2 + class cChannel; class cDevice; class cLiveStreamer; @@ -98,7 +100,7 @@ void ChannelsChange(); void RecordingsChange(); void SignalTimerChange(); - bool EpgChange(); + int EpgChange(); static bool InhibidDataUpdates() { return m_inhibidDataUpdates; } unsigned int GetID() { return m_Id; } @@ -205,5 +207,3 @@ void processSCAN_IsFinished(); void processSCAN_SetStatus(int status); }; - -#endif // VNSI_CLIENT_H diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsicommand.h vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsicommand.h --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsicommand.h 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsicommand.h 2017-02-25 17:14:09.000000000 +0000 @@ -27,7 +27,7 @@ #define VNSI_COMMAND_H /** Current VNSI Protocol Version number */ -#define VNSI_PROTOCOLVERSION 9 +#define VNSI_PROTOCOLVERSION 10 /** Start of RDS support protocol Version */ #define VNSI_RDS_PROTOCOLVERSION 8 @@ -55,6 +55,7 @@ #define CONFNAME_AVOIDEPGSCAN "AvoidEPGScan" #define CONFNAME_DISABLESCRAMBLETIMEOUT "DisableScrambleTimeout" #define CONFNAME_DISABLECAMBLACKLIST "DisableCamBlacklist" +#define CONFNAME_GROUPRECORDINGS "GroupRecordings" /* OPCODE 1 - 19: VNSI network functions for general purpose */ #define VNSI_LOGIN 1 diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsi.h vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsi.h --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsi.h 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsi.h 2017-02-25 17:14:09.000000000 +0000 @@ -28,7 +28,7 @@ #include #include "vnsiserver.h" -static const char *VERSION = "1.5.1"; +static const char *VERSION = "1.5.2"; static const char *DESCRIPTION = "VDR-Network-Streaming-Interface (VNSI) Server"; extern int PmtTimeout; @@ -37,6 +37,7 @@ extern int TimeshiftBufferFileSize; extern char TimeshiftBufferDir[PATH_MAX]; extern int PlayRecording; +extern int GroupRecordings; extern int AvoidEPGScan; extern int DisableScrambleTimeout; extern int DisableCamBlacklist; diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsiosd.c vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsiosd.c --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsiosd.c 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsiosd.c 2017-02-25 17:14:09.000000000 +0000 @@ -29,7 +29,7 @@ #include "vnsi.h" #include #include -#include +#include #include #include #include "cxsocket.h" diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsitimer.c vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsitimer.c --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsitimer.c 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsitimer.c 2017-02-25 17:14:09.000000000 +0000 @@ -112,8 +112,32 @@ std::string lifetime = line.substr(0, pos); timer.m_lifetime = strtol(lifetime.c_str(), &pend, 10); - timer.m_search = line.substr(pos+1); + // searchstring + line = line.substr(pos+1); + pos = line.find(";"); + if (pos == line.npos) + { + timer.m_search = line.substr(pos+1); + } + else + { + timer.m_search = line.substr(0, pos); + } + + // created timers + if (pos != line.npos) + { + line = line.substr(pos+1); + while ((pos = line.find(",")) != line.npos) + { + std::string tmp = line.substr(0, pos); + time_t starttime = strtol(tmp.c_str(), &pend, 10); + timer.m_timersCreated.push_back(starttime); + line = line.substr(pos+1); + } + } + timer.m_id = ++m_nextId; m_timers.emplace_back(std::move(timer)); } rfile.close(); @@ -138,7 +162,13 @@ << timer.m_enabled << ';' << timer.m_priority << ';' << timer.m_lifetime << ';' - << timer.m_search << '\n'; + << timer.m_search << ';'; + + for (auto &starttime : timer.m_timersCreated) + { + wfile << starttime << ','; + } + wfile << '\n'; } wfile.close(); } @@ -151,6 +181,7 @@ return; timer.m_channelID = channel->GetChannelID(); + timer.m_id = ++m_nextId; cMutexLock lock(&m_timerLock); m_timers.emplace_back(std::move(timer)); @@ -176,38 +207,151 @@ return m_timers; } -bool CVNSITimers::GetTimer(int idx, CVNSITimer &timer) +bool CVNSITimers::GetTimer(int id, CVNSITimer &timer) { cMutexLock lock(&m_timerLock); - idx &= ~INDEX_MASK; - if (idx < 0 || idx >= (int)m_timers.size()) - return false; - timer = m_timers[idx]; - return true; + id &= ~VNSITIMER_MASK; + + for (auto &searchtimer : m_timers) + { + if (searchtimer.m_id == id) + { + timer = searchtimer; + return true; + } + } + return false; } -bool CVNSITimers::UpdateTimer(int idx, CVNSITimer &timer) +bool CVNSITimers::UpdateTimer(int id, CVNSITimer &timer) { cMutexLock lock(&m_timerLock); - idx &= ~INDEX_MASK; - if (idx < 0 || idx >= (int)m_timers.size()) - return false; - m_timers[idx] = timer; - m_state++; - Save(); - return true; + id &= ~VNSITIMER_MASK; + + for (auto &searchtimer : m_timers) + { + if (searchtimer.m_id == id) + { + const cChannel *channel = FindChannelByUID(timer.m_channelUID); + if (!channel) + return false; + + if (timer.m_channelUID != searchtimer.m_channelUID || + timer.m_search != searchtimer.m_search) + { + DeleteChildren(searchtimer); + } + + timer.m_id = id; + timer.m_channelID = channel->GetChannelID(); + timer.m_timersCreated = searchtimer.m_timersCreated; + + searchtimer = timer; + m_state++; + Save(); + return true; + } + } + return false; } -bool CVNSITimers::DeleteTimer(int idx) +bool CVNSITimers::DeleteTimer(int id) { cMutexLock lock(&m_timerLock); - idx &= ~INDEX_MASK; - if (idx < 0 || idx >= (int)m_timers.size()) - return false; - m_timers.erase(m_timers.begin()+idx); - m_state++; - Save(); - return true; + id &= ~VNSITIMER_MASK; + + std::vector::iterator it; + for (it = m_timers.begin(); it != m_timers.end(); ++it) + { + if (it->m_id == id) + { + DeleteChildren(*it); + m_timers.erase(it); + m_state++; + Save(); + return true; + } + } + return false; +} + +void CVNSITimers::DeleteChildren(CVNSITimer &vnsitimer) +{ +#if VDRVERSNUM >= 20301 + cStateKey timerState; + timerState.Reset(); + bool modified = false; + cTimers *Timers = cTimers::GetTimersWrite(timerState); + if (Timers) + { + Timers->SetExplicitModify(); + cTimer *timer = Timers->First(); + while (timer) + { + if (!timer->Channel()) + continue; + + timer->Matches(); + cTimer* nextTimer = Timers->Next(timer); + for (auto &starttime : vnsitimer.m_timersCreated) + { + if (vnsitimer.m_channelID == timer->Channel()->GetChannelID() && + timer->StartTime() == starttime && + !timer->Recording()) + { + Timers->Del(timer); + Timers->SetModified(); + modified = true; + break; + } + } + timer = nextTimer; + } + timerState.Remove(modified); + vnsitimer.m_timersCreated.clear(); + } +#endif +} + +int CVNSITimers::GetParent(const cTimer *timer) +{ + if (!timer->Channel()) + return 0; + + timer->Matches(); + cMutexLock lock(&m_timerLock); + for (auto &searchTimer : m_timers) + { + if (searchTimer.m_channelID == timer->Channel()->GetChannelID()) + { + for (auto &starttime : searchTimer.m_timersCreated) + { + if (timer->StartTime() == starttime) + { + return searchTimer.m_id | VNSITIMER_MASK; + } + } + } + } + return 0; +} + +bool CVNSITimers::IsChild(int id, time_t starttime) +{ + cMutexLock lock(&m_timerLock); + + for (auto &timer : m_timers) + { + if (timer.m_id != id) + continue; + + for (auto &time : timer.m_timersCreated) + { + if (time == starttime) + return true; + } + } + return false; } bool CVNSITimers::StateChange(int &state) @@ -302,11 +446,14 @@ for (const cEvent *event = schedule->Events()->First(); event; event = schedule->Events()->Next(event)) { + if (event->EndTime() < time(nullptr)) + continue; + std::string title(event->Title()); std::smatch m; std::regex e(Convert(searchTimer.m_search)); - if (std::regex_search(title, m, e, std::regex_constants::match_not_null)) + if (std::regex_search(title, m, e, std::regex_constants::match_not_null)) { bool duplicate = false; LOCK_RECORDINGS_READ; @@ -336,9 +483,55 @@ if (IsDuplicateEvent(Timers, event)) continue; - std::unique_ptr newTimer(new cTimer(event)); - Timers->Add(newTimer.release()); + cTimer *newTimer = new cTimer(event); + + if (!Setup.MarginStart) + { + unsigned int start = newTimer->Start(); + if (start < searchTimer.m_marginStart) + { + newTimer->SetDay(cTimer::IncDay(newTimer->Day(), -1)); + start = 24*3600 - (searchTimer.m_marginStart - start); + } + else + start -= searchTimer.m_marginStart; + newTimer->SetStart(start); + } + + if (!Setup.MarginStop) + { + unsigned int stop = newTimer->Stop(); + if (stop + searchTimer.m_marginEnd >= 24*3600) + { + newTimer->SetDay(cTimer::IncDay(newTimer->Day(), 1)); + stop = stop + searchTimer.m_marginEnd - 24*3600; + } + else + stop += searchTimer.m_marginEnd; + newTimer->SetStop(stop); + } + + if (IsChild(searchTimer.m_id, newTimer->StartTime())) + { + delete newTimer; + continue; + } + + Timers->Add(newTimer); modified = true; + + { + cMutexLock lock(&m_timerLock); + for (auto &origTimer : m_timers) + { + if (origTimer.m_id == searchTimer.m_id) + { + origTimer.m_timersCreated.push_back(newTimer->StartTime()); + Save(); + break; + } + } + } } } } diff -Nru vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsitimer.h vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsitimer.h --- vdr-plugin-vnsiserver-1.5.1+git20160927-9b19e98/vnsitimer.h 2016-09-27 17:53:38.000000000 +0000 +++ vdr-plugin-vnsiserver-1.5.2+git2017-02-25/vnsitimer.h 2017-02-25 17:14:09.000000000 +0000 @@ -32,17 +32,22 @@ class cEvent; class cTimers; +class cTimer; class CVNSITimer { public: + int m_id; std::string m_name; uint32_t m_channelUID; int32_t m_enabled; int32_t m_priority; int32_t m_lifetime; + uint32_t m_marginStart; + uint32_t m_marginEnd; std::string m_search; tChannelID m_channelID; + std::vector m_timersCreated; }; class CVNSITimers : public cThread @@ -57,19 +62,23 @@ size_t GetTimersCount(); bool StateChange(int &state); std::vector GetTimers(); - bool GetTimer(int idx, CVNSITimer &timer); - bool UpdateTimer(int idx, CVNSITimer &timer); - bool DeleteTimer(int idx); + bool GetTimer(int id, CVNSITimer &timer); + bool UpdateTimer(int id, CVNSITimer &timer); + bool DeleteTimer(int id); + int GetParent(const cTimer *timer); - static constexpr uint32_t INDEX_MASK = 0xF0000000; + static constexpr uint32_t VNSITIMER_MASK = 0xF0000000; protected: virtual void Action(void) override; std::string Convert(std::string search); bool IsDuplicateEvent(cTimers *timers, const cEvent *event); + void DeleteChildren(CVNSITimer &vnsitimer); + bool IsChild(int id, time_t starttime); std::vector m_timers; std::atomic_bool m_doScan; std::atomic_int m_state; cMutex m_timerLock; + int m_nextId = 0; };