diff --git a/Makefile b/Makefile index 2643049..a22169e 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,7 @@ OBJS = $(PLUGIN).o \ extensions/cairoimage.o \ extensions/curlfuncs.o \ extensions/fontmanager.o \ + extensions/globaltimers.o \ extensions/imagecache.o \ extensions/helpers.o \ extensions/imageloader.o \ @@ -80,7 +81,6 @@ OBJS = $(PLUGIN).o \ extensions/skinsetup.o \ extensions/skinrepo.o \ extensions/extrecinfo.o \ - extensions/timers.o \ coreengine/animation.o \ coreengine/attribute.o \ coreengine/attributes.o \ diff --git a/coreengine/definitions.h b/coreengine/definitions.h index 5787615..ccb9acb 100644 --- a/coreengine/definitions.h +++ b/coreengine/definitions.h @@ -504,6 +504,7 @@ enum class eDMTimersLT { channelid, channellogoexists, isremotetimer, + remotehost, count }; @@ -898,6 +899,10 @@ enum class eLeMenuTimersST { eventtitle, eventstart, eventstop, + state, + stateinfo, + action, + vdrname, count }; @@ -914,6 +919,8 @@ enum class eLeMenuTimersIT { flagvps, flagrecording, flagpending, + isvdrrunning, + isremote, count }; @@ -933,6 +940,10 @@ enum class eCeMenuTimersST { eventdescription, posterpath, bannerpath, + state, + stateinfo, + action, + vdrname, count }; @@ -957,6 +968,8 @@ enum class eCeMenuTimersIT { hasbanner, bannerwidth, bannerheight, + isvdrrunning, + isremote, count }; diff --git a/coreengine/listelements.c b/coreengine/listelements.c index 1d9d015..e5dfd93 100644 --- a/coreengine/listelements.c +++ b/coreengine/listelements.c @@ -1,5 +1,6 @@ #include "listelements.h" #include "../config.h" +#include "../services/epgtimer.h" #include #include @@ -1181,6 +1182,10 @@ void cLeMenuTimers::SetTokenContainer(void) { tokenContainer->DefineStringToken("{eventtitle}", (int)eLeMenuTimersST::eventtitle); tokenContainer->DefineStringToken("{eventstart}", (int)eLeMenuTimersST::eventstart); tokenContainer->DefineStringToken("{eventstop}", (int)eLeMenuTimersST::eventstop); + tokenContainer->DefineStringToken("{state}", (int)eLeMenuTimersST::state); + tokenContainer->DefineStringToken("{stateinfo}", (int)eLeMenuTimersST::stateinfo); + tokenContainer->DefineStringToken("{action}", (int)eLeMenuTimersST::action); + tokenContainer->DefineStringToken("{vdrname}", (int)eLeMenuTimersST::vdrname); tokenContainer->DefineIntToken("{nummenuitem}", (int)eLeMenuTimersIT::nummenuitem); tokenContainer->DefineIntToken("{current}", (int)eLeMenuTimersIT::current); tokenContainer->DefineIntToken("{separator}", (int)eLeMenuTimersIT::separator); @@ -1193,6 +1198,8 @@ void cLeMenuTimers::SetTokenContainer(void) { tokenContainer->DefineIntToken("{flagvps}", (int)eLeMenuTimersIT::flagvps); tokenContainer->DefineIntToken("{flagrecording}", (int)eLeMenuTimersIT::flagrecording); tokenContainer->DefineIntToken("{flagpending}", (int)eLeMenuTimersIT::flagpending); + tokenContainer->DefineIntToken("{isvdrrunning}", (int)eLeMenuTimersIT::isvdrrunning); + tokenContainer->DefineIntToken("{isremote}", (int)eLeMenuTimersIT::isremote); InheritTokenContainer(); } @@ -1279,6 +1286,21 @@ bool cLeMenuTimers::Parse(bool forced) { tokenContainer->AddStringToken((int)eLeMenuTimersST::eventstart, *event->GetTimeString()); tokenContainer->AddStringToken((int)eLeMenuTimersST::eventstop, *event->GetEndTimeString()); } + + cEpgTimer_Interface_V1* epgTimer; + if (epgTimer = dynamic_cast((cTimer*)timer)) { + tokenContainer->AddIntToken((int)eLeMenuTimersIT::isvdrrunning, epgTimer->isVdrRunning()); + tokenContainer->AddIntToken((int)eLeMenuTimersIT::isremote, epgTimer->isRemote()); + stringstream state; + state << epgTimer->State(); + tokenContainer->AddStringToken((int)eLeMenuTimersST::state, state.str().c_str()); + tokenContainer->AddStringToken((int)eLeMenuTimersST::stateinfo, epgTimer->StateInfo()); + tokenContainer->AddStringToken((int)eLeMenuTimersST::vdrname, epgTimer->VdrName()); + stringstream action; + action << epgTimer->Action(); + tokenContainer->AddStringToken((int)eLeMenuTimersST::action, action.str().c_str()); + } + return true; } @@ -1318,6 +1340,10 @@ void cCeMenuTimers::SetTokenContainer(void) { tokenContainer->DefineStringToken("{eventdescription}", (int)eCeMenuTimersST::eventdescription); tokenContainer->DefineStringToken("{posterpath}", (int)eCeMenuTimersST::posterpath); tokenContainer->DefineStringToken("{bannerpath}", (int)eCeMenuTimersST::bannerpath); + tokenContainer->DefineStringToken("{state}", (int)eCeMenuTimersST::state); + tokenContainer->DefineStringToken("{stateinfo}", (int)eCeMenuTimersST::stateinfo); + tokenContainer->DefineStringToken("{action}", (int)eCeMenuTimersST::action); + tokenContainer->DefineStringToken("{vdrname}", (int)eCeMenuTimersST::vdrname); tokenContainer->DefineIntToken("{menuitemx}", (int)eCeMenuTimersIT::menuitemx); tokenContainer->DefineIntToken("{menuitemy}", (int)eCeMenuTimersIT::menuitemy); tokenContainer->DefineIntToken("{menuitemwidth}", (int)eCeMenuTimersIT::menuitemwidth); @@ -1338,6 +1364,8 @@ void cCeMenuTimers::SetTokenContainer(void) { tokenContainer->DefineIntToken("{hasbanner}", (int)eCeMenuTimersIT::hasbanner); tokenContainer->DefineIntToken("{bannerwidth}", (int)eCeMenuTimersIT::bannerwidth); tokenContainer->DefineIntToken("{bannerheight}", (int)eCeMenuTimersIT::bannerheight); + tokenContainer->DefineIntToken("{isvdrrunning}", (int)eCeMenuTimersIT::isvdrrunning); + tokenContainer->DefineIntToken("{isremote}", (int)eCeMenuTimersIT::isremote); InheritTokenContainer(); } @@ -1423,6 +1451,21 @@ bool cCeMenuTimers::Parse(bool forced) { if (LoadFullScrapInfo(event, NULL)) SetScraperPosterBannerTimer(tokenContainer); } + + cEpgTimer_Interface_V1* epgTimer; + if (epgTimer = dynamic_cast((cTimer*)timer)) { + tokenContainer->AddIntToken((int)eCeMenuTimersIT::isvdrrunning, epgTimer->isVdrRunning()); + tokenContainer->AddIntToken((int)eCeMenuTimersIT::isremote, epgTimer->isRemote()); + stringstream state; + state << epgTimer->State(); + tokenContainer->AddStringToken((int)eCeMenuTimersST::state, state.str().c_str()); + tokenContainer->AddStringToken((int)eCeMenuTimersST::stateinfo, epgTimer->StateInfo()); + tokenContainer->AddStringToken((int)eCeMenuTimersST::vdrname, epgTimer->VdrName()); + stringstream action; + action << epgTimer->Action(); + tokenContainer->AddStringToken((int)eCeMenuTimersST::action, action.str().c_str()); + } + return true; } diff --git a/coreengine/viewdisplaychannel.c b/coreengine/viewdisplaychannel.c index 38c444f..5a6bb68 100644 --- a/coreengine/viewdisplaychannel.c +++ b/coreengine/viewdisplaychannel.c @@ -68,6 +68,7 @@ void cViewChannel::SetViewElementObjects(void) { else if (dynamic_cast(viewElements[i])) { veEpgInfo = dynamic_cast(viewElements[i]); + veEpgInfo->SetGlobalTimers(&globalTimers); } else if (dynamic_cast(viewElements[i])) { @@ -76,6 +77,7 @@ void cViewChannel::SetViewElementObjects(void) { else if (dynamic_cast(viewElements[i])) { veStatusInfo = dynamic_cast(viewElements[i]); + veStatusInfo->SetGlobalTimers(&globalTimers); } else if (dynamic_cast(viewElements[i])) { @@ -102,6 +104,7 @@ void cViewChannel::ClearVariables(void) { displayChannelGroups = false; if (veCustomTokens) veCustomTokens->Reset(); + globalTimers.ClearTimers(); } void cViewChannel::SetChannel(const cChannel *channel, int number) { @@ -141,6 +144,9 @@ void cViewChannel::SetChannel(const cChannel *channel, int number) { } void cViewChannel::SetEvents(const cEvent *present, const cEvent *following) { + if (init) { + globalTimers.LoadTimers(); + } Clear((int)eVeDisplayChannel::epginfo); Clear((int)eVeDisplayChannel::progressbar); Clear((int)eVeDisplayChannel::scrapercontent); diff --git a/coreengine/viewdisplaychannel.h b/coreengine/viewdisplaychannel.h index 2170e40..e05217e 100644 --- a/coreengine/viewdisplaychannel.h +++ b/coreengine/viewdisplaychannel.h @@ -2,6 +2,7 @@ #define __VIEWDISPLAYCHANNEL_H #include "view.h" +#include "../extensions/globaltimers.h" class cViewChannel : public cView { private: @@ -16,6 +17,7 @@ private: cVeDcEcmInfo *veEcmInfo; bool channelChange; bool displayChannelGroups; + cGlobalTimers globalTimers; void SetViewElements(void); void ClearVariables(void); void SetViewElementObjects(void); diff --git a/coreengine/viewelementsdisplaychannel.c b/coreengine/viewelementsdisplaychannel.c index 3384a53..875a588 100644 --- a/coreengine/viewelementsdisplaychannel.c +++ b/coreengine/viewelementsdisplaychannel.c @@ -1,7 +1,6 @@ #include "viewelementsdisplaychannel.h" #include "../config.h" #include "../extensions/helpers.h" -#include "../extensions/timers.h" #include "../services/scraper2vdr.h" /****************************************************************** @@ -111,6 +110,7 @@ const char *cVeDcChannelGroup::GetChannelSep(const cChannel *c, bool prev) { * cVeDcEpgInfo ******************************************************************/ cVeDcEpgInfo::cVeDcEpgInfo(void) { + globalTimers = NULL; } cVeDcEpgInfo::~cVeDcEpgInfo(void) { @@ -176,24 +176,14 @@ void cVeDcEpgInfo::Close(void) { bool cVeDcEpgInfo::EventHasTimer(const cEvent *e) { if (!e) return false; - int timerCount = 0; - // BLOCK for LOCK_TIMERS_READ scope !! - { -#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) - LOCK_TIMERS_READ; - timerCount = Timers->Count(); -#else - timerCount = Timers.Count(); -#endif - } - cGlobalSortedTimers SortedTimers(timerCount); // local and remote timers bool hasTimer = e->HasTimer(); - for (int i = 0; i < SortedTimers.Size() && !hasTimer; i++) - if (const cTimer *Timer = SortedTimers[i]) + for (int i = 0; i < globalTimers->Size() && !hasTimer; i++) + if (const cTimer *Timer = globalTimers->At(i)) if (Timer->Channel()->GetChannelID() == e->ChannelID()) if (const cEvent *timerEvent = Timer->Event()) if (e->EventID() == timerEvent->EventID()) hasTimer = true; + return hasTimer; } @@ -328,19 +318,9 @@ void cVeDcStatusInfo::Set(const cChannel *c) { bool isDolby = c->Dpid(0); bool isEncrypted = c->Ca(); bool isRecording = cRecordControls::Active(); - int timerCount = 0; - // BLOCK for LOCK_TIMERS_READ scope !! - { -#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) - LOCK_TIMERS_READ; - timerCount = Timers->Count(); -#else - timerCount = Timers.Count(); -#endif - } - cGlobalSortedTimers SortedTimers(timerCount); // local and remote timers - for (int i = 0; i < SortedTimers.Size() && !isRecording; i++) - if (const cTimer *Timer = SortedTimers[i]) + + for (int i = 0; i < globalTimers->Size() && !isRecording; i++) + if (const cTimer *Timer = globalTimers->At(i)) if (Timer->Recording()) isRecording = true; diff --git a/coreengine/viewelementsdisplaychannel.h b/coreengine/viewelementsdisplaychannel.h index 3505201..799456d 100644 --- a/coreengine/viewelementsdisplaychannel.h +++ b/coreengine/viewelementsdisplaychannel.h @@ -3,6 +3,7 @@ #include "viewelement.h" #include "../extensions/scrapmanager.h" +#include "../extensions/globaltimers.h" #include "../services/dvbapi.h" /****************************************************************** @@ -33,10 +34,12 @@ public: ******************************************************************/ class cVeDcEpgInfo : public cViewElement { private: + cGlobalTimers *globalTimers; bool EventHasTimer(const cEvent *e); public: cVeDcEpgInfo(void); virtual ~cVeDcEpgInfo(void); + void SetGlobalTimers(cGlobalTimers *globalTimers) { this->globalTimers = globalTimers; }; void SetTokenContainer(void); void Set(const cEvent *p, const cEvent *f); void Close(void); @@ -63,10 +66,12 @@ public: ******************************************************************/ class cVeDcStatusInfo : public cViewElement { private: + cGlobalTimers *globalTimers; bool CheckMails(void); public: cVeDcStatusInfo(void); virtual ~cVeDcStatusInfo(void); + void SetGlobalTimers(cGlobalTimers *globalTimers) { this->globalTimers = globalTimers; }; void SetTokenContainer(void); void Set(const cChannel *c); }; diff --git a/coreengine/viewelementsdisplaymenu.c b/coreengine/viewelementsdisplaymenu.c index cd2b8fc..51349c7 100644 --- a/coreengine/viewelementsdisplaymenu.c +++ b/coreengine/viewelementsdisplaymenu.c @@ -1,8 +1,8 @@ #include "viewelementsdisplaymenu.h" #include "../config.h" #include -#include "../extensions/timers.h" #include "../extensions/helpers.h" +#include "../extensions/globaltimers.h" #include #include #include @@ -336,6 +336,7 @@ void cVeDmTimers::SetTokenContainer(void) { tokenContainer->DefineLoopToken("{timers[channelid]}", (int)eDMTimersLT::channelid); tokenContainer->DefineLoopToken("{timers[channellogoexists]}", (int)eDMTimersLT::channellogoexists); tokenContainer->DefineLoopToken("{timers[isremotetimer]}", (int)eDMTimersLT::isremotetimer); + tokenContainer->DefineLoopToken("{timers[remotehost]}", (int)eDMTimersLT::remotehost); tokenContainer->DefineIntToken("{numtimers}", (int)eDMTimersIT::numtimers); tokenContainer->DefineIntToken("{numtimerconflicts}", (int)eDMTimersIT::numtimerconflicts); tokenContainer->DefineIntToken("{timer1exists}", (int)eDMTimersIT::timer1exists); @@ -361,21 +362,15 @@ bool cVeDmTimers::Parse(bool forced) { if (!cViewElement::Parse(forced)) return false; tokenContainer->Clear(); + + cGlobalTimers globalTimers; + globalTimers.LoadTimers(); + globalTimers.SortTimers(); + globalTimers.MarkLocalTimers(); - int timerCount = 0; - // BLOCK for LOCK_TIMERS_READ scope !! - { -#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) - LOCK_TIMERS_READ; - timerCount = Timers->Count(); -#else - timerCount = Timers.Count(); -#endif - } - cGlobalSortedTimers SortedTimers(timerCount); // local and remote timers - int numTimers = SortedTimers.Size(); + int numTimers = globalTimers.Size(); tokenContainer->AddIntToken((int)eDMTimersIT::numtimers, numTimers); - tokenContainer->AddIntToken((int)eDMTimersIT::numtimerconflicts, SortedTimers.NumTimerConfilicts()); + tokenContainer->AddIntToken((int)eDMTimersIT::numtimerconflicts, globalTimers.NumTimerConfilicts()); for (int i=0; i<15; i++) { if (i < numTimers) { tokenContainer->AddIntToken(i+2, true); @@ -391,8 +386,9 @@ bool cVeDmTimers::Parse(bool forced) { for (int i = 0; i < numTimers; i++) { if (i >=15) break; - const cTimer *Timer = SortedTimers[i]; - tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::isremotetimer, SortedTimers.IsRemoteTimer(i) ? "1" : "0"); + const cTimer *Timer = globalTimers[i]; + tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::isremotetimer, globalTimers.IsRemoteTimer(i) ? "1" : "0"); + tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::remotehost, globalTimers.RemoteHost(i)); const cEvent *event = Timer->Event(); if (event) { tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::title, event->Title()); @@ -434,8 +430,8 @@ bool cVeDmTimers::Parse(bool forced) { timerDate = cString::sprintf("VPS %s", *timerDate); } tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::datetime, *timerDate); - tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::isremotetimer, SortedTimers.IsRemoteTimer(i) ? "1" : "0"); } + SetDirty(); return true; } @@ -893,20 +889,12 @@ bool cVeDmLastrecordings::Parse(bool forced) { return false; tokenContainer->Clear(); - int numTimers = 0; - // BLOCK for LOCK_TIMERS_READ scope !! - { -#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) - LOCK_TIMERS_READ; - numTimers = Timers->Count(); -#else - numTimers = Timers.Count(); -#endif - } - - cGlobalSortedTimers SortedTimers(numTimers); // local and remote timers + + cGlobalTimers globalTimers; + globalTimers.LoadTimers(); + //set number of timers so that it is possible to adapt this viewelement accordingly - tokenContainer->AddIntToken((int)eDMLastrecordingsIT::numtimers, SortedTimers.Size()); + tokenContainer->AddIntToken((int)eDMLastrecordingsIT::numtimers, globalTimers.Size()); list orderedRecs; @@ -980,6 +968,7 @@ bool cVeDmLastrecordings::Parse(bool forced) { if (i == MAX_RECORDINGS) break; } + SetDirty(); return true; } diff --git a/extensions/globaltimers.c b/extensions/globaltimers.c new file mode 100644 index 0000000..6e7263e --- /dev/null +++ b/extensions/globaltimers.c @@ -0,0 +1,233 @@ +#include "globaltimers.h" +#include "../services/epgsearch.h" +#include "../services/remotetimers.h" +#include "../services/epgtimer.h" + +static int CompareTimers(const void *a, const void *b) { + return (*(const cTimer **)a)->Compare(**(const cTimer **)b); +} + +bool cGlobalTimers::initial = true; +cRemoteTimerRefresh *cGlobalTimers::remoteTimerRefresh = NULL; + +cGlobalTimers::cGlobalTimers(void) : cVector(0) { + pEpg2Vdr = cPluginManager::GetPlugin("epg2vdr"); + pRemoteTimers = cPluginManager::GetPlugin("remotetimers"); + pEpgSearch = cPluginManager::GetPlugin("epgsearch"); + localTimer = NULL; + isEpg2VdrTimers = false; +} + +cGlobalTimers::~cGlobalTimers(void) { + if (localTimer) { + delete[] localTimer; + } + ClearTimers(); +} + +void cGlobalTimers::LoadTimers(void) { + uint64_t start = cTimeMs::Now(); + isEpg2VdrTimers = false; + bool epg2vdrOk = false; + if (pEpg2Vdr) { + epg2vdrOk = SetEpg2VdrTimers(); + } + if (!epg2vdrOk) { + SetLocalTimers(); + if (pRemoteTimers) { + SetRemoteTimers(initial); + } + } + esyslog("skindesigner: loaded %d timers, needed %d ms", Size(), cTimeMs::Now() - start); + initial = false; +} + +void cGlobalTimers::SortTimers(void) { + Sort(CompareTimers); +} + +void cGlobalTimers::MarkLocalTimers(void) { + if (isEpg2VdrTimers) + return; + + if (localTimer) { + delete[] localTimer; + localTimer = NULL; + } +#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) + LOCK_TIMERS_READ; + const cTimers* timers = Timers; +#else + const cTimers* timers = &Timers; +#endif + int numTimers = Size(); + if (numTimers > 0) { + localTimer = new bool[numTimers]; + for (int i=0; i < numTimers; i++) { + if (!pRemoteTimers) { + localTimer[i] = true; + } else { + localTimer[i] = false; + for (const cTimer *Timer = timers->First(); Timer; Timer = timers->Next(Timer)) { + if (Timer == At(i)) { + localTimer[i] = true; + break; + } + } + } + } + } +} + +void cGlobalTimers::SetLocalTimers(void) { +#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) + LOCK_TIMERS_READ; + const cTimers* timers = Timers; +#else + const cTimers* timers = &Timers; +#endif + for (const cTimer *Timer = timers->First(); Timer; Timer = timers->Next(Timer)) { + if (Timer->HasFlags(tfActive)) + Append(Timer); + } +} + +void cGlobalTimers::SetRemoteTimers(bool initial) { + if (initial) { + cString errorMsg; + pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg); + } +#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) + LOCK_SCHEDULES_READ; + const cSchedules* schedules = Schedules; +#else + cSchedulesLock schedulesLock; + const cSchedules* schedules = (cSchedules*)cSchedules::Schedules(schedulesLock); +#endif + cTimer* remoteTimer = NULL; + while (pRemoteTimers->Service("RemoteTimers::ForEach-v1.0", &remoteTimer) && remoteTimer != NULL) { + remoteTimer->SetEventFromSchedule(schedules); // make sure the event is current + if (remoteTimer->HasFlags(tfActive)) + Append(remoteTimer); + } +} + +bool cGlobalTimers::SetEpg2VdrTimers(void) { + bool ok = false; + cEpgTimer_Service_V1 data; + if (pEpg2Vdr->Service(EPG2VDR_TIMER_SERVICE, &data)) { + for (std::list::iterator it = data.epgTimers.begin(); it != data.epgTimers.end(); ++it) { + ok = true; + isEpg2VdrTimers = true; + if ((*it)->HasFlags(tfActive)) { + Append(*it); + } + } + } + return ok; +} + +int cGlobalTimers::NumTimerConfilicts(void) { + int numConflicts = 0; + if (pEpgSearch) { + Epgsearch_lastconflictinfo_v1_0 *serviceData = new Epgsearch_lastconflictinfo_v1_0; + if (serviceData) { + serviceData->nextConflict = 0; + serviceData->relevantConflicts = 0; + serviceData->totalConflicts = 0; + pEpgSearch->Service("Epgsearch-lastconflictinfo-v1.0", serviceData); + if (serviceData->relevantConflicts > 0) { + numConflicts = serviceData->relevantConflicts; + } + delete serviceData; + } + } + return numConflicts; +} + +bool cGlobalTimers::IsRemoteTimer(int i) { + if (isEpg2VdrTimers) { + cEpgTimer_Interface_V1* epgTimer; + if (epgTimer = dynamic_cast((cTimer*)At(i))) + return !epgTimer->isLocal(); + else + return false; + } + if (!localTimer) + return true; + if (i >= Size()) + return true; + return !(localTimer[i]); +} + +const char* cGlobalTimers::RemoteHost(int i) { + if (isEpg2VdrTimers) { + cEpgTimer_Interface_V1* epgTimer; + if (epgTimer = dynamic_cast((cTimer*)At(i))) + return epgTimer->VdrName(); + } + return ""; +} + +void cGlobalTimers::ClearTimers(void) { + if (isEpg2VdrTimers) { + int size = Size(); + for (int i=0; iService("RemoteTimers::RefreshTimers-v1.0", &errorMsg); +#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) + LOCK_TIMERS_WRITE; + Timers->SetModified(); +#else + Timers.SetModified(); +#endif + } + } +} diff --git a/extensions/globaltimers.h b/extensions/globaltimers.h new file mode 100644 index 0000000..9f722d8 --- /dev/null +++ b/extensions/globaltimers.h @@ -0,0 +1,44 @@ +#ifndef __GLOBALTIMERS_H +#define __GLOBALTIMERS_H + +#include +#include + +class cRemoteTimerRefresh; + +class cGlobalTimers : public cVector { + private: + static bool initial; + static cRemoteTimerRefresh *remoteTimerRefresh; + bool *localTimer; + cPlugin *pEpg2Vdr; + cPlugin *pRemoteTimers; + cPlugin *pEpgSearch; + bool isEpg2VdrTimers; + void SetLocalTimers(void); + void SetRemoteTimers(bool initial); + bool SetEpg2VdrTimers(void); + public: + cGlobalTimers(void); + virtual ~cGlobalTimers(void); + void LoadTimers(void); + void SortTimers(void); + void MarkLocalTimers(void); + int NumTimerConfilicts(void); + bool IsRemoteTimer(int i); + const char* RemoteHost(int i); + void ClearTimers(void); + static void StartRefreshThread(void); + static void StopRefreshThread(void); +}; + +class cRemoteTimerRefresh: public cThread { + private: + cPlugin* pRemoteTimers; + protected: + virtual void Action(void); + public: + cRemoteTimerRefresh(void); + virtual ~cRemoteTimerRefresh(void); +}; +#endif //__GLOBALTIMERS_H diff --git a/extensions/timers.c b/extensions/timers.c deleted file mode 100644 index 4f81b2a..0000000 --- a/extensions/timers.c +++ /dev/null @@ -1,134 +0,0 @@ -#include "timers.h" -#include "../services/epgsearch.h" -#include "../services/remotetimers.h" - -static int CompareTimers(const void *a, const void *b) { - return (*(const cTimer **)a)->Compare(**(const cTimer **)b); -} - -cGlobalSortedTimers::cGlobalSortedTimers(int timerCount, bool forceRefresh) : cVector(timerCount) { - static bool initial = true; - static cRemoteTimerRefresh *remoteTimerRefresh = NULL; - localTimer = NULL; - - if (forceRefresh) - initial = true; - //check if remotetimers plugin is available - static cPlugin* pRemoteTimers = cPluginManager::GetPlugin("remotetimers"); - -#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) - LOCK_TIMERS_READ; - LOCK_SCHEDULES_READ; - const cTimers* timers = Timers; - const cSchedules* schedules = Schedules; -#else - const cTimers* timers = &Timers; - cSchedulesLock schedulesLock; - const cSchedules* schedules = (cSchedules*)cSchedules::Schedules(schedulesLock); -#endif - - if (pRemoteTimers && initial) { - cString errorMsg; - pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg); - initial = false; - } - - for (const cTimer *Timer = timers->First(); Timer; Timer = timers->Next(Timer)) { - if (Timer->HasFlags(tfActive)) - Append(Timer); - } - - //if remotetimers plugin is available, take timers also from him - if (pRemoteTimers) { - cTimer* remoteTimer = NULL; - while (pRemoteTimers->Service("RemoteTimers::ForEach-v1.0", &remoteTimer) && remoteTimer != NULL) { - remoteTimer->SetEventFromSchedule(schedules); // make sure the event is current - if (remoteTimer->HasFlags(tfActive)) - Append(remoteTimer); - } - } - - Sort(CompareTimers); - - int numTimers = Size(); - if (numTimers > 0) { - localTimer = new bool[numTimers]; - for (int i=0; i < numTimers; i++) { - if (!pRemoteTimers) { - localTimer[i] = true; - } else { - localTimer[i] = false; - for (const cTimer *Timer = timers->First(); Timer; Timer = timers->Next(Timer)) { - if (Timer == At(i)) { - localTimer[i] = true; - break; - } - } - } - } - } - - if (pRemoteTimers && (remoteTimerRefresh == NULL)) - remoteTimerRefresh = new cRemoteTimerRefresh(); -} - -cGlobalSortedTimers::~cGlobalSortedTimers(void) { - if (localTimer) { - delete[] localTimer; - } -} - -bool cGlobalSortedTimers::IsRemoteTimer(int i) { - if (!localTimer) - return true; - if (i >= Size()) - return true; - return !(localTimer[i]); -} - - -int cGlobalSortedTimers::NumTimerConfilicts(void) { - int numConflicts = 0; - cPlugin *p = cPluginManager::GetPlugin("epgsearch"); - if (p) { - Epgsearch_lastconflictinfo_v1_0 *serviceData = new Epgsearch_lastconflictinfo_v1_0; - if (serviceData) { - serviceData->nextConflict = 0; - serviceData->relevantConflicts = 0; - serviceData->totalConflicts = 0; - p->Service("Epgsearch-lastconflictinfo-v1.0", serviceData); - if (serviceData->relevantConflicts > 0) { - numConflicts = serviceData->relevantConflicts; - } - delete serviceData; - } - } - return numConflicts; -} - -cRemoteTimerRefresh::cRemoteTimerRefresh(): cThread("skindesigner: RemoteTimers::RefreshTimers") { - Start(); -} - -cRemoteTimerRefresh::~cRemoteTimerRefresh(void) { - Cancel(-1); - while (Active()) - cCondWait::SleepMs(10); -} - -void cRemoteTimerRefresh::Action(void) { -#define REFESH_INTERVALL_MS 30000 - while (Running()) { - cCondWait::SleepMs(REFESH_INTERVALL_MS); - // make sure that no timer is currently being edited - if (!cOsd::IsOpen()) { - cGlobalSortedTimers(true); -#if defined (APIVERSNUM) && (APIVERSNUM >= 20301) - LOCK_TIMERS_WRITE; - Timers->SetModified(); -#else - Timers.SetModified(); -#endif - } - } -} diff --git a/extensions/timers.h b/extensions/timers.h deleted file mode 100644 index fdbca31..0000000 --- a/extensions/timers.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __NOPACITY_TIMERS_H -#define __NOPACITY_TIMERS_H - -#include -#include - -class cGlobalSortedTimers : public cVector { - private: - bool *localTimer; - public: - cGlobalSortedTimers(int timerCount, bool forceRefresh = false); - virtual ~cGlobalSortedTimers(void); - bool IsRemoteTimer(int i); - int NumTimerConfilicts(void); -}; - -class cRemoteTimerRefresh: public cThread { - protected: - virtual void Action(void); - public: - cRemoteTimerRefresh(void); - virtual ~cRemoteTimerRefresh(void); -}; -#endif //__NOPACITY_TIMERS_H diff --git a/services/epgtimer.h b/services/epgtimer.h new file mode 100644 index 0000000..89e318c --- /dev/null +++ b/services/epgtimer.h @@ -0,0 +1,121 @@ +/* + * service.h: EPG2VDR plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef _SERVICE_H_ +#define _SERVICE_H_ + +#include +#include + +#include + +//*************************************************************************** +// Timer - Skin Interface +//*************************************************************************** + +class cEpgEvent_Interface_V1 : public cEvent +{ + public: + + cEpgEvent_Interface_V1(tEventID EventID) + : cEvent(EventID) {} + + // #TODO ... getter + + protected: + + // #TODO ... attributes +}; + +//*************************************************************************** +// Timer - Skin Interface +//*************************************************************************** + +class cEpgTimer_Interface_V1 : public cTimer +{ + public: + + cEpgTimer_Interface_V1(bool Instant = false, bool Pause = false, cChannel* Channel = 0) + : cTimer(Instant, Pause, Channel) {} + + long TimerId() { return timerid; } + long EventId() { return eventid; } + const char* VdrName() { return vdrName ? vdrName : ""; } + const char* VdrUuid() { return vdrUuid ? vdrUuid : ""; } + int isVdrRunning() { return vdrRunning; } + int isLocal() { return local; } + int isRemote() { return !isLocal(); } + + char State() { return state; } + const char* StateInfo() { return stateInfo ? stateInfo : ""; } + char Action() { return action; } + + protected: + + long timerid; + long eventid; + + char* vdrName; + char* vdrUuid; + int local; + int vdrRunning; + + char state; + char* stateInfo; + char action; +}; + +//*************************************************************************** +// Timer - Service Interface +//*************************************************************************** + +struct cEpgTimer_Service_V1 +{ + std::list epgTimers; +}; + +#define EPG2VDR_TIMER_SERVICE "Epg2Vdr_Timer_Service-v1.0" + +#ifdef EPG2VDR + +//*************************************************************************** +// Class cEpgEvent +//*************************************************************************** + +class cEpgEvent : public cEpgEvent_Interface_V1 +{ + public: + + cEpgEvent(tEventID EventID); + virtual ~cEpgEvent() {} + + // #TODO ... setter +}; + +//*************************************************************************** +// Class cEpgTimer +//*************************************************************************** + +class cEpgTimer : public cEpgTimer_Interface_V1 +{ + public: + + cEpgTimer(bool Instant = false, bool Pause = false, cChannel* Channel = 0); + virtual ~cEpgTimer(); + + void setTimerId(long id) { timerid = id; } + void setEventId(long id) { eventid = id; } + void setState(char s, const char* info); + void setAction(char a); + void setVdr(const char* name, const char* uuid = 0, int running = 0); +}; + +#endif // EPG2VDR + +//*************************************************************************** + +#endif // _SERVICE_H_ diff --git a/skindesigner.c b/skindesigner.c index 83aa288..56c97b9 100644 --- a/skindesigner.c +++ b/skindesigner.c @@ -13,6 +13,7 @@ #include "designer.h" #include "setup.h" #include "libskindesignerapi/skindesignerapi.h" +#include "extensions/globaltimers.h" #if defined(APIVERSNUM) && APIVERSNUM < 20200 #error "VDR-2.2.0 API version or greater is required!" @@ -111,6 +112,7 @@ bool cPluginSkinDesigner::Initialize(void) { bool cPluginSkinDesigner::Start(void) { cXmlParser::InitLibXML(); cImageImporterSVG::InitLibRSVG(); + cGlobalTimers::StartRefreshThread(); bool trueColorAvailable = true; if (!cOsdProvider::SupportsTrueColor()) { @@ -164,6 +166,7 @@ void cPluginSkinDesigner::Stop(void) { delete fontManager; delete plgManager; cXmlParser::CleanupLibXML(); + cGlobalTimers::StopRefreshThread(); } void cPluginSkinDesigner::Housekeeping(void) { diff --git a/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer.svg b/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer.svg new file mode 100644 index 0000000..4e1f43a --- /dev/null +++ b/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer.svg @@ -0,0 +1,89 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer_active.svg b/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer_active.svg new file mode 100644 index 0000000..cb25723 --- /dev/null +++ b/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer_active.svg @@ -0,0 +1,89 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/skins/estuary4vdr/xmlfiles/displaymenumain.xml b/skins/estuary4vdr/xmlfiles/displaymenumain.xml index ef9b362..d6f0b67 100644 --- a/skins/estuary4vdr/xmlfiles/displaymenumain.xml +++ b/skins/estuary4vdr/xmlfiles/displaymenumain.xml @@ -38,7 +38,9 @@ - + + + diff --git a/skins/estuary4vdr/xmlfiles/displaymenutimers.xml b/skins/estuary4vdr/xmlfiles/displaymenutimers.xml index e25ff90..dada8c8 100644 --- a/skins/estuary4vdr/xmlfiles/displaymenutimers.xml +++ b/skins/estuary4vdr/xmlfiles/displaymenutimers.xml @@ -31,6 +31,8 @@ + + diff --git a/skinskeleton/xmlfiles/displaymenumain.xml b/skinskeleton/xmlfiles/displaymenumain.xml index eecf94a..a0a3284 100644 --- a/skinskeleton/xmlfiles/displaymenumain.xml +++ b/skinskeleton/xmlfiles/displaymenumain.xml @@ -15,7 +15,8 @@ {timers[channelnumber]} number of channel {timers[channelid]} ChannelID of channel {timers[channellogoexists]} true if channel logo exists - {timers[isremotetimer]} true if timer is a remote timer from remotetimers plugin + {timers[isremotetimer]} true if timer is a remote timer from remotetimers or epg2vdr plugin + {timers[remotehost]} name of host on which timer is set. only for epg2vdr timers available --> diff --git a/skinskeleton/xmlfiles/displaymenutimers.xml b/skinskeleton/xmlfiles/displaymenutimers.xml index 7889572..42aa090 100644 --- a/skinskeleton/xmlfiles/displaymenutimers.xml +++ b/skinskeleton/xmlfiles/displaymenutimers.xml @@ -23,6 +23,12 @@ {flagvps} true if timer uses VPS {flagrecording} true if is recording currently {flagpending} true if timer is pending + {isremote} true if timer is a epg2vdr remote timer + {vdrname} name of vdr on which epg2vdr timer is located + {isvdrrunning} true if vdr on which epg2vdr timer is located is running + {action} action of epg2vdr timer + {state} state of epg2vdr timer + {stateinfo} stateinfo of epg2vdr timer -->