epgsearch-1.0.1.beta3/0000755000175000017500000000000012112105535013474 5ustar winniwinniepgsearch-1.0.1.beta3/epgsearchtools.h0000644000175000017500000002166412112105236016676 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __EPGSEARCH_TOOLS_INC__ #define __EPGSEARCH_TOOLS_INC__ #include #include // For VDRVERSNUM only #include "epgsearchext.h" #include "recdone.h" using std::string; #if VDRVERSNUM < 10733 #define eTimerMatch int #endif #define MAXPARSEBUFFER KILOBYTE(10) #undef CHANNELNAME #define CHANNELNAME(x) (x ? x->ShortName(true) : "") #undef TIMESTRING #define TIMESTRING(x) *(TimeString(x)) #undef DATESTRING #define DATESTRING(x) *(DateString(x)) #undef GETDATESTRING #define GETDATESTRING(x) *(x->GetDateString()) #undef GETTIMESTRING #define GETTIMESTRING(x) *(x->GetTimeString()) #undef PRINTDAY #define PRINTDAY *cTimer::PrintDay #undef DAYDATETIME #define DAYDATETIME(x) *DayDateTime(x) #undef CHANNELSTRING #define CHANNELSTRING(x) (*x->GetChannelID().ToString()) #undef WEEKDAYNAME #define WEEKDAYNAME(x) (*WeekDayName(x)) #undef ADDDIR #define ADDDIR *AddDirectory #undef CONFIGDIR #define CONFIGDIR (!ConfigDir?cPlugin::ConfigDirectory():ConfigDir) #define CHNUMWIDTH (numdigits(Channels.MaxNumber()) + 2) #define SHORTTEXT(EVENT) \ (EVENT && EPGSearchConfig.showShortText && !isempty((EVENT)->ShortText()))?" ~ ":"", \ (EVENT && EPGSearchConfig.showShortText && !isempty((EVENT)->ShortText()))?(EVENT)->ShortText():"" #define ISRADIO(x) ((x)->Vpid()==0||(x)->Vpid()==1||(x)->Vpid()==0x1fff) #ifndef MENU_SEPARATOR_ITEMS #define MENU_SEPARATOR_ITEMS "----------------------------------------" #endif #define UPDS_WITH_OSD (1<<1) #define UPDS_WITH_EPGSCAN (1<<2) // Icons used in VDRSymbols-Font #define ICON_REC 0x8B #define ICON_RUNNING 0x92 #define ICON_CLOCK 0x8C #define ICON_CLOCK_HALF 0x94 #define ICON_BAR_OPEN 0x87 #define ICON_BAR_FULL 0x88 #define ICON_BAR_EMPTY 0x89 #define ICON_BAR_CLOSE 0x8A #define ICON_VPS 0x93 // UTF-8 Icons #define ICON_BAR_OPEN_UTF8 "\uE007" #define ICON_BAR_FULL_UTF8 "\uE008" #define ICON_BAR_EMPTY_UTF8 "\uE009" #define ICON_BAR_CLOSE_UTF8 "\uE00A" #define ICON_REC_UTF8 "\uE00B" #define ICON_CLOCK_UTF8 "\uE00C" #define ICON_CLOCK_HALF_UTF8 "\uE014" #define ICON_RUNNING_UTF8 "\uE012" #define ICON_VPS_UTF8 "\uE013" #define CONTENT_DESCRIPTOR_MAX 255 #define ERROR(T) Skins.Message(mtError, T) #define INFO(I) Skins.Message(mtInfo, I) extern const char AllowedChars[]; extern char* ConfigDir; // Helper functions class cSearchExt; class cSearchExtCat; class cEvent; cString IndentMenuItem(const char*, int indentions=1); bool MatchesSearchMode(const char* test, const char* values, int searchmode, const char* delim, int tolerance); char* GetExtEPGValue(const cEvent* e, cSearchExtCat* SearchExtCat); char* GetExtEPGValue(const char* description, const char* catname, const char *format); char* GetAuxValue(const char* aux, const char* name); char* GetAuxValue(const cRecording *recording, const char* name); char* GetAuxValue(const cTimer* timer, const char* name); string UpdateAuxValue(string aux, string section, string value); string UpdateAuxValue(string aux, string section, long num); void ToLower(char* szText); char *strreplacei(char *s, const char *s1, const char *s2); std::string strreplace(std::string& result, const std::string& replaceWhat, const std::string& replaceWithWhat); // replace s1 with s2 in s ignoring the case of s1 inline char *strreplacei(char *s, const char *s1, const char s2) { char *p = strcasestr(s, s1); if (p) { int offset = p - s; int l = strlen(s); int l1 = strlen(s1); memmove(s + offset + 1, s + offset + l1, l - offset - l1 + 1); s[offset] = s2; } return s; } void sleepMSec(long ms); void sleepSec(long s); bool SendViaSVDRP(cString SVDRPcmd); int SendMsg(cString Message, bool confirm = false, int seconds = 0, eMessageType messageType = mtInfo); bool InEditMode(const char* ItemText, const char* ItemName, const char* ItemValue); cSearchExt* TriggeredFromSearchTimer(const cTimer* timer); int TriggeredFromSearchTimerID(const cTimer* timer); double FuzzyMatch(const char* s1, const char* s2, int maxLength); bool DescriptionMatches(const char* eDescr, const char* rDescr, int matchLimit = 90); const cEvent* GetEvent(cTimer* timer); char* GetRawDescription(const char* descr); void PrepareTimerFile(const cEvent* event, cTimer* timer); int CompareEventTime(const void *p1, const void *p2); int CompareEventChannel(const void *p1, const void *p2); int CompareSearchExtPrioDescTerm(const void *p1, const void *p2); bool EventsMatch(const cEvent* event1, const cEvent* event2, bool compareTitle, int compareSubtitle, bool compareSummary, int compareDate, unsigned long catvaluesAvoidRepeat, int matchLimit=90); int ChannelNrFromEvent(const cEvent* pEvent); void DelTimer(int index); char* FixSeparators(char* buffer, char sep); cString DateTime(time_t t); string NumToString(long l); int FindIgnoreCase(const string& expr, const string& query); bool EqualsNoCase(const string& a, const string& b); string Strip(const string& input); string ReplaceAll(const string& input, const string& what, const string& with); string GetAlNum(const string& s); string EscapeString(const string& S); string QuoteApostroph(const string& S); string MD5(const string& input); time_t GetDateTime(time_t day, int start); void SetAux(cTimer* timer, string aux); int msprintf(char **strp, const char *fmt, ...); std::string GetCodeset(); ssize_t Readline(int sockd, char *vptr, size_t maxlen); ssize_t Writeline(int sockd, const char *vptr, ssize_t n); long getAddrFromString(const char* hostnameOrIp, struct sockaddr_in* addr); // --- cTimerObj -------------------------------------------------------- class cTimerObj : public cListObject { public: cTimer* timer; cTimerObj(cTimer* Timer) : timer(Timer) {} virtual ~cTimerObj() { timer = NULL; } // do not delete anything! }; // --- cTimerObjList -------------------------------------------------------- class cTimerObjList : public cList { public: void DelTimer(cTimer* t) { for (cTimerObj* pTObj = First(); pTObj; pTObj = Next(pTObj)) if (pTObj->timer == t) { Del(pTObj); return; } } }; // --- icstring ------------------------------------------ // a case-insensitive string class struct ignorecase_traits : public std:: #if defined(__GNUC__) && __GNUC__ < 3 && __GNUC_MINOR__ < 96 string_char_traits #else char_traits #endif { // return whether c1 and c2 are equal static bool eq(const char& c1, const char& c2) { return (c1==c2 || std::toupper(c1)==std::toupper(c2)); } // return whether c1 is less than c2 static bool lt(const char& c1, const char& c2) { return std::toupper(c1) icstring; // --- eTimerMod ------------------------------------------------------------- enum eTimerMod { tmNoChange=0, tmStartStop=1, tmFile=2, tmAuxEventID=4 }; #if VDRVERSNUM >= 10712 // --- cCommands ------------------------------------------------------------------- class cCommand : public cListObject { private: char *title; char *command; bool confirm; static char *result; public: cCommand(void); virtual ~cCommand(); bool Parse(const char *s); const char *Title(void) { return title; } bool Confirm(void) { return confirm; } const char *Execute(const char *Parameters = NULL); }; class cCommands : public cConfig {}; #endif #endif epgsearch-1.0.1.beta3/timerstatus.h0000644000175000017500000000264412112105236016235 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #if APIVERSNUM < 10515 enum eTimerChange { tcMod, tcAdd, tcDel }; #endif class cTimerStatusMonitor : public cStatus { bool conflictCheckAdvised; protected: virtual void TimerChange(const cTimer *Timer, eTimerChange Change); public: cTimerStatusMonitor(); void SetConflictCheckAdvised(bool ConflictCheckAdvised = true); bool ConflictCheckAdvised(); }; extern cTimerStatusMonitor* gl_timerStatusMonitor; epgsearch-1.0.1.beta3/noannounce.h0000644000175000017500000000412712112105236016012 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __NOANNOUCE_H #define __NOANNOUCE_H #include #include using std::string; // --- cNoAnnouce -------------------------------------------------------- // an event that should not be announced again class cNoAnnounce : public cListObject { public: string title; // Title of this event string shortText; // Short description of this event time_t startTime; // Start time of the timer time_t nextAnnounce; // time of the next announce tChannelID channelID; static char *buffer; cNoAnnounce(); cNoAnnounce(const cEvent* Event, time_t NextAnnounce = 0); ~cNoAnnounce(); bool operator== (const cNoAnnounce &arg) const; static bool Read(FILE *f); bool Parse(const char *s); const char *ToText(void) const; bool Save(FILE *f); bool Valid() { return startTime > 0; } }; class cNoAnnounces : public cConfig { public: cNoAnnounce* InList(const cEvent* e); void ClearOutdated(void); void UpdateNextAnnounce(const cEvent* e, time_t NextAnnounce); }; extern cNoAnnounces NoAnnounces; #endif epgsearch-1.0.1.beta3/searchtimer_thread.h0000644000175000017500000000546612112105236017513 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef VDR_SEARCHTIMER_THREAD_H #define VDR_SEARCHTIMER_THREAD_H #include #include "epgsearchext.h" #include "epgsearchtools.h" #include "mail.h" class cPluginEpgsearch; // --- cRecordingObj -------------------------------------------------------- class cRecordingObj : public cListObject { public: cRecording* recording; cSearchExt* search; public: cRecordingObj(cRecording* r, cSearchExt* s) : recording(r), search(s) {} ~cRecordingObj() { recording = NULL;} // do not delete anything! }; // --- cSearchTimerThread---------------------------------------------------- class cSearchTimerThread: public cThread { private: bool m_Active; time_t m_lastUpdate; cPluginEpgsearch* m_plugin; cMailUpdateNotifier mailNotifier; cCondWait Wait; protected: virtual void Action(void); bool AddModTimer(cTimer* Timer, int, cSearchExt*, const cEvent*, int Prio, int Lifetime, char* Summary = NULL, uint timerMod = tmNoChange); void RemoveTimer(cTimer* Timer, const cEvent* Event = NULL); void Stop(void); bool NeedUpdate(); bool TimerWasModified(cTimer* t); public: static cSearchResults announceList; static char* SummaryExtended(cSearchExt* searchExt, cTimer* Timer, const cEvent* pEvent); static cSearchTimerThread *m_Instance; static cTimer* GetTimer(cSearchExt *searchExt, const cEvent *pEvent, bool& bTimesMatchExactly); static bool justRunning; cSearchTimerThread(cPluginEpgsearch* thePlugin); virtual ~cSearchTimerThread(); static void Init(cPluginEpgsearch* thePlugin, bool activatePermanently = false); static void Exit(void); void CheckExpiredRecs(); void DelRecording(int index); void CheckManualTimers(); void ModifyManualTimer(const cEvent* event, const cTimer* timer, int bstart, int bstop); void CheckEPGHours(); }; #endif epgsearch-1.0.1.beta3/menu_recsdone.h0000644000175000017500000000437012112105236016475 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __MENU_RECSDONE_H #define __MENU_RECSDONE_H #include "epgsearchext.h" #include "recdone.h" #include #include // --- cMenuRecDoneItem ---------------------------------------------------------- class cMenuRecDoneItem : public cOsdItem { public: cRecDone* recDone; bool showEpisodeOnly; cMenuRecDoneItem(cRecDone* RecDone, bool ShowEpisodeOnly = false); void Set(); int Compare(const cListObject &ListObject) const; }; // --- cMenuRecDone ---------------------------------------------------------- class cMenuRecsDone : public cOsdMenu { private: cSearchExt* search; eOSState Delete(void); eOSState DeleteAll(void); const char* ButtonBlue(cSearchExt* Search); int showMode; bool showEpisodeOnly; protected: void Set(); virtual eOSState ProcessKey(eKeys Key); void UpdateTitle(); eOSState Summary(void); cRecDone* CurrentRecDone(void); public: cMenuRecsDone(cSearchExt* search = NULL); }; // --- cMenuTextDone ---------------------------------------------------------- class cMenuTextDone : public cMenuText { cRecDone* recDone; public: cMenuTextDone(const char *Title, cRecDone* RecDone, eDvbFont Font = fontOsd); virtual eOSState ProcessKey(eKeys Key); }; #endif epgsearch-1.0.1.beta3/pending_notifications.c0000644000175000017500000001134112112105223020207 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include "pending_notifications.h" #include "epgsearchtools.h" cPendingNotifications PendingNotifications; char *cPendingNotification::buffer = NULL; // -- cPendingNotifications ----------------------------------------------------------------- cPendingNotification::~cPendingNotification(void) { if (buffer) { free(buffer); buffer = NULL; } } bool cPendingNotification::Parse(const char *s) { char *t = skipspace(s + 1); switch (*s) { case 'F': strreplace(t, '|', '\n'); formatted = strdup(t); break; default: LogFile.eSysLog("ERROR: unexpected tag while reading epgsearch pending notifications data: %s", s); return false; } return true; } bool cPendingNotification::Read(FILE *f) { cPendingNotification *p = NULL; char *s; cReadLine ReadLine; while ((s = ReadLine.Read(f)) != NULL) { char *t = skipspace(s + 1); switch (*s) { case 'N': if (!p) { tEventID EventID; int Type, TimerMod, SearchID; time_t Start; int n = sscanf(t, "%d %u %d %d %ld", &Type, &EventID, &TimerMod, &SearchID, &Start); if (n == 5) { p = new cPendingNotification; if (p) { p->type = Type; p->eventID = EventID; p->timerMod = TimerMod; p->searchID = SearchID; p->start = Start; PendingNotifications.Add(p); } } } break; case 'C': { s = skipspace(s + 1); char *pC = strchr(s, ' '); if (pC) *pC = 0; // strips optional channel name if (*s) { tChannelID channelID = tChannelID::FromString(s); if (channelID.Valid()) { if (p) p->channelID = channelID; } else { LogFile.Log(3, "ERROR: illegal channel ID: %s", s); return false; } } } break; case 'n': p = NULL; break; default: if (p && !p->Parse(s)) { LogFile.Log(1,"ERROR: parsing %s", s); return false; } } } return true; } const char *cPendingNotification::ToText(void) const { char* tmpFormatted = formatted!=""?strdup(formatted.c_str()):NULL; if (tmpFormatted) strreplace(tmpFormatted, '\n', '|'); if (buffer) free(buffer); buffer = NULL; cChannel *channel = Channels.GetByChannelID(channelID, true, true); if (!channel) LogFile.Log(3,"invalid channel in pending notifications!"); msprintf(&buffer, "N %d %u %d %d %ld\nC %s\n%s%s%sn", type, eventID, timerMod, searchID, start, channel?CHANNELSTRING(channel):"", tmpFormatted?"F ":"",tmpFormatted?tmpFormatted:"", tmpFormatted?"\n":""); if (tmpFormatted) free(tmpFormatted); return buffer; } bool cPendingNotification::Save(FILE *f) { return fprintf(f, "%s\n", ToText()) > 0; } bool cPendingNotifications::Load(const char *FileName) { Clear(); if (FileName) { free(fileName); fileName = strdup(FileName); } if (fileName && access(fileName, F_OK) == 0) { LogFile.iSysLog("loading %s", fileName); FILE *f = fopen(fileName, "r"); bool result = false; if (f) { result = cPendingNotification::Read(f); fclose(f); } if (result) LogFile.Log(2,"loaded pending notifications from %s (count: %d)", fileName, Count()); else LogFile.Log(1,"error loading pending notifications from %s (count: %d)", fileName, Count()); return result; } return false; } bool cPendingNotifications::Save(void) { bool result = true; cPendingNotification* l = (cPendingNotification*)this->First(); cSafeFile f(fileName); if (f.Open()) { while (l) { if (!l->Save(f)) { result = false; break; } l = (cPendingNotification*)l->Next(); } if (!f.Close()) result = false; } else result = false; LogFile.Log(2,"saved pending notifications (count: %d)", Count()); return result; } epgsearch-1.0.1.beta3/menu_dirselect.h0000644000175000017500000000417112112105236016650 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __EPGSEARCHDIRSELECT_H #define __EPGSEARCHDIRSELECT_H #include #include #include using std::string; using std::set; class cDirExt : public cListObject { private: char name[MaxFileName]; public: cDirExt(void){ name[0]=0; } bool Parse(const char *s) {strcpy(name,s); return true;} char* Name() {return name;} }; class cDirExts : public cConfig {}; class cConfDDirExts : public cList {}; extern cDirExts DirExts; extern cConfDDirExts ConfDDirExts; // --- cMenuDirSelect --------------------------------------------------------- class cMenuDirSelect : public cOsdMenu { private: int CurLevel; int MaxLevel; char* Directory; char* yellow; public: static set directorySet; cMenuDirSelect(char*); ~cMenuDirSelect(); void Load(); void AddDistinct(const char* szText); #if APIVERSNUM >= 10712 static void AddVDRFolders(cNestedItem* folder, string parentDirectory = ""); #endif virtual eOSState ProcessKey(eKeys Key); int Level(const char* szDir); void ReplaceDirVars(); static void CreateDirSet(bool extraDirs=true); }; #endif epgsearch-1.0.1.beta3/recdone.h0000644000175000017500000000522312112105236015264 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __RECDONE_H #define __RECDONE_H #include #include #include #include "epgsearchext.h" class cSearchExt; // --- cRecDone -------------------------------------------------------- class cRecDone : public cListObject { public: char *title; // Title of this event char *shortText; // Short description of this event char *description; // Description of this event char *aux; // Aux info time_t startTime; // Start time of the timer int duration; int searchID; // ID of the search, that triggered this recording tChannelID channelID; char* rawdescription; static char *buffer; cRecDone(); cRecDone(cTimer*, const cEvent* event, cSearchExt* search); ~cRecDone(); static bool Read(FILE *f); bool Parse(char *s); const char *ToText(void); bool Save(FILE *f); int ChannelNr(); }; class cRecsDone : public cList, public cMutex { private: char *fileName; public: void Clear(void) { free(fileName); fileName = NULL; cList::Clear(); } cRecsDone(void) { fileName = NULL; } int GetCountRecordings(const cEvent* event, cSearchExt* search, cRecDone** first = NULL, int matchLimit = 90); int GetCountRecordings(const cEvent*, bool compareTitle, int compareSubtitle, bool compareSummary, int compareDate, unsigned long, cRecDone** first = NULL, int matchLimit = 90); int GetTotalCountRecordings(cSearchExt* search, cRecDone** first); void RemoveSearchID(int ID); bool Load(const char *FileName = NULL); bool Save(void); }; extern cRecsDone RecsDone; #endif epgsearch-1.0.1.beta3/main.c0000644000175000017500000000335112112105223014560 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ // The functions contained in this file are pretty dummy // and are included only as a placeholder. Nevertheless, // they *will* get included in the static library if you // don't remove them :) // // Obviously, you 'll have to write yourself the super-duper // functions to include in the resulting library... // Also, it's not necessary to write every function in this file. // Feel free to add more files in this project. They will be // included in the resulting library. // A function adding two integers and returning the result int SampleAddInt(int i1, int i2) { return i1 + i2; } // A function doing nothing ;) void SampleFunction1() { // insert code here } // A function always returning zero int SampleFunction2() { // insert code here return 0; } epgsearch-1.0.1.beta3/menu_main.h0000644000175000017500000000400512112105236015612 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __EPGSEARCH_MENUMAIN_H #define __EPGSEARCH_MENUMAIN_H #include #include "menu_event.h" // --- cMenuSearchMain --------------------------------------------------------- class cMenuSearchMain : public cOsdMenu { private: int helpKeys; cSchedulesLock schedulesLock; const cSchedules *schedules; int otherChannel; int currentChannel; eOSState Record(void); eOSState ExtendedSearch(void); void PrepareSchedule(cChannel *Channel); eOSState Commands(eKeys Key); void SetHelpKeys(bool Force = false); int GetTab(int Tab); int shiftTime; bool InWhatsOnMenu; bool InFavoritesMenu; cEventObjects eventObjects; public: cMenuSearchMain(void); virtual ~cMenuSearchMain(); virtual eOSState ProcessKey(eKeys Key); eOSState Switch(void); eOSState Shift(int iMinutes); eOSState ShowSummary(); bool Update(void); void UpdateCurrent(); #ifdef USE_GRAPHTFT virtual const char* MenuKind() { return "MenuEpgsSchedule"; } virtual void Display(void); #endif static int forceMenu; }; #endif epgsearch-1.0.1.beta3/menu_searchresults.h0000644000175000017500000001172612112105236017565 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __EPGSEARCHRES_H #define __EPGSEARCHRES_H #include #include #include "templatefile.h" #include "epgsearchext.h" #include "menu_event.h" typedef enum { showTitleEpisode, showEpisode } ModeYellowSR; typedef enum { showAll, showNoPayTV, showTimerPreview } ModeBlueSR; // --- cMenuSearchResultsItem ------------------------------------------------------ class cMenuSearchResultsItem : public cOsdItem { char *fileName; // for search in recordings bool previewTimer; bool episodeOnly; cMenuTemplate* menuTemplate; public: eTimerMatch timerMatch; bool inSwitchList; const cEvent *event; const cSearchExt* search; const char *FileName(void) { return fileName; } cMenuSearchResultsItem(const cEvent *EventInfo, bool EpisodeOnly = false, bool PreviewTimer = false, cMenuTemplate* MenuTemplate = NULL, const cSearchExt* Search = NULL); cMenuSearchResultsItem(cRecording *Recording); bool Update(bool Force = false); void SetMenuItem(cSkinDisplayMenu *DisplayMenu, int Index, bool Current, bool Selectable); }; // --- cMenuSearchResults ------------------------------------------------------ class cMenuSearchResults : public cOsdMenu { friend class cMenuFavorites; protected: int helpKeys; cMenuTemplate* menuTemplate; bool ignoreRunning; cEventObjects eventObjects; virtual bool BuildList()=0; virtual eOSState ProcessKey(eKeys Key); eOSState ShowSummary(void); virtual eOSState OnRed(cSearchExt* searchExt = NULL); virtual eOSState OnGreen(); virtual eOSState OnYellow(); eOSState Record(void); eOSState Switch(void); eOSState Commands(eKeys Key, cSearchExt* SearchExt = NULL); int GetTab(int Tab); virtual void SetHelpKeys(bool Force=false)=0; bool Update(void); void UpdateCurrent(); static const cEvent *scheduleEventInfo; ModeYellowSR modeYellow; ModeBlueSR modeBlue; public: bool m_bSort; cMenuSearchResults(cMenuTemplate* MenuTemplate); }; // --- cMenuSearchResultsForSearch ------------------------------------------------------ class cMenuSearchResultsForSearch : public cMenuSearchResults { protected: cSearchExt* searchExt; virtual bool BuildList(); virtual void SetHelpKeys(bool Force=false); eOSState ProcessKey(eKeys Key); public: cMenuSearchResultsForSearch(cSearchExt*, cMenuTemplate* MenuTemplate); virtual ~cMenuSearchResultsForSearch() {} }; class cBlacklist; // --- cMenuSearchResultsForBlacklist ------------------------------------------------------ class cMenuSearchResultsForBlacklist : public cMenuSearchResults { cBlacklist* blacklist; virtual bool BuildList(); virtual void SetHelpKeys(bool Force=false); eOSState ProcessKey(eKeys Key); public: cMenuSearchResultsForBlacklist(cBlacklist*); }; // --- cMenuSearchResultsForQuery ------------------------------------------------------ class cMenuSearchResultsForQuery : public cMenuSearchResultsForSearch { public: cMenuSearchResultsForQuery(const char *query, bool IgnoreRunning = false); ~cMenuSearchResultsForQuery(); virtual bool BuildList(); }; // --- cMenuSearchResultsForRecs ------------------------------------------------------ class cMenuSearchResultsForRecs : public cMenuSearchResultsForQuery { virtual bool BuildList(); eOSState ProcessKey(eKeys Key); eOSState Play(void); cRecording *GetRecording(cMenuSearchResultsItem *Item); public: cMenuSearchResultsForRecs(const char *query); }; // --- cMenuSearchResultsForList ------------------------------------------------------ class cMenuSearchResultsForList : public cMenuSearchResults { protected: cSearchResults* searchResults; virtual bool BuildList(); virtual void SetHelpKeys(bool Force=false); virtual eOSState ProcessKey(eKeys Key); public: cMenuSearchResultsForList(cSearchResults& SearchResults, const char* Title, bool IgnoreRunning = false); }; #endif epgsearch-1.0.1.beta3/epgsearchcfg.c0000644000175000017500000000750112112105223016256 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include "epgsearchcfg.h" #include "epgsearchtools.h" cEPGSearchConfig EPGSearchConfig; cEPGSearchConfig::cEPGSearchConfig(void) { hidemenu = 0; redkeymode = 0; bluekeymode = 1; showProgress = 1; showChannelNr = 0; useSearchTimers = 0; UpdateIntervall = 30; #if APIVERSNUM >= 10715 SVDRPPort = 6419; #else SVDRPPort = 2001; #endif timeShiftValue = 30; toggleGreenYellow = 1; StartMenu = 0; DefPriority = Setup.DefaultPriority; DefLifetime = Setup.DefaultLifetime; DefMarginStart = Setup.MarginStart; DefMarginStop = Setup.MarginStop; checkTimerConflictsAfterUpdate = 0; checkMinPriority = 0; checkMinDuration = 0; checkMaxDays = 14; ignorePayTV = 0; useExternalSVDRP = 0; ignorePrimary = 0; strcpy(defrecdir,""); useVDRTimerEditMenu = 0; showChannelGroups = 0; showDaySeparators = 0; showEmptyChannels = 0; DefSearchTemplateID = -1; addSubtitleToTimer = addSubtitleSmart; strcpy(mainmenuentry, ""); WarEagle = 0; showRadioChannels = 1; onePressTimerCreation = 1; conflictCheckIntervall = 30; conflictCheckWithinLimit = 60; conflictCheckIntervall2 = 15; checkTimerConflAfterTimerProg = 0; checkTimerConflOnRecording = 0; showFavoritesMenu = 0; FavoritesMenuTimespan = 24; useOkForSwitch = 0; strcpy(MailAddress, ""); strcpy(MailAddressTo, ""); strcpy(MailServer, ""); MailUseAuth = 0; strcpy(MailAuthUser, ""); strcpy(MailAuthPass, ""); strcpy(LastMailConflicts, ""); mailViaScript = 1; manualTimerCheckDefault = 0; noAnnounceWhileReplay = 0; TimerProgRepeat = 0; maxChannelMenuNow = 0; noConflMsgWhileReplay = 0; sendMailOnSearchtimerHours = 0; lastMailOnSearchtimerAt = 0; checkEPGHours = 6; checkEPGWarnByOSD = 1; checkEPGWarnByMail = 0; checkEPGchannelGroupNr = -1; strcpy(conflCheckCmd, ""); ReplaceOrgSchedule = 0; sendMailOnSearchtimers = 0; sendMailOnConflicts = 0; } int cShowMode::Compare(const cListObject &ListObject) const { cShowMode *p = (cShowMode *)&ListObject; if (EPGSearchConfig.showFavoritesMenu == 1) { if (mode == showFavorites) { if (p->mode <= showNext) return 1; else return -1; } if (p->mode == showFavorites) { if (mode <= showNext) return -1; else return 1; } } if (EPGSearchConfig.showFavoritesMenu == 2) { if (mode == showFavorites && p->mode != showFavorites) return 1; if (p->mode == showFavorites && mode != showFavorites) return -1; } if (EPGSearchConfig.showFavoritesMenu == 3) { if (mode == showFavorites) { if (p->mode < showNext) return 1; else return -1; } if (p->mode == showFavorites) { if (mode < showNext) return -1; else return 1; } } if (mode > showNext && p->mode > showNext) return seekTime - p->seekTime; else return mode - p->mode; } epgsearch-1.0.1.beta3/INSTALL.DE0000644000175000017500000000200612100027260015005 0ustar winniwinniHier gibt es nichts besonderes. Bitte wie jedes andere Standard-Plugin installieren (entpacken, soft link, make plugins). Eine kleine Besonderheit: Wer lieber mit Perl compatible regular expressions in der Suche arbeitet, sollte einfach im Makefile des Plugins '#REGEXLIB = pcre' in 'REGEXLIB = pcre' ändern oder einfach REGEXLIB=pcre an den 'make plugins'-Aufruf anhängen. Hierzu muss pcreposix installiert sein, das in der libpcre von www.pcre.org enthalten ist. Dies sollte aber in den meisten Distributionen bereits enthalten sein. HINWEIS: wenn alles normal kompiliert, aber beim Start von VDR folgendes kommt: ERROR: /usr/lib/libpcreposix.so.0: undefined symbol: pcre_free). dann bitte libpcre von www.pcre.org updaten und das Plugin neu kompilieren. Scheinbar gibt es auf manchen Systemen Probleme mit PCRE, die sich in einem Crash äußern, wenn man reg. Ausdrücke benutzt. Da ich die Ursache bisher nicht finden konnte, empfehle ich deshalb auf REGEXLIB=pcre zu verzichten, wenn es nicht unbedingt notwendig ist. epgsearch-1.0.1.beta3/menu_main.c0000644000175000017500000003740312112105223015611 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include "menu_main.h" #include "menu_whatson.h" #include "menu_myedittimer.h" #include "epgsearchext.h" #include "menu_event.h" #include "menu_searchresults.h" #include "menu_search.h" #include "menu_commands.h" #include "epgsearchcfg.h" #include "epgsearchtools.h" #include #include "menu_conflictcheck.h" #include "menu_favorites.h" #include "menu_deftimercheckmethod.h" #include "timerstatus.h" int toggleKeys=0; int exitToMainMenu = 0; extern int gl_InfoConflict; int cMenuSearchMain::forceMenu = 0; // 1 = now, 2 = schedule, 3 = summary // --- cMenuSearchMain --------------------------------------------------------- cMenuSearchMain::cMenuSearchMain(void) :cOsdMenu("", GetTab(1), GetTab(2), GetTab(3), GetTab(4), GetTab(5)) { #if VDRVERSNUM >= 10734 SetMenuCategory(mcSchedule); #endif helpKeys = -1; otherChannel = 0; toggleKeys = 0; shiftTime = 0; InWhatsOnMenu = false; InFavoritesMenu = false; cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel()); schedules = cSchedules::Schedules(schedulesLock); if (channel) { cMenuWhatsOnSearch::SetCurrentChannel(channel->Number()); if (EPGSearchConfig.StartMenu == 0 || forceMenu != 0) PrepareSchedule(channel); SetHelpKeys(); cMenuWhatsOnSearch::currentShowMode = showNow; // timeb tnow; //ftime(&tnow); //isyslog("duration epgs sched: %d", tnow.millitm - gl_time.millitm + ((tnow.millitm - gl_time.millitm<0)?1000:0)); } if ((EPGSearchConfig.StartMenu == 1 || forceMenu == 1) && forceMenu != 2) { InWhatsOnMenu = true; AddSubMenu(new cMenuWhatsOnSearch(schedules, cDevice::CurrentChannel())); } if (forceMenu == 3) ShowSummary(); } #ifdef USE_GRAPHTFT void cMenuSearchMain::Display(void) { cOsdMenu::Display(); if (Count() > 0) { int i = 0; for (cOsdItem *item = First(); item; item = Next(item)) cStatus::MsgOsdEventItem(!item->Selectable() ? 0 : ((cMenuMyScheduleItem*)item)->event, item->Text(), i++, Count()); } } #endif /* GRAPHTFT */ cMenuSearchMain::~cMenuSearchMain() { cMenuWhatsOnSearch::ScheduleChannel(); // makes sure any posted data is cleared forceMenu = 0; } int cMenuSearchMain::GetTab(int Tab) { return cTemplFile::GetTemplateByName("MenuSchedule")->Tab(Tab-1); } void cMenuSearchMain::PrepareSchedule(cChannel *Channel) { Clear(); cString buffer = cString::sprintf("%s - %s", trVDR("Schedule"), Channel->Name()); SetTitle(buffer); cMenuTemplate* ScheduleTemplate = cTemplFile::GetTemplateByName("MenuSchedule"); eventObjects.Clear(); if (schedules) { const cSchedule *Schedule = schedules->GetSchedule(Channel); currentChannel = Channel->Number(); if (Schedule && Schedule->Events()->First()) { const cEvent *PresentEvent = Schedule->GetPresentEvent(); time_t now = time(NULL); now -= Setup.EPGLinger * 60; if (shiftTime != 0) PresentEvent = Schedule->GetEventAround(time(NULL) + shiftTime * 60); time_t lastEventDate = Schedule->Events()->First()->StartTime(); // timeb tstart; // ftime(&tstart); for (const cEvent *Event = Schedule->Events()->First(); Event; Event = Schedule->Events()->Next(Event)) { if (Event->EndTime() > now || (shiftTime==0 && Event == PresentEvent)) { if (EPGSearchConfig.showDaySeparators) { struct tm tm_rEvent; struct tm tm_rLastEvent; time_t EventDate = Event->StartTime(); struct tm *t_event = localtime_r(&EventDate, &tm_rEvent); struct tm *t_lastevent = localtime_r(&lastEventDate, &tm_rLastEvent); if (t_event->tm_mday != t_lastevent->tm_mday) Add(new cMenuMyScheduleSepItem(Event)); lastEventDate = EventDate; } Add(new cMenuMyScheduleItem(Event, NULL, showNow, ScheduleTemplate), Event == PresentEvent); eventObjects.Add(Event); } } // timeb tnow; // ftime(&tnow); // isyslog("duration epgs prepsched: %d (%d)", tnow.millitm - tstart.millitm + ((tnow.millitm - tstart.millitm<0)?1000:0), Count()); } } if (shiftTime) { cString buffer = cString::sprintf("%s (%s%dh %dm)", Channel->Name(), shiftTime>0?"+":"", shiftTime/60, abs(shiftTime)%60); SetTitle(buffer); } } bool cMenuSearchMain::Update(void) { bool result = false; for (cOsdItem *item = First(); item; item = Next(item)) { if (item->Selectable() && ((cMenuMyScheduleItem *)item)->Update()) result = true; } return result; } eOSState cMenuSearchMain::Record(void) { cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current()); if (item) { if (item->timerMatch == tmFull) { eTimerMatch tm = tmNone; cTimer *timer = Timers.GetMatch(item->event, &tm); if (timer) { if (EPGSearchConfig.useVDRTimerEditMenu) return AddSubMenu(new cMenuEditTimer(timer)); else return AddSubMenu(new cMenuMyEditTimer(timer, false, item->event, item->channel)); } } cTimer *timer = new cTimer(item->event); PrepareTimerFile(item->event, timer); cTimer *t = Timers.GetTimer(timer); if (EPGSearchConfig.onePressTimerCreation == 0 || t || !item->event || (!t && item->event && item->event->StartTime() - (Setup.MarginStart+2) * 60 < time(NULL))) { if (t) { delete timer; timer = t; } if (EPGSearchConfig.useVDRTimerEditMenu) return AddSubMenu(new cMenuEditTimer(timer, !t)); else return AddSubMenu(new cMenuMyEditTimer(timer, !t, item->event)); } else { string fullaux = ""; string aux = ""; if (item->event) { const cEvent* event = item->event; int bstart = event->StartTime() - timer->StartTime(); int bstop = timer->StopTime() - event->EndTime(); int checkmode = DefTimerCheckModes.GetMode(timer->Channel()); aux = UpdateAuxValue(aux, "channel", NumToString(timer->Channel()->Number()) + " - " + CHANNELNAME(timer->Channel())); aux = UpdateAuxValue(aux, "update", checkmode); aux = UpdateAuxValue(aux, "eventid", event->EventID()); aux = UpdateAuxValue(aux, "bstart", bstart); aux = UpdateAuxValue(aux, "bstop", bstop); fullaux = UpdateAuxValue(fullaux, "epgsearch", aux); } #ifdef USE_PINPLUGIN aux = ""; aux = UpdateAuxValue(aux, "protected", timer->FskProtection() ? "yes" : "no"); fullaux = UpdateAuxValue(fullaux, "pin-plugin", aux); #endif SetAux(timer, fullaux); Timers.Add(timer); gl_timerStatusMonitor->SetConflictCheckAdvised(); timer->Matches(); Timers.SetModified(); LogFile.iSysLog("timer %s added (active)", *timer->ToDescr()); if (HasSubMenu()) CloseSubMenu(); if (Update()) Display(); SetHelpKeys(); } } return osContinue; } eOSState cMenuSearchMain::Switch(void) { cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current()); if (item) { cChannel *channel = Channels.GetByChannelID(item->event->ChannelID(), true, true); if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true)) return osEnd; } INFO(trVDR("Can't switch channel!")); return osContinue; } eOSState cMenuSearchMain::ExtendedSearch(void) { return AddSubMenu(new cMenuEPGSearchExt()); } eOSState cMenuSearchMain::Commands(eKeys Key) { if (HasSubMenu() || Count() == 0) return osContinue; cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); if (mi && mi->event) { cMenuSearchCommands *menu; eOSState state = AddSubMenu(menu = new cMenuSearchCommands(tr("EPG Commands"), mi->event, true)); if (Key != kNone) state = menu->ProcessKey(Key); return state; } return osContinue; } eOSState cMenuSearchMain::ShowSummary() { if (Count()) { cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); if (mi && mi->event) return AddSubMenu(new cMenuEventSearch(mi->event, eventObjects, SurfModeTime)); } return osContinue; } void cMenuSearchMain::SetHelpKeys(bool Force) { cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)Get(Current()); int NewHelpKeys = 0; if (item) { if (item->Selectable() && item->timerMatch == tmFull) NewHelpKeys = 2; else NewHelpKeys = 1; } bool hasTimer = (NewHelpKeys == 2); if (NewHelpKeys != helpKeys || Force) { if (toggleKeys==0) SetHelp((EPGSearchConfig.redkeymode==0?(hasTimer?trVDR("Button$Timer"):trVDR("Button$Record")):tr("Button$Commands")), trVDR("Button$Now"), trVDR("Button$Next"), EPGSearchConfig.bluekeymode==0?trVDR("Button$Switch"):tr("Button$Search")); else { const char* szGreenToggled = CHANNELNAME(Channels.GetByNumber(currentChannel-1,-1)); const char* szYellowToggled = CHANNELNAME(Channels.GetByNumber(currentChannel+1,1)); SetHelp((EPGSearchConfig.redkeymode==1?(hasTimer?trVDR("Button$Timer"):trVDR("Button$Record")):tr("Button$Commands")), (EPGSearchConfig.toggleGreenYellow==0?trVDR("Button$Now"):szGreenToggled), (EPGSearchConfig.toggleGreenYellow==0?trVDR("Button$Next"):szYellowToggled), EPGSearchConfig.bluekeymode==1?trVDR("Button$Switch"):tr("Button$Search")); } helpKeys = NewHelpKeys; } } eOSState cMenuSearchMain::Shift(int iMinutes) { shiftTime += iMinutes; cChannel *channel = Channels.GetByNumber(currentChannel); PrepareSchedule(channel); Display(); SetHelpKeys(); return osContinue; } void cMenuSearchMain::UpdateCurrent() { // navigation in summary could have changed current item, so update it cEventObj* cureventObj = eventObjects.GetCurrent(); if (cureventObj && cureventObj->Event()) for (cMenuMyScheduleItem *item = (cMenuMyScheduleItem *)First(); item; item = (cMenuMyScheduleItem *)Next(item)) if (item->Selectable() && item->event == cureventObj->Event()) { cureventObj->Select(false); SetCurrent(item); Display(); break; } } eOSState cMenuSearchMain::ProcessKey(eKeys Key) { bool HadSubMenu = HasSubMenu(); eOSState state = cOsdMenu::ProcessKey(Key); if (exitToMainMenu == 1) { exitToMainMenu = 0; return osBack; } if (!HasSubMenu() && HadSubMenu) UpdateCurrent(); if (state == osUnknown) { switch (Key) { case kFastRew: if (HasSubMenu() && !InWhatsOnMenu && !InFavoritesMenu) { /* if (Count()) { CursorUp(); return ShowSummary(); } */ } else return Shift(-EPGSearchConfig.timeShiftValue); case kFastFwd: if (HasSubMenu() && !InWhatsOnMenu && !InFavoritesMenu) { /* if (Count()) { CursorDown(); return ShowSummary(); } */ } else return Shift(EPGSearchConfig.timeShiftValue); case kRecord: case kRed: if(HasSubMenu()) { UpdateCurrent(); state = Record(); break; } if (Count()) { if (EPGSearchConfig.redkeymode==toggleKeys) state = Record(); else { cMenuMyScheduleItem *mi = (cMenuMyScheduleItem *)Get(Current()); if (mi) { if (mi->event) { return AddSubMenu(new cMenuSearchCommands(tr("EPG Commands"),mi->event)); } } } } break; case k0: if(!HasSubMenu()) { toggleKeys = 1 - toggleKeys; SetHelpKeys(true); } state = osContinue; break; case k1...k9: if (!HasSubMenu()) return Commands(Key); else state = osContinue; break; case kGreen: if (schedules) { if (HasSubMenu() && !InWhatsOnMenu && !InFavoritesMenu) { if (Count()) { // CursorUp(); // return ShowSummary(); } } else if (toggleKeys == 0 || (toggleKeys == 1 && EPGSearchConfig.toggleGreenYellow == 0)) { int ChannelNr = cDevice::CurrentChannel(); if (Count()) { cMenuMyScheduleItem* Item = (cMenuMyScheduleItem *)Get(Current()); if (Item && Item->event) { cChannel *channel = Channels.GetByChannelID(Item->event->ChannelID(), true, true); if (channel) ChannelNr = channel->Number(); } } if (cMenuWhatsOnSearch::currentShowMode == showFavorites) { InFavoritesMenu = true; return AddSubMenu(new cMenuFavorites()); } else { InWhatsOnMenu = true; return AddSubMenu(new cMenuWhatsOnSearch(schedules, ChannelNr)); } } else { cChannel *channel = Channels.GetByNumber(currentChannel-1,-1); if (channel) { PrepareSchedule(channel); if (channel->Number() != cDevice::CurrentChannel()) { otherChannel = channel->Number(); } Display(); } SetHelpKeys(true); return osContinue; } } case kYellow: if (schedules) { if (HasSubMenu()) { if (Count()) { // CursorDown(); // return ShowSummary(); } } else if (toggleKeys == 0 || (toggleKeys == 1 && EPGSearchConfig.toggleGreenYellow == 0)) { cMenuWhatsOnSearch::currentShowMode = showNext; InWhatsOnMenu = true; return AddSubMenu(new cMenuWhatsOnSearch(schedules, cMenuWhatsOnSearch::CurrentChannel())); } else { cChannel *channel = Channels.GetByNumber(currentChannel+1,1); if (channel) { PrepareSchedule(channel); if (channel->Number() != cDevice::CurrentChannel()) { otherChannel = channel->Number(); } Display(); } SetHelpKeys(true); return osContinue; } } break; case kBlue: if (HasSubMenu()) { UpdateCurrent(); return Switch(); } if (EPGSearchConfig.bluekeymode==toggleKeys) return Switch(); else return ExtendedSearch(); break; case kInfo: case kOk: if (Count()) return ShowSummary(); break; default: break; } } if (!HasSubMenu()) { cChannel *ch = cMenuWhatsOnSearch::ScheduleChannel(); InWhatsOnMenu = false; InFavoritesMenu = false; if (ch) { // when switch from the other menus to the schedule, try to keep the same time if (cMenuWhatsOnSearch::shiftTime) { time_t diff = cMenuWhatsOnSearch::seekTime - time(NULL); shiftTime = (diff + (diff>0?30:-30)) / 60 ; } else shiftTime = 0; PrepareSchedule(ch); if (ch->Number() != cDevice::CurrentChannel()) { otherChannel = ch->Number(); } Display(); } else if ((HadSubMenu || gl_TimerProgged) && Update()) { if (gl_TimerProgged) // when using epgsearch's timer edit menu, update is delayed because of SVDRP { gl_TimerProgged = 0; SetHelpKeys(); } Display(); } if (Key != kNone) SetHelpKeys(); if (gl_InfoConflict) { gl_InfoConflict = 0; if (Interface->Confirm(tr("Timer conflict! Show?"))) return AddSubMenu(new cMenuConflictCheck()); } } return state; } epgsearch-1.0.1.beta3/createcats.c0000644000175000017500000002503212112105222015751 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include #include #include #include #define MINAPPEARANCE 100 // the minimum appearance of a category #define MAXVALUES 60 // the maximum of values for a category #define MAXNAMELENGTH 30 // the maximum length of a category name or value // some helping stuff copied from VDR sources #define KILOBYTE(n) ((n) * 1024) #define MAXPARSEBUFFER KILOBYTE(10) #ifdef __FreeBSD__ #ifdef isnumber #undef isnumber #endif #endif bool isnumber(const char *s) { if (!*s) return false; while (*s) { if (!isdigit(*s)) return false; s++; } return true; } // --- cReadLine ------------------------------------------------------------- class cReadLine { private: char buffer[MAXPARSEBUFFER]; public: cReadLine() { buffer[0]=0; } char *Read(FILE *f); }; char *cReadLine::Read(FILE *f) { if (fgets(buffer, sizeof(buffer), f) > 0) { int l = strlen(buffer) - 1; if (l >= 0 && buffer[l] == '\n') buffer[l] = 0; return buffer; } return NULL; } char *skipspace(const char *s) { while (*s && isspace(*s)) s++; return (char *)s; } int comparevalue( const void *arg1, const void *arg2 ) { char* value1 = *(char**) arg1; char* value2 = *(char**) arg2; return strcmp(value1, value2); } // --- cCat ------------------------------------------------------------- class cCat { public: int appeared; char name[MAXPARSEBUFFER]; int numvalues; char** values; cCat(char* n) :appeared(0), numvalues(0), values(NULL) { strcpy(name, n); } void addvalue(char* value) { if (valueexists(value)) return; char* newvalue = (char*) malloc(sizeof(char) * (strlen(value)+1)); strcpy(newvalue, value); char **tmp = (char**) realloc(values, sizeof(char*)*(numvalues+1)); if (tmp) { values=tmp; values[numvalues++] = newvalue; } else { free(newvalue); } } bool valueexists(char* value) { for(int i=0; iappeared == cat2->appeared) return 0; if (cat1->appeared < cat2->appeared) return 1; else return -1; } // --- cCats ------------------------------------------------------------- class cCats { private: int numcats; cCat** cats; public: cCats():numcats(0), cats(NULL) {} int num() {return numcats;} cCat* add(char* name) { cCat* newCat = new cCat(name); cCat **tmp = (cCat**) realloc(cats, sizeof(cCat*)*(numcats+1)); if (tmp) { cats=tmp; cats[numcats++] = newCat; return newCat; } else { delete newCat; return NULL; } } cCat* get(int i) { if (i>=0 && iname, name) == 0) return cats[i]; return NULL; } void sort() { for(int i=0; isort(); qsort(cats, numcats, sizeof( cCat* ), comparecat ); } }; int main(int argc, char *argv[]) { FILE* f = NULL; cCats catlist; unsigned int minappearance = MINAPPEARANCE; unsigned int maxvalues = MAXVALUES; unsigned int maxlength = MAXNAMELENGTH; static const struct option long_options[] = { { "minappearance", required_argument, NULL, 'm' }, { "maxvalues", required_argument, NULL, 'v' }, { "maxlength", required_argument, NULL, 'l' }, { "help", no_argument, NULL, 'h' }, { NULL, no_argument, NULL, 0 } }; int c; while ((c = getopt_long(argc, argv, "m:v:l:h", long_options, NULL)) != -1) { switch (c) { case 'm': if (isnumber(optarg)) { minappearance = atoi(optarg); break; } fprintf(stderr, "invalid parameter minappearance: %s\n", optarg); return 2; break; case 'v': if (isnumber(optarg)) { maxvalues = atoi(optarg); break; } fprintf(stderr, "invalid parameter maxvalues: %s\n", optarg); return 2; break; case 'l': if (isnumber(optarg)) { maxlength = atoi(optarg); break; } fprintf(stderr, "invalid parameter maxlength: %s\n", optarg); return 2; break; case 'h': printf("usage: createcats [OPTIONS] /path_to/epg.data\n\n"); printf("-m N, --minappearance=N the minimum number a category has to appear\n"); printf(" to be used\n"); printf("-v N, --maxvalues=N values of a category are omitted if they exceed\n"); printf(" this number\n"); printf("-l N, --maxlength=N the maximum length of a text to be accepted\n"); printf(" as a category value\n"); printf("-h, --help this help\n\n"); return 0; default: break; } } if (argc < 2) { fprintf(stderr, "ERROR: please pass your epg.data\nusage: createcats epg.data\n"); return 1; } f = fopen(argv[argc-1], "r"); if (f == NULL) { fprintf(stderr, "ERROR: could not open: %s\n", argv[1]); return 1; } char *s; cReadLine ReadLine; while ((s = ReadLine.Read(f)) != NULL) { if (*s == 'D') { s = strchr(s,'|'); // jump to possibly first category if (!s) continue; s++; char *pstrSearchToken; char *pstrSearch=strdup(s); pstrSearchToken=strtok(pstrSearch, "|"); while(pstrSearchToken) { // must have a ':' char* szPos = NULL; if ((szPos = strchr(pstrSearchToken, ':')) == NULL) { pstrSearchToken=strtok(NULL, "|"); continue; } char catname[MAXPARSEBUFFER] = ""; char catvalue[MAXPARSEBUFFER] = ""; strncpy(catname, pstrSearchToken, szPos - pstrSearchToken); catname[szPos - pstrSearchToken] = 0; strcpy(catvalue, skipspace(szPos+1)); cCat* cat = catlist.exists(catname); if (!cat && strlen(catname) < maxlength) // accept only names up to 30 chars cat = catlist.add(catname); if (cat) { cat->appeared++; if (strlen(catvalue) < maxlength) // accept only values up to 30 chars cat->addvalue(catvalue); } pstrSearchToken=strtok(NULL, "|"); } free(pstrSearch); } } fclose(f); catlist.sort(); f = fopen("epgsearchcats.conf", "w"); if (f == NULL) { fprintf(stderr, "ERROR: could not open outputfile\n"); return 1; } fprintf(f, "# -----------------------------------------------------------------------------\n"); fprintf(f, "# This is just a template based on your current epg.data. Please edit!\n"); fprintf(f, "# Perhaps a category or its value list should be removed. Also the\n"); fprintf(f, "# 'name in menu' should be adjusted to your language.\n"); fprintf(f, "# The order of items determines the order listed in epgsearch. It does not\n"); fprintf(f, "# depend on the ID, which is used by epgsearch.\n"); fprintf(f, "# Format:\n"); fprintf(f, "# ID|category name|name in menu|values separated by ',' (option)|searchmode(option)\n"); fprintf(f, "# - 'ID' should be a unique positive integer\n"); fprintf(f, "# (changing the id later on will force you to reedit your search timers!)\n"); fprintf(f, "# - 'category name' is the name in your epg.data\n"); fprintf(f, "# - 'name in menu' is the name displayed in epgsearch.\n"); fprintf(f, "# - 'values' is an optional list of possible values\n"); fprintf(f, "# if you omit the list, the entry turns to an edit field in epgsearch,\n"); fprintf(f, "# else it's a list of items to select from\n"); fprintf(f, "# - 'searchmode' is an optional parameter specifying the mode of search:\n"); fprintf(f, "# text comparison:\n"); fprintf(f, "# 0 - the whole term must appear as substring\n"); fprintf(f, "# 1 - all single words (delimiters are ',', ';', '|' or '~')\n"); fprintf(f, "# must exist as substrings. This is the default search mode.\n"); fprintf(f, "# 2 - at least one word (delimiters are ',', ';', '|' or '~')\n"); fprintf(f, "# must exist as substring.\n"); fprintf(f, "# 3 - matches exactly\n"); fprintf(f, "# 4 - regular expression\n"); fprintf(f, "# numerical comparison:\n"); fprintf(f, "# 10 - less\n"); fprintf(f, "# 11 - less or equal\n"); fprintf(f, "# 12 - greater\n"); fprintf(f, "# 13 - greater or equal\n"); fprintf(f, "# 14 - equal\n"); fprintf(f, "# 15 - not equal\n"); fprintf(f, "# -----------------------------------------------------------------------------\n\n"); int id = 1; for(int i=0; iappeared > (int)minappearance && cat->numvalues > 1) // accept only category, that have at least 2 values and appear more than MINAPPEARANCE timers { fprintf(f, "# '%s' found %d times with %d different values %s\n", cat->name, cat->appeared, cat->numvalues, cat->numvalues>=(int)maxvalues?"(values omitted, too much)":""); fprintf(f, "%d|%s|%s|", id++, cat->name, cat->name); for(int j=0; cat->numvalues < (int)maxvalues && jnumvalues; j++) fprintf(f, "%s%s", cat->values[j], (j == cat->numvalues-1?"":",")); fprintf(f, "|1\n\n"); } } fclose(f); printf("epgsearchcats.conf created!\n"); return 0; } epgsearch-1.0.1.beta3/menu_favorites.c0000644000175000017500000001311712112105222016662 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include "menu_favorites.h" #include "menu_whatson.h" #include "menu_commands.h" using std::set; extern const char* ButtonBlue[3]; extern int exitToMainMenu; cMenuFavorites::cMenuFavorites() : cMenuSearchResults(cTemplFile::GetTemplateByName("MenuFavorites")) { BuildList(); } bool cMenuFavorites::BuildList() { Clear(); eventObjects.Clear(); cSearchResults* pCompleteSearchResults = NULL; cMutexLock SearchExtsLock(&SearchExts); cSearchExt *SearchExt = SearchExts.First(); int timespan = EPGSearchConfig.FavoritesMenuTimespan*60; while (SearchExt) { if (SearchExt->useInFavorites) pCompleteSearchResults = SearchExt->Run(modeBlue == showNoPayTV?1:0, false, timespan, pCompleteSearchResults, true); SearchExt = SearchExts.Next(SearchExt); } if (pCompleteSearchResults) { set foundEvents; pCompleteSearchResults->SortBy(CompareEventTime); for (cSearchResult* pResultObj = pCompleteSearchResults->First(); pResultObj; pResultObj = pCompleteSearchResults->Next(pResultObj)) { if (foundEvents.find(pResultObj->event) == foundEvents.end()) { foundEvents.insert(pResultObj->event); Add(new cMenuSearchResultsItem(pResultObj->event, modeYellow == showEpisode, false, menuTemplate)); eventObjects.Add(pResultObj->event); } } delete pCompleteSearchResults; } SetHelpKeys(); cString szTitle = cString::sprintf("%s: %d %s", tr("Favorites"), Count(), tr("Search results")); SetTitle(szTitle); Display(); return true; } eOSState cMenuFavorites::OnGreen() { eOSState state = osUnknown; if(!HasSubMenu()) { toggleKeys = 0; cMenuWhatsOnSearch::currentShowMode = cMenuWhatsOnSearch::GetNextMode(); return osUnknown; } return state; } eOSState cMenuFavorites::OnYellow() { eOSState state = osUnknown; if(!HasSubMenu()) { cMenuSearchResultsItem *item = (cMenuSearchResultsItem *)Get(Current()); if (item && item->event) { cChannel *channel = Channels.GetByChannelID(item->event->ChannelID(), true, true); cMenuWhatsOnSearch::scheduleChannel = channel; cMenuWhatsOnSearch::currentShowMode = showNow; } toggleKeys = 0; return osBack; } return state; } eOSState cMenuFavorites::ProcessKey(eKeys Key) { exitToMainMenu = 0; if (!HasSubMenu() && Key == kBack) { exitToMainMenu = 1; return osBack; } eOSState state = cMenuSearchResults::ProcessKey(Key); if (state == osUnknown) { switch (Key) { case kRecord: case kRed: state = OnRed(); break; case k0: if(!HasSubMenu()) { toggleKeys = 1 - toggleKeys; SetHelpKeys(true); } state = osContinue; break; case k1...k9: state = HasSubMenu()?osContinue:Commands(Key); break; case kBlue: return EPGSearchConfig.useOkForSwitch?ShowSummary():Switch(); break; case kOk: if(HasSubMenu()) { state = cOsdMenu::ProcessKey(Key); break; } if (Count()) state = EPGSearchConfig.useOkForSwitch?Switch():ShowSummary(); else state = osBack; break; default: break; } } return state; } void cMenuFavorites::SetHelpKeys(bool Force) { cMenuSearchResultsItem *item = (cMenuSearchResultsItem *)Get(Current()); int NewHelpKeys = 0; if (item) { if (item->Selectable() && item->timerMatch == tmFull) NewHelpKeys = 2; else NewHelpKeys = 1; } bool hasTimer = (NewHelpKeys == 2); if (NewHelpKeys != helpKeys || Force) { showMode nextShowMode = cMenuWhatsOnSearch::GetNextMode(); cShowMode* mode = cMenuWhatsOnSearch::GetShowMode(nextShowMode); const char* szButtonGreen = NULL; if (mode) szButtonGreen = mode->GetDescription(); if (toggleKeys==0) SetHelp((EPGSearchConfig.redkeymode==0?(hasTimer?trVDR("Button$Timer"):trVDR("Button$Record")):tr("Button$Commands")), szButtonGreen,trVDR("Button$Schedule"), EPGSearchConfig.useOkForSwitch?trVDR("Button$Info"):trVDR("Button$Switch")); else SetHelp((EPGSearchConfig.redkeymode==1?(hasTimer?trVDR("Button$Timer"):trVDR("Button$Record")):tr("Button$Commands")), szButtonGreen,trVDR("Button$Schedule"), EPGSearchConfig.useOkForSwitch?trVDR("Button$Info"):trVDR("Button$Switch")); helpKeys = NewHelpKeys; } } epgsearch-1.0.1.beta3/menu_blacklists.c0000644000175000017500000001325312112105222017014 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include #include #include #include "menu_blacklists.h" #include "epgsearchtools.h" #include "menu_blacklistedit.h" #include "epgsearchcfg.h" #include "menu_searchresults.h" using namespace std; // --- cMenuBlacklistsItem ---------------------------------------------------------- class cMenuBlacklistsItem : public cOsdItem { private: public: cBlacklist* blacklist; cMenuBlacklistsItem(cBlacklist* Blacklist); int Compare(const cListObject &ListObject) const; void Set(void); }; cMenuBlacklistsItem::cMenuBlacklistsItem(cBlacklist* Blacklist) { blacklist = Blacklist; Set(); } void cMenuBlacklistsItem::Set(void) { ostringstream line; if (blacklist->isGlobal != 0) line << setiosflags(ios::left) << "G"; line << "\t"; if (blacklist->search && strlen(blacklist->search) > 0) line << setiosflags(ios::left) << string(blacklist->search); else line << setiosflags(ios::left) << "*"; line << "\t"; if (blacklist->useChannel == 1) { if (blacklist->channelMin != blacklist->channelMax) line << setiosflags(ios::left) << blacklist->channelMin->Number() << " - " << blacklist->channelMax->Number(); else line << setiosflags(ios::left) << setw(11) << (blacklist->useChannel?CHANNELNAME(blacklist->channelMin):""); } else if (blacklist->useChannel == 2) line << setiosflags(ios::left) << setw(11) << blacklist->channelGroup; line << "\t"; if (blacklist->useTime) { ostringstream timeline; timeline << setfill('0') << setw(2) << blacklist->startTime / 100 << ":" << setw(2) << blacklist->startTime % 100; timeline << "\t"; timeline << setfill('0') << setw(2) << blacklist->stopTime / 100 << ":" << setw(2) << blacklist->stopTime % 100; line << timeline.str(); } else line << "--:--\t--:--"; SetText(strdup(line.str().c_str()), false); } int cMenuBlacklistsItem::Compare(const cListObject &ListObject) const { cMenuBlacklistsItem *p = (cMenuBlacklistsItem *)&ListObject; return strcasecmp(blacklist->search, p->blacklist->search); } // --- cMenuBlacklists ---------------------------------------------------------- cMenuBlacklists::cMenuBlacklists() :cOsdMenu(tr("Blacklists"), 3, 20, 11, 6, 5) { #if VDRVERSNUM >= 10734 SetMenuCategory(mcSetupPlugins); #endif cMutexLock BlacklistLock(&Blacklists); cBlacklist *Blacklist = Blacklists.First(); while (Blacklist) { Add(new cMenuBlacklistsItem(Blacklist)); Blacklist = Blacklists.Next(Blacklist); } SetHelp(trVDR("Button$Edit"), trVDR("Button$New"), trVDR("Button$Delete"), NULL); Sort(); Display(); } cBlacklist *cMenuBlacklists::CurrentBlacklist(void) { cMenuBlacklistsItem *item = (cMenuBlacklistsItem *)Get(Current()); if (item && Blacklists.Exists(item->blacklist)) return item->blacklist; return NULL; } eOSState cMenuBlacklists::New(void) { if (HasSubMenu()) return osContinue; return AddSubMenu(new cMenuBlacklistEdit(new cBlacklist, true)); } eOSState cMenuBlacklists::Delete(void) { cBlacklist *curBlacklist = CurrentBlacklist(); if (curBlacklist) { if (Interface->Confirm(tr("Edit$Delete blacklist?"))) { LogFile.Log(1,"blacklist %s (%d) deleted", curBlacklist->search, curBlacklist->ID); SearchExts.RemoveBlacklistID(curBlacklist->ID); cMutexLock BlacklistLock(&Blacklists); Blacklists.Del(curBlacklist); Blacklists.Save(); cOsdMenu::Del(Current()); Display(); } } return osContinue; } eOSState cMenuBlacklists::ProcessKey(eKeys Key) { int BlacklistNumber = HasSubMenu() ? Count() : -1; eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { if (HasSubMenu()) return osContinue; switch (Key) { case kOk: return AddSubMenu(new cMenuSearchResultsForBlacklist(CurrentBlacklist())); break; case kRed: if (CurrentBlacklist()) state = AddSubMenu(new cMenuBlacklistEdit(CurrentBlacklist())); else state = osContinue; break; case kGreen: state = New(); break; case kYellow: state = Delete(); break; default: break; } } if (BlacklistNumber >= 0 && !HasSubMenu()) { cMutexLock BlacklistLock(&Blacklists); cBlacklist* Blacklist = Blacklists.Get(BlacklistNumber); if (Blacklist) // a newly created search was confirmed with Ok Add(new cMenuBlacklistsItem(Blacklist)); // always update all entries, since channel group names may have changed and affect other searches Sort(); for(int i=0; iSet(); if (item->blacklist == Blacklist) SetCurrent(item); } } Display(); } return state; } epgsearch-1.0.1.beta3/menu_conflictcheck.h0000644000175000017500000000563412112105236017476 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __EPGSEARCHMENUCONFL_H #define __EPGSEARCHMENUCONFL_H #include #include "conflictcheck.h" #include "menu_event.h" // --- cMenuConflictCheckItem ------------------------------------------------------ class cMenuConflictCheckItem : public cOsdItem { public: cConflictCheckTime* checktime; cConflictCheckTimerObj* timerObj; cMenuConflictCheckItem(cConflictCheckTime* Ct, cConflictCheckTimerObj* TimerObj = NULL); }; // --- cMenuConflictCheck ------------------------------------------------------ class cMenuConflictCheck : public cOsdMenu { private: cConflictCheck conflictCheck; bool showAll; int lastSel; virtual eOSState ProcessKey(eKeys Key); cConflictCheckTimerObj* CurrentTimerObj(void); void Update(); bool BuildList(); public: cMenuConflictCheck(); }; // --- cMenuConflictCheckDetailsItem ------------------------------------------------------ class cMenuConflictCheckDetailsItem : public cOsdItem { bool hasTimer; public: cConflictCheckTimerObj* timerObj; cMenuConflictCheckDetailsItem(cConflictCheckTimerObj* TimerObj = NULL); bool Update(bool Force = false); }; // --- cMenuConflictCheckDetails ------------------------------------------------------ class cMenuConflictCheckDetails : public cOsdMenu { private: cConflictCheck* conflictCheck; cConflictCheckTimerObj* timerObj; cConflictCheckTime* checktime; cEventObjects eventObjects; virtual eOSState ProcessKey(eKeys Key); cConflictCheckTimerObj* CurrentTimerObj(void); eOSState Commands(eKeys Key); void SetHelpKeys(); eOSState ToggleTimer(cConflictCheckTimerObj* TimerObj); eOSState DeleteTimer(cConflictCheckTimerObj* TimerObj); bool Update(bool Force = false); bool BuildList(); eOSState ShowSummary(); void UpdateCurrent(); public: cMenuConflictCheckDetails(cConflictCheckTimerObj* TimerObj = NULL, cConflictCheck* ConflictCheck = NULL); }; #endif epgsearch-1.0.1.beta3/blacklist.c0000644000175000017500000004600012112105223015602 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include "epgsearchtools.h" #include "blacklist.h" #include "epgsearchcats.h" #include #include "menu_dirselect.h" #include "changrp.h" #include "menu_search.h" #include "menu_searchedit.h" #include "menu_searchresults.h" #include cBlacklists Blacklists; // -- cBlacklist ----------------------------------------------------------------- char *cBlacklist::buffer = NULL; cBlacklist::cBlacklist(void) { ID = -1; *search = 0; options = 1; useTime = false; startTime = 0000; stopTime = 2359; useChannel = false; channelMin = Channels.GetByNumber(cDevice::CurrentChannel()); channelMax = Channels.GetByNumber(cDevice::CurrentChannel()); channelGroup = NULL; useCase = false; mode = 0; useTitle = true; useSubtitle = true; useDescription = true; useDuration = false; minDuration = 0; maxDuration = 130; useDayOfWeek = false; DayOfWeek = 0; buffer = NULL; isGlobal = 0; useExtEPGInfo = false; catvalues = (char**) malloc(SearchExtCats.Count() * sizeof(char*)); cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { catvalues[index] = (char*)malloc(MaxFileName); *catvalues[index] = 0; SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } ignoreMissingEPGCats = 0; fuzzyTolerance = 1; } cBlacklist::~cBlacklist(void) { if (buffer) { free(buffer); buffer = NULL; } if (catvalues) { cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { free(catvalues[index]); SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } free(catvalues); catvalues = NULL; } } cBlacklist& cBlacklist::operator= (const cBlacklist &Blacklist) { char** catvaluesTemp = this->catvalues; memcpy(this, &Blacklist, sizeof(*this)); this->catvalues = catvaluesTemp; cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { *catvalues[index] = 0; strcpy(catvalues[index], Blacklist.catvalues[index]); SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } return *this; } void cBlacklist::CopyFromTemplate(const cSearchExt* templ) { options = templ->options; useTime = templ->useTime; startTime = templ->startTime; stopTime = templ->stopTime; useChannel = templ->useChannel; useCase = templ->useCase; mode = templ->mode; useTitle = templ->useTitle; useSubtitle = templ->useSubtitle; useDescription = templ->useDescription; useDuration = templ->useDuration; minDuration = templ->minDuration; maxDuration = templ->maxDuration; useDayOfWeek = templ->useDayOfWeek; DayOfWeek = templ->DayOfWeek; useExtEPGInfo = templ->useExtEPGInfo; isGlobal = 0; cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { strcpy(catvalues[index], templ->catvalues[index]); SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } channelMin = templ->channelMin; channelMax = templ->channelMax; if (channelGroup) free(channelGroup); if (templ->channelGroup) channelGroup = strdup(templ->channelGroup); fuzzyTolerance = templ->fuzzyTolerance; ignoreMissingEPGCats = templ->ignoreMissingEPGCats; } bool cBlacklist::operator< (const cListObject &ListObject) { cBlacklist *BL = (cBlacklist *)&ListObject; return strcasecmp(search, BL->search) < 0; } const char *cBlacklist::ToText(void) { char tmp_Start[5] = ""; char tmp_Stop[5] = ""; char tmp_minDuration[5] = ""; char tmp_maxDuration[5] = ""; char* tmp_chanSel = NULL; char* tmp_search = NULL; char* tmp_catvalues = NULL; free(buffer); tmp_search = strdup(search); while(strstr(tmp_search, "|")) tmp_search = strreplace(tmp_search, "|", "!^pipe^!"); // ugly: replace a pipe with something, that should not happen to be part of a regular expression strreplace(tmp_search, ':', '|'); if (useTime) { sprintf(tmp_Start, "%04d", startTime); sprintf(tmp_Stop, "%04d", stopTime); } if (useDuration) { sprintf(tmp_minDuration, "%04d", minDuration); sprintf(tmp_maxDuration, "%04d", maxDuration); } if (useChannel==1) { if (channelMin->Number() < channelMax->Number()) msprintf(&tmp_chanSel, "%s|%s", CHANNELSTRING(channelMin), CHANNELSTRING(channelMax)); else msprintf(&tmp_chanSel, "%s", CHANNELSTRING(channelMin)); } if (useChannel==2) { int channelGroupNr = ChannelGroups.GetIndex(channelGroup); if (channelGroupNr == -1) { LogFile.eSysLog("channel group %s does not exist!", channelGroup); useChannel = 0; } else tmp_chanSel = strdup(channelGroup); } if (useExtEPGInfo) { cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { char* catvalue = NULL; if (msprintf(&catvalue, "%s", catvalues[index])!=-1) { while(strstr(catvalue, ":")) catvalue = strreplace(catvalue, ":", "!^colon^!"); // ugly: replace with something, that should not happen to be part ofa category value while(strstr(catvalue, "|")) catvalue = strreplace(catvalue, "|", "!^pipe^!"); // ugly: replace with something, that should not happen to be part of a regular expression if (index == 0) msprintf(&tmp_catvalues, "%d#%s", SearchExtCat->id, catvalue); else { char* temp = tmp_catvalues; msprintf(&tmp_catvalues, "%s|%d#%s", tmp_catvalues, SearchExtCat->id, catvalue); free(temp); } } SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; free(catvalue); } } msprintf(&buffer, "%d:%s:%d:%s:%s:%d:%s:%d:%d:%d:%d:%d:%d:%s:%s:%d:%d:%d:%s:%d:%d:%d", ID, tmp_search, useTime, tmp_Start, tmp_Stop, useChannel, (useChannel>0 && useChannel<3)?tmp_chanSel:"0", useCase, mode, useTitle, useSubtitle, useDescription, useDuration, tmp_minDuration, tmp_maxDuration, useDayOfWeek, DayOfWeek, useExtEPGInfo, useExtEPGInfo?tmp_catvalues:"", fuzzyTolerance, ignoreMissingEPGCats, isGlobal); if (tmp_chanSel) free(tmp_chanSel); if (tmp_search) free(tmp_search); if (tmp_catvalues) free(tmp_catvalues); return buffer; } bool cBlacklist::Parse(const char *s) { char *line; char *pos; char *pos_next; int parameter = 1; int valuelen; char value[MaxFileName]; pos = line = strdup(s); pos_next = pos + strlen(pos); if (*pos_next == '\n') *pos_next = 0; while (*pos) { while (*pos == ' ') pos++; if (*pos) { if (*pos != ':') { pos_next = strchr(pos, ':'); if (!pos_next) pos_next = pos + strlen(pos); valuelen = pos_next - pos + 1; if (valuelen > MaxFileName) valuelen = MaxFileName; strn0cpy(value, pos, valuelen); pos = pos_next; switch (parameter) { case 1: ID = atoi(value); break; case 2: strcpy(search, value); break; case 3: useTime = atoi(value); break; case 4: startTime = atoi(value); break; case 5: stopTime = atoi(value); break; case 6: useChannel = atoi(value); break; case 7: if (useChannel == 0) { channelMin = NULL; channelMax = NULL; } else if (useChannel == 1) { int minNum=0, maxNum=0; int fields = sscanf(value, "%d-%d", &minNum, &maxNum); if (fields == 0) // stored with ID { #ifdef __FreeBSD__ char *channelMinbuffer = MALLOC(char, 32); char *channelMaxbuffer = MALLOC(char, 32); int channels = sscanf(value, "%31[^|]|%31[^|]", channelMinbuffer, channelMaxbuffer); #else char *channelMinbuffer = NULL; char *channelMaxbuffer = NULL; int channels = sscanf(value, "%a[^|]|%a[^|]", &channelMinbuffer, &channelMaxbuffer); #endif channelMin = Channels.GetByChannelID(tChannelID::FromString(channelMinbuffer), true, true); if (!channelMin) { LogFile.eSysLog("ERROR: channel %s not defined", channelMinbuffer); channelMin = channelMax = NULL; useChannel = 0; } if (channels == 1) channelMax = channelMin; else { channelMax = Channels.GetByChannelID(tChannelID::FromString(channelMaxbuffer), true, true); if (!channelMax) { LogFile.eSysLog("ERROR: channel %s not defined", channelMaxbuffer); channelMin = channelMax = NULL; useChannel = 0; } } free(channelMinbuffer); free(channelMaxbuffer); } } else if (useChannel == 2) channelGroup = strdup(value); break; case 8: useCase = atoi(value); break; case 9: mode = atoi(value); break; case 10: useTitle = atoi(value); break; case 11: useSubtitle = atoi(value); break; case 12: useDescription = atoi(value); break; case 13: useDuration = atoi(value); break; case 14: minDuration = atoi(value); break; case 15: maxDuration = atoi(value); break; case 16: useDayOfWeek = atoi(value); break; case 17: DayOfWeek = atoi(value); break; case 18: useExtEPGInfo = atoi(value); break; case 19: if (!ParseExtEPGValues(value)) { LogFile.eSysLog("ERROR reading ext. EPG values - 1"); free(line); return false; } break; case 20: fuzzyTolerance = atoi(value); break; case 21: ignoreMissingEPGCats = atoi(value); break; case 22: isGlobal = atoi(value); break; default: break; } //switch } parameter++; } if (*pos) pos++; } //while strreplace(search, '|', ':'); while(strstr(search, "!^pipe^!")) strreplace(search, "!^pipe^!", "|"); free(line); return (parameter >= 19) ? true : false; } bool cBlacklist::ParseExtEPGValues(const char *s) { char *line; char *pos; char *pos_next; int valuelen; char value[MaxFileName]; pos = line = strdup(s); pos_next = pos + strlen(pos); if (*pos_next == '\n') *pos_next = 0; while (*pos) { while (*pos == ' ') pos++; if (*pos) { if (*pos != '|') { pos_next = strchr(pos, '|'); if (!pos_next) pos_next = pos + strlen(pos); valuelen = pos_next - pos + 1; if (valuelen > MaxFileName) valuelen = MaxFileName; strn0cpy(value, pos, valuelen); pos = pos_next; if (!ParseExtEPGEntry(value)) { LogFile.eSysLog("ERROR reading ext. EPG value: %s", value); free(line); return false; } } } if (*pos) pos++; } //while free(line); return true; } bool cBlacklist::ParseExtEPGEntry(const char *s) { char *line; char *pos; char *pos_next; int parameter = 1; int valuelen; char value[MaxFileName]; int currentid = -1; pos = line = strdup(s); pos_next = pos + strlen(pos); if (*pos_next == '\n') *pos_next = 0; while (*pos) { while (*pos == ' ') pos++; if (*pos) { if (*pos != '#') { pos_next = strchr(pos, '#'); if (!pos_next) pos_next = pos + strlen(pos); valuelen = pos_next - pos + 1; if (valuelen > MaxFileName) valuelen = MaxFileName; strn0cpy(value, pos, valuelen); pos = pos_next; switch (parameter) { case 1: { currentid = atoi(value); int index = SearchExtCats.GetIndexFromID(currentid); if (index > -1) strcpy(catvalues[index], ""); } break; case 2: if (currentid > -1) { int index = SearchExtCats.GetIndexFromID(currentid); if (index > -1) { while(strstr(value, "!^colon^!")) strreplace(value, "!^colon^!", ":"); while(strstr(value, "!^pipe^!")) strreplace(value, "!^pipe^!", "|"); strcpy(catvalues[index], value); } } break; default: break; } //switch } parameter++; } if (*pos) pos++; } //while free(line); return (parameter >= 2) ? true : false; } bool cBlacklist::Save(FILE *f) { return fprintf(f, "%s\n", ToText()) > 0; } cEvent * cBlacklist::GetEventByBlacklist(const cSchedule *schedules, const cEvent *Start, int MarginStop) { cEvent *pe = NULL; cEvent *p1 = NULL; if (Start) p1 = schedules->Events()->Next(Start); else p1 = schedules->Events()->First(); time_t tNow=time(NULL); char* szTest = NULL; char* searchText = strdup(search); if (!useCase) ToLower(searchText); int searchStart = 0, searchStop = 0; if (useTime) { searchStart = startTime; searchStop = stopTime; if (searchStop < searchStart) searchStop += 2400; } int minSearchDuration = 0; int maxSearchDuration = 0; if (useDuration) { minSearchDuration = minDuration/100*60 + minDuration%100; maxSearchDuration = maxDuration/100*60 + maxDuration%100; } for (cEvent *p = p1; p; p = schedules->Events()->Next(p)) { if(!p) { break; } if (szTest) { free(szTest); szTest = NULL; } // ignore events without title if (!p->Title() || strlen(p->Title()) == 0) continue; msprintf(&szTest, "%s%s%s%s%s", (useTitle?p->Title():""), (useSubtitle||useDescription)?"~":"", (useSubtitle?p->ShortText():""),useDescription?"~":"", (useDescription?p->Description():"")); if (tNow < p->EndTime() + MarginStop * 60) { if (!useCase) ToLower(szTest); if (useTime) { time_t tEvent = p->StartTime(); struct tm tmEvent; localtime_r(&tEvent, &tmEvent); int eventStart = tmEvent.tm_hour*100 + tmEvent.tm_min; int eventStart2 = tmEvent.tm_hour*100 + tmEvent.tm_min + 2400; if ((eventStart < searchStart || eventStart > searchStop) && (eventStart2 < searchStart || eventStart2 > searchStop)) continue; } if (useDuration) { int duration = p->Duration()/60; if (minSearchDuration > duration || maxSearchDuration < duration) continue; } if (useDayOfWeek) { time_t tEvent = p->StartTime(); struct tm tmEvent; localtime_r(&tEvent, &tmEvent); if (DayOfWeek >= 0 && DayOfWeek != tmEvent.tm_wday) continue; if (DayOfWeek < 0) { int iFound = 0; for(int i=0; i<7; i++) if (abs(DayOfWeek) & (int)pow(2,i) && i == tmEvent.tm_wday) { iFound = 1; break; } if (!iFound) continue; } } if (strlen(szTest) > 0) { if (!MatchesSearchMode(szTest, searchText, mode," ,;|~", fuzzyTolerance)) continue; } if (useExtEPGInfo && !MatchesExtEPGInfo(p)) continue; pe=p; break; } } if (szTest) free(szTest); free(searchText); return pe; } // returns a pointer array to the matching search results cSearchResults* cBlacklist::Run(cSearchResults* pSearchResults, int MarginStop) { LogFile.Log(3,"start search for blacklist '%s'", search); cSchedulesLock schedulesLock; const cSchedules *schedules; schedules = cSchedules::Schedules(schedulesLock); if(!schedules) { LogFile.Log(1,"schedules are currently locked! try again later."); return NULL; } const cSchedule *Schedule = schedules->First(); while (Schedule) { cChannel* channel = Channels.GetByChannelID(Schedule->ChannelID(),true,true); if (!channel) { Schedule = (const cSchedule *)schedules->Next(Schedule); continue; } if (useChannel == 1 && channelMin && channelMax) { if (channelMin->Number() > channel->Number() || channelMax->Number() < channel->Number()) { Schedule = (const cSchedule *)schedules->Next(Schedule); continue; } } if (useChannel == 2 && channelGroup) { cChannelGroup* group = ChannelGroups.GetGroupByName(channelGroup); if (!group || !group->ChannelInGroup(channel)) { Schedule = (const cSchedule *)schedules->Next(Schedule); continue; } } if (useChannel == 3) { if (channel->Ca() >= CA_ENCRYPTED_MIN) { Schedule = (const cSchedule *)schedules->Next(Schedule); continue; } } const cEvent *pPrevEvent = NULL; do { const cEvent* event = GetEventByBlacklist(Schedule, pPrevEvent, MarginStop); pPrevEvent = event; if (event && Channels.GetByChannelID(event->ChannelID(),true,true)) { if (!pSearchResults) pSearchResults = new cSearchResults; pSearchResults->Add(new cSearchResult(event, this)); } } while(pPrevEvent); Schedule = (const cSchedule *)schedules->Next(Schedule); } LogFile.Log(3,"found %d event(s) for blacklist '%s'", pSearchResults?pSearchResults->Count():0, search); return pSearchResults; } bool cBlacklist::MatchesExtEPGInfo(const cEvent* e) { if (!e || !e->Description()) return false; cSearchExtCat* SearchExtCat = SearchExtCats.First(); while (SearchExtCat) { char* value = NULL; int index = SearchExtCats.GetIndexFromID(SearchExtCat->id); if (index > -1) value = catvalues[index]; if (value && strlen(value) > 0) { char* testvalue = GetExtEPGValue(e, SearchExtCat); if (!testvalue) return false; // compare not case sensitive char* valueLower = strdup(value); ToLower(valueLower); ToLower(testvalue); if (!MatchesSearchMode(testvalue, valueLower, SearchExtCat->searchmode, ",;|~", fuzzyTolerance)) { free(testvalue); free(valueLower); return false; } free(testvalue); free(valueLower); } SearchExtCat = SearchExtCats.Next(SearchExtCat); } return true; } // -- cBlacklists ---------------------------------------------------------------- int cBlacklists::GetNewID() { int newID = -1; cMutexLock BlacklistLock(this); cBlacklist *l = (cBlacklist *)First(); while (l) { newID = max(newID, l->ID); l = (cBlacklist *)l->Next(); } return newID+1; } cBlacklist* cBlacklists::GetBlacklistFromID(int ID) { if (ID == -1) return NULL; cMutexLock BlacklistLock(this); cBlacklist *l = (cBlacklist *)First(); while (l) { if (l->ID == ID) return l; l = (cBlacklist *)l->Next(); } return NULL; } bool cBlacklists::Exists(const cBlacklist* Blacklist) { cMutexLock BlacklistLock(this); cBlacklist *l = (cBlacklist*)First(); while (l) { if (l == Blacklist) return true; l = (cBlacklist*)l->Next(); } return false; } epgsearch-1.0.1.beta3/epgsearchonly.c0000644000175000017500000000403712112105223016501 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include #include #include "services.h" #include "mainmenushortcut.h" static const char *VERSION = "0.0.1"; static const char *DESCRIPTION = trNOOP("Direct access to epgsearch's search menu"); static const char *MAINMENUENTRY = trNOOP("Search"); static const char *SETUPTEXT = trNOOP("EpgSearch-Search in main menu"); class cPluginEpgsearchonly:public cMainMenuShortcut { public: virtual const char *Version() { return VERSION; } virtual const char *Description() { return I18nTranslate(DESCRIPTION, I18nEpgsearch); } virtual bool Initialize(); virtual cOsdObject *MainMenuAction() { return GetEpgSearchMenu("Epgsearch-searchmenu-v1.0"); }; protected: virtual const char *SetupText() { return I18nTranslate(SETUPTEXT, I18nEpgsearch); } virtual const char *MainMenuText() { return I18nTranslate(MAINMENUENTRY, I18nEpgsearch); } }; bool cPluginEpgsearchonly::Initialize() { return cMainMenuShortcut::Initialize(); } VDRPLUGINCREATOR(cPluginEpgsearchonly); // Don't touch this! epgsearch-1.0.1.beta3/pending_notifications.h0000644000175000017500000000444512112105236020227 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __PENDING_NOTIFICATIONS_H #define __PENDING_NOTIFICATIONS_H #include using std::string; // --- cPendingNotification -------------------------------------------------------- class cPendingNotification : public cListObject { public: int type; tEventID eventID; tChannelID channelID; time_t start; uint timerMod; int searchID; string formatted; static char *buffer; cPendingNotification() : type(-1), start(-1), timerMod(-1), searchID(-1) {} cPendingNotification(int Type, tEventID EventID, tChannelID ChannelID, time_t Start, uint TimerMod = -1, int SearchID = -1, string Formatted = "") : type(Type), eventID(EventID), channelID(ChannelID), start(Start), timerMod(TimerMod), searchID(SearchID), formatted(Formatted) {} ~cPendingNotification(); static bool Read(FILE *f); bool Parse(const char *s); const char *ToText(void) const; bool Save(FILE *f); }; class cPendingNotifications : public cList { public: private: char *fileName; public: cPendingNotifications() { fileName = NULL; } void Clear(void) { free(fileName); fileName = NULL; cList::Clear(); } bool Load(const char *FileName = NULL); bool Save(void); }; extern cPendingNotifications PendingNotifications; #endif epgsearch-1.0.1.beta3/menu_dirselect.c0000644000175000017500000001627212112105223016644 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include "menu_dirselect.h" #include "epgsearchext.h" #include "epgsearchcats.h" #include "epgsearchtools.h" set cMenuDirSelect::directorySet; cDirExts DirExts; cConfDDirExts ConfDDirExts; // --- cMenuDirItem --------------------------------------------------------- class cMenuDirItem : public cOsdItem { private: char* directory; public: cMenuDirItem(const char* text) : cOsdItem(text) { directory = strdup(text);} ~cMenuDirItem(){ if (directory) free(directory);} virtual int Compare(const cListObject &ListObject) const; }; int cMenuDirItem::Compare(const cListObject &ListObject) const { const cMenuDirItem *p = (cMenuDirItem *)&ListObject; int hasVars1 = (strchr(directory,'%') != NULL?1:0); int hasVars2 = (strchr(p->directory,'%') != NULL?1:0); if (hasVars1 || hasVars2) { if (hasVars1 != hasVars2) return hasVars2-hasVars1; else return strcasecmp(directory, p->directory); } else return strcasecmp(directory, p->directory); } // --- cMenuDirSelect --------------------------------------------------------- cMenuDirSelect::cMenuDirSelect(char* szDirectory) :cOsdMenu(tr("Select directory")) { #if VDRVERSNUM >= 10728 SetMenuCategory(mcTimer); #endif Directory = szDirectory; yellow=NULL; MaxLevel = 1; CurLevel = 1; Load(); } cMenuDirSelect::~cMenuDirSelect() { if (yellow) free(yellow); } int cMenuDirSelect::Level(const char* szDir) { int iLevel = 1; if (strchr(szDir, '%')) // dirs with vars always have level 1 return 1; do { const char* pos = strchr(szDir, '~'); if (pos) { iLevel++; szDir = pos+1; } else return iLevel; } while(true); return 1; } void cMenuDirSelect::AddDistinct(const char* szText) { int iLevel = Level(szText); MaxLevel = max(MaxLevel, iLevel); if (iLevel > CurLevel) // only show Items of the specified level, except those with vars return; for(int i=0; iText(); char* itemtext = strdup(ItemText); char* sztext = strdup(szText); ToLower(itemtext); ToLower(sztext); if (itemtext && strlen(itemtext) > 0 && strcmp(sztext, itemtext) == 0) { free(itemtext); free(sztext); return; } free(itemtext); free(sztext); } Add(new cMenuDirItem(hk(szText))); } void cMenuDirSelect::CreateDirSet(bool extraDirs) { directorySet.clear(); // add distinct directories from current recordings if (Recordings.Count() == 0) Recordings.Load(); for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { if (recording->HierarchyLevels() > 0) { char* dir = strdup(recording->Name()); // strip the trailing rec dir char* pos = strrchr(dir, '~'); if (pos) { *pos=0; for(int iLevel = 0; iLevel < recording->HierarchyLevels(); iLevel++) { directorySet.insert(dir); char* pos = strrchr(dir, '~'); if (pos) *pos=0; } } free(dir); } } // add distinct directories from current timers for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { char* dir = strdup(timer->File()); // strip the trailing name dir char* pos = strrchr(dir, '~'); if (pos) { *pos=0; do { directorySet.insert(dir); char* pos = strrchr(dir, '~'); if (pos) *pos=0; else break; } while(true); } free(dir); } #if APIVERSNUM >= 10712 // add distinct directories from folders.conf for(cNestedItem* item = Folders.First(); item; item = Folders.Next(item)) AddVDRFolders(item); #endif if (extraDirs) { cMutexLock SearchExtsLock(&SearchExts); cSearchExt *searchExt = SearchExts.First(); // add distinct directories from existing search timers while (searchExt) { if (strlen(searchExt->directory) > 0) directorySet.insert(searchExt->directory); searchExt = SearchExts.Next(searchExt); } // add distinct directories from epgsearchdirs.conf DirExts.Load(AddDirectory(CONFIGDIR, "epgsearchdirs.conf"), true); cDirExt* DirExt = DirExts.First(); while (DirExt) { directorySet.insert(DirExt->Name()); DirExt = DirExts.Next(DirExt); } // add distinct directories from conf.d files DirExt = ConfDDirExts.First(); while (DirExt) { directorySet.insert(DirExt->Name()); DirExt = ConfDDirExts.Next(DirExt); } } } #if APIVERSNUM >= 10712 void cMenuDirSelect::AddVDRFolders(cNestedItem* folder, string parentDirectory) { if (folder == NULL) return; string folderDirectory = string((parentDirectory.size() == 0)?"":parentDirectory + "~") + folder->Text(); directorySet.insert(folderDirectory); if (folder->SubItems() == NULL) return; for(cNestedItem* subfolder = folder->SubItems()->First(); subfolder; subfolder = folder->SubItems()->Next(subfolder)) AddVDRFolders(subfolder, folderDirectory); } #endif void cMenuDirSelect::Load() { int current = Current(); char* oldSelection = NULL; // save old selection for reselection if (current>-1) oldSelection = strdup(Get(current)->Text()); Clear(); CreateDirSet(); std::set::iterator it; for (it = directorySet.begin(); it != directorySet.end(); ++it) AddDistinct((*it).c_str()); Sort(); for(int i=0; iText(); if (oldSelection && strchr(text, '%') == NULL && strstr(text, oldSelection) == text) // skip entries with variables { SetCurrent(Get(i)); break; } } if (oldSelection) free(oldSelection); if (yellow) { free(yellow); yellow = NULL; } msprintf(&yellow, "%s %d", tr("Button$Level"), (CurLevel==MaxLevel?1:CurLevel+1)); SetHelp(NULL, NULL, MaxLevel==1?NULL:yellow, tr("Button$Select")); Display(); } eOSState cMenuDirSelect::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch ((int)Key) { case kBlue|k_Repeat: case kYellow: if (++CurLevel>MaxLevel) CurLevel=1; Load(); return osContinue; case kGreen: case kRed: return osContinue; case kBlue: case kOk: if (Count() > 0) strn0cpy(Directory,Get(Current())->Text(), MaxFileName); return osBack; default: break; } } return state; } epgsearch-1.0.1.beta3/epgsearchsetup.h0000644000175000017500000000666012112105236016675 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __EPGSEARCH_H #define __EPGSEARCH_H #include #include "epgsearchcfg.h" #include class cPluginEpgsearch; class cMenuSetupSubMenu : public cOsdMenu { protected: cEPGSearchConfig* data; std::vector helpTexts; eOSState Help(); void AddHelp(const char* helpText); virtual eOSState ProcessKey(eKeys Key); virtual void Set(void) = 0; public: cMenuSetupSubMenu(const char* Title, cEPGSearchConfig* Data); }; class cMenuSetupGeneral : public cMenuSetupSubMenu { protected: virtual eOSState ProcessKey(eKeys Key); void Set(void); public: cMenuSetupGeneral(cEPGSearchConfig* Data); }; class cMenuSetupEPGMenus : public cMenuSetupSubMenu { protected: void Set(void); void SetHelpKeys(); public: cMenuSetupEPGMenus(cEPGSearchConfig* Data); }; class cMenuSetupUserdefTimes : public cMenuSetupSubMenu { protected: virtual eOSState ProcessKey(eKeys Key); void Set(void); public: cMenuSetupUserdefTimes(cEPGSearchConfig* Data); }; class cMenuSetupTimers : public cMenuSetupSubMenu { protected: virtual eOSState ProcessKey(eKeys Key); void Set(void); void SetHelpKeys(); public: cMenuSetupTimers(cEPGSearchConfig* Data); }; class cMenuSetupSearchtimers : public cMenuSetupSubMenu { char** menuitemsChGr; protected: virtual eOSState ProcessKey(eKeys Key); void Set(void); void SetHelpKeys(); public: cMenuSetupSearchtimers(cEPGSearchConfig* Data); ~cMenuSetupSearchtimers(); }; class cMenuSetupTimerConflicts : public cMenuSetupSubMenu { protected: virtual eOSState ProcessKey(eKeys Key); void Set(void); public: cMenuSetupTimerConflicts(cEPGSearchConfig* Data); }; class cMenuSetupMailNotification : public cMenuSetupSubMenu { char tmpMailAuthPass[MaxFileName]; void SetHelpKeys(); protected: virtual eOSState ProcessKey(eKeys Key); void Set(void); public: cMenuSetupMailNotification(cEPGSearchConfig* Data); eOSState TestMailAccount(); static const char *HostNameChars; static const char *UserNameChars; static const char *PasswordChars; static const char *MailBoxChars; }; class cMenuEPGSearchSetup : public cMenuSetupPage { private: virtual void Setup(void); cEPGSearchConfig data; int delaySearchTimerThreadMode; protected: virtual eOSState ProcessKey(eKeys Key); virtual void Store(void); void Set(void); public: cMenuEPGSearchSetup(void); }; #endif epgsearch-1.0.1.beta3/conflictcheck_thread.c0000644000175000017500000001236612112105223017770 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include "conflictcheck_thread.h" #include "epgsearchcfg.h" #include "mail.h" #include "epgsearch.h" #define CONFLICTCHECK_NICE 19 cConflictCheckThread *cConflictCheckThread::m_Instance = NULL; time_t cConflictCheckThread::m_cacheNextConflict = 0; int cConflictCheckThread::m_cacheRelevantConflicts = 0; int cConflictCheckThread::m_cacheTotalConflicts = 0; bool cConflictCheckThread::m_runOnce = false; bool cConflictCheckThread::m_forceUpdate = false; cConflictCheckThread::cConflictCheckThread(cPluginEpgsearch* thePlugin) : cThread("EPGSearch: conflictcheck") { m_plugin = thePlugin; m_Active = false; m_lastUpdate = time(NULL); m_runOnce = false; m_forceUpdate = false; } cConflictCheckThread::~cConflictCheckThread() { if (m_Active) Stop(); } void cConflictCheckThread::Init(cPluginEpgsearch* thePlugin, bool runOnce) { if (EPGSearchConfig.checkTimerConflictsAfterUpdate || EPGSearchConfig.conflictCheckIntervall == 0) { if (!runOnce) return; m_runOnce = true; } if (m_Instance == NULL) { m_Instance = new cConflictCheckThread(thePlugin); m_Instance->Start(); } else if (runOnce) m_forceUpdate = true; // force an update, because thread is already running } void cConflictCheckThread::Exit(void) { if (m_Instance != NULL) { m_Instance->Stop(); DELETENULL(m_Instance); } } void cConflictCheckThread::Stop(void) { m_Active = false; Wait.Signal(); Cancel(6); } void cConflictCheckThread::Action(void) { SetPriority(CONFLICTCHECK_NICE); m_Active = true; // let VDR do its startup if (!m_runOnce) { if (!cPluginEpgsearch::VDR_readyafterStartup) LogFile.Log(2, "ConflictCheckThread: waiting for VDR to become ready..."); while(m_Active && !cPluginEpgsearch::VDR_readyafterStartup) Wait.Wait(1000); } time_t nextUpdate = time(NULL); while (m_Active && Running()) { time_t now = time(NULL); if (now >= nextUpdate || m_forceUpdate) { m_forceUpdate = false; if (Timers.BeingEdited()) { Wait.Wait(1000); continue; } LogFile.iSysLog("timer conflict check started"); cConflictCheck conflictCheck; conflictCheck.Check(); time_t nextConflict = 0; if (conflictCheck.relevantConflicts > 0) { cString msgfmt = ""; if (conflictCheck.relevantConflicts == 1) msgfmt = cString::sprintf(tr("timer conflict at %s! Show it?"), *DateTime(conflictCheck.nextRelevantConflictDate)); else msgfmt = cString::sprintf(tr("%d timer conflicts! First at %s. Show them?"), conflictCheck.relevantConflicts, *DateTime(conflictCheck.nextRelevantConflictDate)); bool doMessage = EPGSearchConfig.noConflMsgWhileReplay == 0 || !cDevice::PrimaryDevice()->Replaying() || conflictCheck.nextRelevantConflictDate - now < 2*60*60; if (doMessage && SendMsg(msgfmt, true,7, mtWarning) == kOk) { m_plugin->showConflicts = true; cRemote::CallPlugin("epgsearch"); } if (EPGSearchConfig.sendMailOnConflicts) { cMailConflictNotifier mailNotifier; mailNotifier.SendConflictNotifications(conflictCheck); } conflictCheck.EvaluateConflCheckCmd(); } // store for external access cConflictCheckThread::m_cacheNextConflict = conflictCheck.nextRelevantConflictDate; cConflictCheckThread::m_cacheRelevantConflicts = conflictCheck.relevantConflicts; cConflictCheckThread::m_cacheTotalConflicts = conflictCheck.numConflicts; LogFile.iSysLog("timer conflict check finished"); m_lastUpdate = time(NULL); int Intervall = EPGSearchConfig.conflictCheckIntervall; if (nextConflict > 0 && EPGSearchConfig.conflictCheckWithinLimit > 0 && nextConflict - time(NULL) < EPGSearchConfig.conflictCheckWithinLimit * 60) Intervall = EPGSearchConfig.conflictCheckIntervall2; nextUpdate = long(m_lastUpdate/60)*60 + (Intervall * 60); } if (m_Active && Running()) Wait.Wait(2000); // to avoid high system load if time%30==0 ????????????????????? // no waiting in the while loop if m_runOnce is true while (Running() && m_Active && time(NULL)%30 != 0 && !m_runOnce) // sync heart beat to a multiple of 5secs Wait.Wait(1000); }; m_Active = false; // always false at this point LogFile.iSysLog("Leaving conflict check thread"); } epgsearch-1.0.1.beta3/timerdone.h0000644000175000017500000000417312112105236015636 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __TIMERDONE_H #define __TIMERDONE_H #include #include using std::string; // --- cTimerDone -------------------------------------------------------- class cTimerDone : public cListObject { public: time_t start; // Start time of the timer time_t stop; // Stop time of the timer tChannelID channelID; int searchID; string title; string shorttext; cTimerDone(); cTimerDone(const time_t Start, const time_t Stop, const cEvent* pEvent, const int SearchID); bool operator== (const cTimerDone &arg) const; static bool Read(FILE *f); bool Parse(const char *s); cString ToText(void) const; bool Save(FILE *f); const cEvent* GetEvent() const; }; class cTimersDone : public cConfig, public cMutex { public: cTimerDone* InList(const time_t Start, const time_t Stop, const cEvent* pEvent, const int SearchID); void Update(const time_t Start, const time_t Stop, const cEvent* pEvent, const int SearchID, cTimerDone* timerdone); void ClearOutdated(void); void RemoveEntriesOfSearch(const int SearchID); }; extern cTimersDone TimersDone; #endif epgsearch-1.0.1.beta3/menu_searchactions.c0000644000175000017500000001477212112105223017517 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include #include "menu_commands.h" #include #include #include #include "menu_searchactions.h" #include "menu_searchresults.h" #include "menu_recsdone.h" #include "menu_timersdone.h" #include "menu_switchtimers.h" #include "menu_blacklists.h" #include "epgsearchtools.h" #include "menu_conflictcheck.h" #include "epgsearchcfg.h" #include "searchtimer_thread.h" #include "menu_searchedit.h" using namespace std; #define ACTION_COUNTER 11 extern int updateForced; // --- cMenuSearchActions --------------------------------------------------------- cMenuSearchActions::cMenuSearchActions(cSearchExt* Search, bool DirectCall) :cOsdMenu(tr("Search actions")) { #if VDRVERSNUM >= 10728 SetMenuCategory(mcCommand); #endif directCall = DirectCall; SetHasHotkeys(); search = Search; Add(new cOsdItem(hk(tr("Execute search")))); Add(new cOsdItem(hk(tr("Use as search timer on/off")))); Add(new cOsdItem(hk(tr("Trigger search timer update")))); Add(new cOsdItem(hk(tr("Show recordings done")))); Add(new cOsdItem(hk(tr("Show timers created")))); Add(new cOsdItem(hk(tr("Create a copy")))); Add(new cOsdItem(hk(tr("Use as template")))); Add(new cOsdItem(hk(tr("Show switch list")))); Add(new cOsdItem(hk(tr("Show blacklists")))); Add(new cOsdItem(hk(tr("Delete created timers?")))); Add(new cOsdItem(hk(tr("Timer conflict check")))); } cMenuSearchActions::~cMenuSearchActions() { } eOSState cMenuSearchActions::Search(void) { cMenuTemplate* MenuTemplate = NULL; if (!search) return osContinue; if (search->menuTemplate > 0) MenuTemplate = cTemplFile::GetSearchTemplateByPos(search->menuTemplate); if (!MenuTemplate) MenuTemplate = cTemplFile::GetTemplateByName("MenuSearchResults"); return AddSubMenu(new cMenuSearchResultsForSearch(search, MenuTemplate)); } eOSState cMenuSearchActions::OnOffSearchtimer(void) { if (search) { search->useAsSearchTimer = search->useAsSearchTimer?0:1; SearchExts.Save(); if (!search->useAsSearchTimer && Interface->Confirm(tr("Disable associated timers too?"))) search->OnOffTimers(false); if (search->useAsSearchTimer && Interface->Confirm(tr("Activate associated timers too?"))) { search->OnOffTimers(true); if (!EPGSearchConfig.useSearchTimers) // enable search timer thread if necessary { cSearchTimerThread::Init((cPluginEpgsearch*) cPluginManager::GetPlugin("epgsearch"), true); INFO(tr("Search timers activated in setup.")); } } } return osBack; } eOSState cMenuSearchActions::Execute() { int current = Current(); if (current <= ACTION_COUNTER-1) { if (current == 0) return Search(); if (current == 1) return OnOffSearchtimer(); if (current == 2) { if (!EPGSearchConfig.useSearchTimers) // enable search timer thread if necessary { cSearchTimerThread::Init((cPluginEpgsearch*) cPluginManager::GetPlugin("epgsearch"), true); INFO(tr("Search timers activated in setup.")); } if (Interface->Confirm(tr("Run search timer update?"))) updateForced = 3; // with message about completion return osBack; } if (current == 3 && search) return AddSubMenu(new cMenuRecsDone(search)); if (current == 4 && search) return AddSubMenu(new cMenuTimersDone(search)); if (current == 5 && search) { if (!Interface->Confirm(tr("Copy this entry?"))) return osBack; cSearchExt* copy = new cSearchExt; copy->CopyFromTemplate(search); string copyname = string(tr("Copy")) + ": " + search->search; strcpy(copy->search, copyname.c_str()); cMutexLock SearchExtsLock(&SearchExts); copy->ID = SearchExts.GetNewID(); SearchExts.Add(copy); SearchExts.Save(); return AddSubMenu(new cMenuEditSearchExt(copy)); } if (current == 6 && search) { if (!Interface->Confirm(tr("Copy this entry to templates?"))) return osBack; cSearchExt* templateObj = new cSearchExt; templateObj->CopyFromTemplate(search); strcpy(templateObj->search, search->search); cMutexLock SearchTemplatesLock(&SearchTemplates); templateObj->ID = SearchTemplates.GetNewID(); SearchTemplates.Add(templateObj); SearchTemplates.Save(); return osBack; } if (current == 7) return AddSubMenu(new cMenuSwitchTimers()); if (current == 8) return AddSubMenu(new cMenuBlacklists()); if (current == 9) { if (!Interface->Confirm(tr("Delete all timers created from this search?"))) return osBack; search->DeleteAllTimers(); return osBack; } if (current == 10) return AddSubMenu(new cMenuConflictCheck()); } return osContinue; } eOSState cMenuSearchActions::ProcessKey(eKeys Key) { bool hadSubmenu = HasSubMenu(); if (directCall && Key == k1 && !HasSubMenu()) return Search(); eOSState state = cOsdMenu::ProcessKey(Key); // jump back to calling menu, if a command was called directly with key '1' .. '9' if (directCall && hadSubmenu && !HasSubMenu()) return osBack; if (state == osUnknown) { switch (Key) { case kGreen: case kYellow: case kBlue: return osContinue; case kOk: if (!HasSubMenu()) return Execute(); default: break; } } return state; } epgsearch-1.0.1.beta3/docsrc2man.sh0000755000175000017500000000247112100027257016073 0ustar winniwinni#!/bin/sh # # Creates the man pages # # Needs: pod2man and nroff # # Mike Constabel # # Version 0.1 - 31.07.2006 # DOCSRC="doc-src" if [ ! -s "epgsearch.c" ]; then echo "Cannot find epgsearch.c. Call this script from epgsearch source directory." exit fi VERSION="$(awk -F\" '/VERSION/ {print $2; exit;}' epgsearch.c)" for LANGUAGE in $(ls "$DOCSRC"/); do [ ! -d ""$DOCSRC"/$LANGUAGE" ] && continue mkdir -p man/$LANGUAGE rm man/$LANGUAGE/* 2>/dev/null for i in "$DOCSRC"/$LANGUAGE/*.txt; do echo -ne "create man page: ($LANGUAGE) $(basename "$i" ".txt")..." name=$(echo "$(basename "$i")" | sed -e 's/\.[0-9]\..*$//') sect=$(echo "$i" | sed -e 's/.*\.\([0-9]\)\.txt/\1/') pod2man -c "Epgsearch Version $VERSION" -n "$name" --section="$sect" "$i" >"man/$LANGUAGE/$(basename "$i" ".txt")" if [ $? -eq 0 ]; then echo " done." else echo " failed." fi done rm "$DOCSRC"/$LANGUAGE/*~ 2>/dev/null gzip -f man/$LANGUAGE/*.[0-9] done echo for LANGUAGE in $(ls "$DOCSRC"/); do [ ! -d "$DOCSRC/$LANGUAGE" ] && continue mkdir -p doc/$LANGUAGE rm doc/$LANGUAGE/* 2>/dev/null for i in man/$LANGUAGE/*.gz; do echo -ne "create doc file from man page: ($LANGUAGE) $(basename "$i")..." zcat "$i" | nroff -man - | col -xbp > "doc/$LANGUAGE/$(basename "$i" ".gz").txt" echo " done" done done echo #EOF epgsearch-1.0.1.beta3/conflictcheck_thread.h0000644000175000017500000000340612112105236017774 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef VDR_CONFLICTCHECK_THREAD_H #define VDR_CONFLICTCHECK_THREAD_H #include #include "conflictcheck.h" #include "epgsearch.h" class cConflictCheckThread: public cThread { private: bool m_Active; time_t m_lastUpdate; cPluginEpgsearch* m_plugin; static bool m_runOnce; static bool m_forceUpdate; cCondWait Wait; protected: virtual void Action(void); void Stop(void); public: static cConflictCheckThread *m_Instance; static time_t m_cacheNextConflict; static int m_cacheRelevantConflicts; static int m_cacheTotalConflicts; cConflictCheckThread(cPluginEpgsearch* thePlugin); virtual ~cConflictCheckThread(); static void Init(cPluginEpgsearch* thePlugin, bool runOnce = false); static void Exit(void); }; #endif epgsearch-1.0.1.beta3/switchtimer.c0000644000175000017500000001110412112105223016171 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include "switchtimer.h" #include "epgsearchtools.h" cSwitchTimers SwitchTimers; // -- cSwitchTimer ----------------------------------------------------------------- cSwitchTimer::cSwitchTimer(void) { switchMinsBefore = 1; mode = 0; unmute = 0; } cSwitchTimer::cSwitchTimer(const cEvent* Event, int SwitchMinsBefore, int Mode, int Unmute) { eventID = 0; startTime = 0; if (Event) { eventID = Event->EventID(); channelID = Event->ChannelID(); startTime = Event->StartTime(); } switchMinsBefore = SwitchMinsBefore; mode = Mode; unmute = Unmute; } bool cSwitchTimer::Parse(const char *s) { char *line; char *pos; char *pos_next; int parameter = 1; int valuelen; #define MAXVALUELEN (10 * MaxFileName) char value[MAXVALUELEN]; startTime=0; pos = line = strdup(s); pos_next = pos + strlen(pos); if (*pos_next == '\n') *pos_next = 0; while (*pos) { while (*pos == ' ') pos++; if (*pos) { if (*pos != ':') { pos_next = strchr(pos, ':'); if (!pos_next) pos_next = pos + strlen(pos); valuelen = pos_next - pos + 1; if (valuelen > MAXVALUELEN) valuelen = MAXVALUELEN; strn0cpy(value, pos, valuelen); pos = pos_next; switch (parameter) { case 1: channelID = tChannelID::FromString(value); break; case 2: eventID = atoi(value); break; case 3: startTime = atol(value); break; case 4: switchMinsBefore = atoi(value); break; case 5: mode = atoi(value); break; case 6: unmute = atoi(value); break; default: break; } //switch } parameter++; } if (*pos) pos++; } //while free(line); return (parameter >= 3) ? true : false; } const cEvent* cSwitchTimer::Event() { time_t now = time(NULL); const cEvent* event = NULL; if (startTime > now) { cSchedulesLock schedulesLock; const cSchedules* schedules = cSchedules::Schedules(schedulesLock); if (!schedules) return NULL; const cSchedule *Schedule = schedules->GetSchedule(channelID); if (Schedule) { event = Schedule->GetEvent(eventID, startTime); if (!event) event = Schedule->GetEventAround(startTime); } } return event; } cString cSwitchTimer::ToText(bool& ignore) { ignore = false; if (!Event()) { ignore = true; return NULL; } cChannel *channel = Channels.GetByChannelID(channelID, true, true); if (!channel) return NULL; cString buffer = cString::sprintf("%s:%u:%ld:%d:%d:%d", CHANNELSTRING(channel), eventID, startTime, switchMinsBefore, mode, unmute?1:0); return buffer; } bool cSwitchTimer::Save(FILE *f) { bool ignore = false; cString buffer = ToText(ignore); if (!ignore) return fprintf(f, "%s\n", *buffer) > 0; return true; } cSwitchTimer* cSwitchTimers::InSwitchList(const cEvent* event) { if (!event) return false; cMutexLock SwitchTimersLock(this); cSwitchTimer* switchTimer = SwitchTimers.First(); while (switchTimer) { if (switchTimer->eventID == event->EventID() && switchTimer->channelID == event->ChannelID() && switchTimer->startTime == event->StartTime()) return switchTimer; switchTimer = SwitchTimers.Next(switchTimer); } return NULL; } bool cSwitchTimers::Exists(const cSwitchTimer* SwitchTimer) { cMutexLock SwitchTimersLock(this); cSwitchTimer* switchTimer = SwitchTimers.First(); while (switchTimer) { if (switchTimer == SwitchTimer) return true; switchTimer = SwitchTimers.Next(switchTimer); } return false; } epgsearch-1.0.1.beta3/timerstatus.c0000644000175000017500000000335512112105223016224 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include "timerstatus.h" cTimerStatusMonitor* gl_timerStatusMonitor = NULL; cTimerStatusMonitor::cTimerStatusMonitor() { conflictCheckAdvised = true; } void cTimerStatusMonitor::TimerChange(const cTimer *Timer, eTimerChange Change) { // vdr-1.5.15 and above will inform us, when there are any timer changes. // so timer changes (within epgsearch) in previous versions have to be tracked // at the correspondig places. conflictCheckAdvised = true; } void cTimerStatusMonitor::SetConflictCheckAdvised(bool ConflictCheckAdvised) { if (!ConflictCheckAdvised) conflictCheckAdvised = false; #if APIVERSNUM < 10515 conflictCheckAdvised = ConflictCheckAdvised; #endif } bool cTimerStatusMonitor::ConflictCheckAdvised() { return conflictCheckAdvised; } epgsearch-1.0.1.beta3/mail.h0000644000175000017500000001001312112105236014560 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __EPGSEARCH_MAIL_H #define __EPGSEARCH_MAIL_H #include #include #include #include #include "conflictcheck.h" using std::string; using std::set; // --- cMailNotifier -------------------------------------------------------- class cMailNotifier { protected: string subject; string body; bool SendMailViaSendmail(); bool SendMailViaScript(); bool SendMail(bool force=false); bool ExecuteMailScript(string ScriptArgs); public: string scriptReply; cMailNotifier() {} cMailNotifier(string Subject, string Body); bool TestMailAccount(string MailAddressTo, string MailAddress, string MailServer, string AuthUser, string AuthPass); static string LoadTemplate(const string& templtype); static string GetTemplValue(const string& templ, const string& entry); static string MailCmd; }; class cMailTimerNotification { friend class cMailUpdateNotifier; tEventID eventID; tChannelID channelID; uint timerMod; protected: virtual const cEvent* GetEvent() const; public: cMailTimerNotification(tEventID EventID, tChannelID ChannelID, uint TimerMod = tmNoChange) : eventID(EventID), channelID(ChannelID), timerMod(TimerMod) {} virtual bool operator< (const cMailTimerNotification &N) const; virtual string Format(const string& templ) const; }; class cMailDelTimerNotification { friend class cMailUpdateNotifier; time_t start; tChannelID channelID; public: string formatted; cMailDelTimerNotification(cTimer* t, const cEvent* pEvent, const string& templ); cMailDelTimerNotification(const string& Formatted, tChannelID ChannelID, time_t Start); bool operator< (const cMailDelTimerNotification &N) const; string Format(const string& templ) const { return formatted; } }; class cMailAnnounceEventNotification : public cMailTimerNotification { friend class cMailUpdateNotifier; int searchextID; public: cMailAnnounceEventNotification(tEventID EventID, tChannelID ChannelID, int SearchExtID) : cMailTimerNotification(EventID, ChannelID), searchextID(SearchExtID) {} string Format(const string& templ) const; }; class cMailUpdateNotifier : public cMailNotifier { set newTimers; set modTimers; set delTimers; set announceEvents; string mailTemplate; public: cMailUpdateNotifier(); void AddNewTimerNotification(tEventID EventID, tChannelID ChannelID); void AddModTimerNotification(tEventID EventID, tChannelID ChannelID, uint timerMod = tmNoChange); void AddRemoveTimerNotification(cTimer* t, const cEvent* e = NULL); void AddRemoveTimerNotification(const string& Formatted, tChannelID ChannelID, time_t Start); void AddAnnounceEventNotification(tEventID EventID, tChannelID ChannelID, int SearchExtID); void SendUpdateNotifications(); }; class cMailConflictNotifier : public cMailNotifier { public: void SendConflictNotifications(cConflictCheck& conflictcheck); }; #endif epgsearch-1.0.1.beta3/quickepgsearch.c0000644000175000017500000000404112112105223016627 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include #include #include "services.h" #include "mainmenushortcut.h" static const char VERSION[] = "0.0.1"; static const char DESCRIPTION[] = trNOOP("Quick search for broadcasts"); static const char MAINMENUENTRY[] = trNOOP("Quick search"); static const char SETUPTEXT[] = trNOOP("Show in main menu"); class cPluginQuicksearch : public cMainMenuShortcut { public: virtual const char* Version() { return VERSION; } virtual const char* Description() { return I18nTranslate(DESCRIPTION, I18nEpgsearch); } virtual bool Initialize(); virtual cOsdObject* MainMenuAction() { return GetEpgSearchMenu("Epgsearch-quicksearch-v1.0"); }; protected: virtual const char* SetupText() { return I18nTranslate(SETUPTEXT, I18nEpgsearch); } virtual const char* MainMenuText() { return I18nTranslate(MAINMENUENTRY, I18nEpgsearch); } }; bool cPluginQuicksearch::Initialize() { return cMainMenuShortcut::Initialize(); } VDRPLUGINCREATOR(cPluginQuicksearch); // Don't touch this! epgsearch-1.0.1.beta3/source/0000755000175000017500000000000012100027260014767 5ustar winniwinniepgsearch-1.0.1.beta3/source/vdr-epgsearchclient-0.0.2.tgz0000644000175000017500000002433412100027260022107 0ustar winniwinniO\wFϯyĔz v`iξ=94Hvi^o tyvisY3% ?5G477ϓfFi57#Kƞܹ;O'ӧ|y:`>{㽟?ط>ۚkЋgϦd\]GU7l(@:BP=z .Qv.;GGn3;lܱ(`Rp{NCyY7w{.>]bGoy%,ȵ"fa GA)+K'yϺΰw56siI L yB哹lu?%2uS0j5f_ ?Nu4XǕ*ba]Ǎ]{S3!u[C6 |^ |5GU`%ش\JELEPX-]A/gVrSJ4(GRGS73Xqx88`*U>j2#FGs}b޹~\t2 ."pf׵؁\r%y OYeGRbB-`Vt6H˓MڦbBL4 //5m؍AigP؋ˉ` "$@~pkvo@r"ž֖M6i8uw۳ç9.ǵ˪̝#W1/ +6[ bCRR'(,auT*/M__\T lOv4C3q :ܗIj583.jz3y[=̂zn ͡dpi" "o,YA s ~1tCn]@",P \Usa$Uyr3I*.C6̗Kz%"\J+r PɍȲ܎'Ng0L!4 HO4J5&`DNsPL8)v2.C%)y&S~i2 /O5˧Rvд 5^wݸQWJL& b~A@F:_mGx"Y),dRzRT֓HW: -?O SdWT0>{VwP7IQ:$!!꧈ҍ*GӶbe"3f&0\ v3iA ǡXJJ8Y cF϶4? {n)؂.~1pM=߼."sA澝F SS s"ȔfS,'3[toa,!0l!hK>nMcb fi 9BID.k k+i0" הDusFtB*92*  ;/^ /քm -ns9/( A@[# 5b%n]eC>¸Gri @L[ъF^x6BWOTq(J%YQ|!:5e6;ɍيC(}P|A]1d^^l=[e?w٨wengXhCv5]wH W( (WfOp!Sj)hƶE r&!>^}y}1qc`‰ ȋ`T/@""Q>9\X= gPBqj10؇ӝLM  P5L1Hq `$7'j čO"f#&+q~vXLX^iF! X1`Ս".W,/*؇6F7f֣a> QEp}W}bN#(0tp-`% 86IKat͖=R^OX1]NR 8S O5T0._a= UN(,gn˸+7yg'Qq==~vFk _ -tHll[VtlXp{1TTwC:B2u<@68kGrߌ.uWo:B! Zf ko=|x&?!/9>_[_dɇx`ao tPz2=0c5M_΅k"rC`^^Bj% p'Sx dsCaX@M@" [i4PZ$\ZW#0zJ zzvj.@ՙ!۾1_5=譥m?ݰhU3aj`,u_f{oGrH̢d򋎪>eoW#^koP .Y;`%>4>jg?< Az b]`]ֺz_^G"P`R;_ຉc0e`eՒ{eͱB1> *@4۞!$bfyd1 VDfpά0bC+y pd{" 9II#}{Uʝ_Yx<J+•JN%6Y)YӕYWq'5~ %=5jw~j[GBn|Wi,fS :6TgܦS|!}%G7c޽_ .|"/zo{T^2bِP?JqE=0.p;tS=h?mkg  H-1؟fJK.?uϺWėh./Wy_w2C,$N-VneCRȾ @S~`/4k,L'CpkAA8(H:9[O%8 "7ayaVb\_W9}Q_s a@&&0@E΋ FufkߑJ=j6Y=`!opvq O@VB|p5ql&~lPm}/e{`x\?vZuyFvxb@!]k& ?Ty$ӣQs6PW~wؾ`W//zwpā?f%rJM\ F4å9PyT"nmo;6xQۢF1.юU2(/یAh6kM cףź"[ ܅\<| t=A F,O56Ufx崫/p\[ nBWP-&PՂfXJ6U 9S-ݙ%E#,9)͆QI“\TgHrJOBB8E 4,ĉ,wsr+lk5ȬJWQ_{L7RVuF@ֺh,NB>fٷkXL,6xgNZd0|J&Vt(+=} RyatM9w |Hܜ(U$S^8O.Lo$V0APGԼ77h j"IP")BJf*bo4|. 5f}hْ֨;rFPݹj^@[>N |q 80 PcFc D"M~A)]^O8459ѽXY. GDڢVf-YENds|A7Q%'&pv|\}Mvl:}ce+Cֵ 8Ð%9X5Z^jetTE`.  ` "0tl%S>,P,9DZܬd:ºV{"zf`TZtƣW0<4DӘGR={AOF6 *I`3|,0n[JgItxML 3'5IxKԉ9-2&ߒyR4rW1QZ|$D6KG6S^\hq CqRlI}=rR(״6^B :һ_\+\'kx&e[M^('ԥ¤/"z~7Hhl#1bikh :FneS(AUVj#څ4~5<x9}NiIX;:i`t'>Fնv13Z,nȐ+kO'd/ eSH^cs(KI(Ub E)k hN{܄>kP19}ǃhR J" pNCv 9Ƒ74[Ab{ZlcxY5NB|ugxxDc1VγϣSHwMk7AЬ|MCSU&[njN}Z(鮀py  ;B ndnh-4"?ӪǼcWi A&H_iDc`Tu5q@w.=qh{8B˽9PU-pnhS^( sZ]iUfy`U5$$rj!q,Y Rv~}[-4]ESIz ÅTcS(#|y \voYS߰h&S?q?r ?DQ@(LiHCVO+"a73^ҽYN w0 ؙSt Ӛ.E7j0:e ,牐{R5[v^3yDMV Q!l AJzFrOȰphuB#ߜ>L=Xbg%>5 RC20 gRƲR}f0Ҷx`p$ M)nN0zZg㋱^7XђHRo"^Z\/4E^(Z d Z)@kw5F-,Bza:Pf]GPLD*^ 1+`uýC"2\QX1= + I\5f4;Z 7g.uK 6.kzpfeY<nw |Y|DPғ[PنSđ|an*Bzl A릟P <ܽIr^5T_Ch;b\*[M1^ؽO5+hu;{&EGo{:0=Ǩ:< .1=3^Ǥ2ᇋUZd2EwcQ%htvq  SOX\ZI!ߦ4j rm{bԞ@K)Eydq԰3R| #cy R"TsΉ QX_z5fKZZhNI$\G d/ŕ2pqVSOڐ~wFnӳ sћZx[\ 1x֎WS>orL MiClȣV'q&b GD@og̤w7gRrDӺڊ}GJAt#཈S[SXXrհ}D2"5 |BdTsY$g Dv͡ QaB8+>;EeK iu[, /:YbPkVq5ѠS(-cr"":^655؞3>b4-~խEs4pP J7ϻ?`v=gLLFl+jRDj7`iXTZJN^k:Mp_¯ogH}Ne> وϫ*N \?: %{IZ܋'Ty Ҽwa>V ~"~JbYbJJ^[#88e(JjQt"̓k8ziH89\;?߶OW‘."]3]7=pgR/O̠w^Įi..QE2Pjf~)pΊ Y\]U:(aWZj]#], IC QιH-8wX/># + J!:[R7Jbص^,ӛbnq<<L%;n:x)k=Z uFDlI#vA$kea_E^F& حo3@omRUF:oAԪ7֋Ty@j'yUt qؙ{t-ao zImTG&CKr9 V័ 7f6VIcXo؇8'm0X|C%sC$!Ƴiq~v,?Vgb@TF}§S7-UUQ܆{Q0fF'O۶f~N&ÛWgEv98~JGSgžO?L,H/M2lVٯffOLZoou^jf^fUvg:Me2(4"dj^guaz;F4q| 27j|7 p_F7i6bCٯl*O'q& Hn3Y's6޺ FO>eYbt=.0HuwCv<J#/pnՕ6> o.Qtӯ;X { X,}g^yS}lq,uz]x4|]bIv;MRr'2Q6O$ l=6EڰѾ'_F9v~kP1Ux0s+"t/X ψÒ`AE BL>H#ѓUSWܭ+Fҡl'9-ݸHsyݓ?x aNfÔ#^dx{z8 //&rL䰍n) 6M?ڙ Ƥb')I ; &uQ)hH{+<$^rmQ :r0]&0L~sLM|ϗjr |+LkƤ)<1B`~b7|F?L>NtIV7®" g'w@oB4mz.C*&?W2QN) +-L_'IA//Ҩ硺ˊ~0eP=U즃[0Pj );nal˒>g NŚV9NstqhܸC ?*dxwIƠS:h̴jU:\DOpFҘZßY*?]ϟ$(Jd -Z.@ULH㪾=;t=uѫJrc7U ُS%+ѩ>a).wqQz!/k_c|N0iH[￱tY{*5=h`T!xym<3s|9>s|9>s|8Oepgsearch-1.0.1.beta3/menu_searchedit.c0000644000175000017500000012563212112105223017002 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include #include #include "menu_searchedit.h" #include "changrp.h" #include "epgsearchcats.h" #include "epgsearchtools.h" #include "menu_dirselect.h" #include "menu_recsdone.h" #include "menu_searchtemplate.h" #include "epgsearchcfg.h" #include "blacklist.h" #include "menu_blacklists.h" #include "epgsearch.h" #include "searchtimer_thread.h" #include #include "templatefile.h" using namespace std; cChannelGroups ChannelGroups; cSearchExtCats SearchExtCats; // --- cMenuEditSearchExt -------------------------------------------------------- cMenuEditSearchExt::cMenuEditSearchExt(cSearchExt *SearchExt, bool New, bool Template, bool FromEPG) :cOsdMenu(tr("Edit search"),32) { #if VDRVERSNUM >= 10728 SetMenuCategory(mcPlugin); #endif templateMode = Template; SearchModes[0] = strdup(tr("phrase")); SearchModes[1] = strdup(tr("all words")); SearchModes[2] = strdup(tr("at least one word")); SearchModes[3] = strdup(tr("match exactly")); SearchModes[4] = strdup(tr("regular expression")); SearchModes[5] = strdup(tr("fuzzy")); DaysOfWeek[0] = strdup(WeekDayName(0)); DaysOfWeek[1] = strdup(WeekDayName(1)); DaysOfWeek[2] = strdup(WeekDayName(2)); DaysOfWeek[3] = strdup(WeekDayName(3)); DaysOfWeek[4] = strdup(WeekDayName(4)); DaysOfWeek[5] = strdup(WeekDayName(5)); DaysOfWeek[6] = strdup(WeekDayName(6)); DaysOfWeek[7] = strdup(tr("user-defined")); UseChannelSel[0] = strdup(trVDR("no")); UseChannelSel[1] = strdup(tr("interval")); UseChannelSel[2] = strdup(tr("channel group")); UseChannelSel[3] = strdup(tr("only FTA")); SearchTimerModes[0] = strdup(tr("Record")); SearchTimerModes[1] = strdup(tr("Announce by OSD")); SearchTimerModes[2] = strdup(tr("Switch only")); SearchTimerModes[3] = strdup(tr("Announce and switch")); SearchTimerModes[4] = strdup(tr("Announce by mail")); BlacklistModes[0] = strdup(tr("only globals")); BlacklistModes[1] = strdup(tr("Selection")); BlacklistModes[2] = strdup(tr("all")); BlacklistModes[3] = strdup(trVDR("none")); DelModes[0] = strdup(trVDR("no")); DelModes[1] = strdup(tr("count recordings")); DelModes[2] = strdup(tr("count days")); SearchActiveModes[0] = strdup(trVDR("no")); SearchActiveModes[1] = strdup(trVDR("yes")); SearchActiveModes[2] = strdup(tr("user-defined")); CompareSubtitleModes[0] = strdup(trVDR("no")); CompareSubtitleModes[1] = strdup(tr("if present")); CompareDateModes[0] = strdup(trVDR("no")); CompareDateModes[1] = strdup(tr("same day")); CompareDateModes[2] = strdup(tr("same week")); CompareDateModes[3] = strdup(tr("same month")); #if APIVERSNUM > 10710 // collect content string IDs std::set contentStrings; for(unsigned int i=0; iID == EPGSearchConfig.DefSearchTemplateID) SearchTempl = SearchExtTempl; SearchExtTempl = SearchTemplates.Next(SearchExtTempl); } if (SearchTempl) SearchExt->CopyFromTemplate(SearchTempl, FromEPG); } searchExt = SearchExt; addIfConfirmed = New; if (!templateMode) SetHelp(NULL, NULL, tr("Button$Help"), tr("Button$Templates")); if (searchExt) { data = *searchExt; UserDefDayOfWeek = 0; if (searchExt->DayOfWeek < 0) { UserDefDayOfWeek = searchExt->DayOfWeek; data.DayOfWeek = 7; } menuitemsChGr = NULL; channelGroupName = NULL; channelMin = channelMax = cDevice::CurrentChannel(); channelGroupNr = 0; if (data.channelMin) channelMin = data.channelMin->Number(); if (data.channelMax) channelMax = data.channelMax->Number(); if (data.useChannel==2) { channelGroupNr = ChannelGroups.GetIndex(data.channelGroup); if (channelGroupNr == -1) { free(data.channelGroup); data.channelGroup = NULL; channelGroupNr = 0; // no selection } else { channelGroupName = strdup(data.channelGroup); channelGroupNr++; } } contentStringsFlags = NULL; #if APIVERSNUM > 10710 // set the flags for the content descriptors contentStringsFlags = (int*) malloc((CONTENT_DESCRIPTOR_MAX+1) * sizeof(int)); for(unsigned int i=0; i<=CONTENT_DESCRIPTOR_MAX;i++) contentStringsFlags[i] = data.HasContent(i); useContentDescriptors = (data.contentsFilter.size() > 0); #endif catarrayAvoidRepeats = NULL; catvaluesNumeric = NULL; if (SearchExtCats.Count() > 0) { // fill an array, that stores yes/no for using categories in avoid repeats catarrayAvoidRepeats = (int*) malloc(SearchExtCats.Count() * sizeof(int)); catvaluesNumeric = (int*) malloc(SearchExtCats.Count() * sizeof(int)); cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { catarrayAvoidRepeats[index] = (SearchExt->catvaluesAvoidRepeat & (1<catvalues[index]); SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } } blacklists.Clear(); if (data.blacklistMode == blacklistsSelection) { cBlacklistObject* blacklistObj = searchExt->blacklists.First(); while(blacklistObj) { blacklists.Add(new cBlacklistObject(blacklistObj->blacklist)); blacklistObj = searchExt->blacklists.Next(blacklistObj); } } Set(); } } void cMenuEditSearchExt::AddHelp(const char* helpText) { helpTexts.push_back(helpText); } void cMenuEditSearchExt::Set() { int current = Current(); Clear(); helpTexts.clear(); if (templateMode) { Add(new cMenuEditStrItem( tr("Template name"), data.search, sizeof(data.search), tr(AllowedChars))); AddHelp(tr("Help$Specify the name of the template.")); } else { Add(new cMenuEditStrItem( tr("Search term"), data.search, sizeof(data.search), tr(AllowedChars))); AddHelp(tr("Help$Specify here the term to search for.")); } Add(new cMenuEditStraItem(tr("Search mode"), &data.mode, 6, SearchModes)); AddHelp(tr("Help$The following search modes exist:\n\n- phrase: searches for sub terms\n- all words: all single words must appear\n- at least one word: at least one single word must appear\n- match exactly: must match exactly\n- regular expression: match a regular expression\n- fuzzy searching: searches approximately")); if (data.mode == 5) // fuzzy { Add(new cMenuEditIntItem(IndentMenuItem(tr("Tolerance")), &data.fuzzyTolerance, 1, 9)); AddHelp(tr("Help$This sets the tolerance of fuzzy searching. The value represents the allowed errors.")); } Add(new cMenuEditBoolItem( tr("Match case"), &data.useCase, trVDR("no"), trVDR("yes"))); AddHelp(tr("Help$Set this to 'Yes' if your search should match the case.")); Add(new cMenuEditBoolItem( tr("Use title"), &data.useTitle, trVDR("no"), trVDR("yes"))); AddHelp(tr("Help$Set this to 'Yes' if you like to search in the title of an event.")); Add(new cMenuEditBoolItem( tr("Use subtitle"), &data.useSubtitle, trVDR("no"), trVDR("yes"))); AddHelp(tr("Help$Set this to 'Yes' if you like to search in the episode of an event.")); Add(new cMenuEditBoolItem( tr("Use description"), &data.useDescription, trVDR("no"), trVDR("yes"))); AddHelp(tr("Help$Set this to 'Yes' if you like to search in the summary of an event.")); #if APIVERSNUM > 10710 Add(new cMenuEditBoolItem( tr("Use content descriptor"), &useContentDescriptors, trVDR("no"), trVDR("yes"))); AddHelp(tr("Help$Set this to 'Yes' if you want to search the contents by a descriptor.")); if (useContentDescriptors) { vector::const_iterator it; for(unsigned int i=0; i< contentStringIDs.size(); i++) { int level = (contentStringIDs[i] % 0x10==0?1:2); Add(new cMenuEditBoolItem(IndentMenuItem(tr(cEvent::ContentToString(contentStringIDs[i])), level), &contentStringsFlags[contentStringIDs[i]], trVDR("no"), trVDR("yes"))); } } #endif // show Categories only if we have them if (SearchExtCats.Count() > 0) { Add(new cMenuEditBoolItem( tr("Use extended EPG info"), &data.useExtEPGInfo, trVDR("no"), trVDR("yes"))); AddHelp(tr("Help$The summary of an event, can contain additional information like 'Genre', 'Category', 'Year',... called 'EPG categories' within EPGSearch. External EPG providers often deliver this information. This allows refining a search and other nice things, like searching for the 'tip of the day'. To use it set this to 'Yes'.")); if (data.useExtEPGInfo) { cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { if (SearchExtCat->searchmode >= 10) Add(new cMenuEditIntItem(IndentMenuItem(SearchExtCat->menuname), &catvaluesNumeric[index], 0, 999999, "")); else Add(new cMenuEditStrItem( IndentMenuItem(SearchExtCat->menuname), data.catvalues[index], MaxFileName, tr(AllowedChars))); AddHelp(tr("Help$The file epgsearchcats.conf specifies the search mode for this entry. One can search by text or by value. You can also edit a list of predefined values in this file that can be selected here.")); SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } Add(new cMenuEditBoolItem(IndentMenuItem(tr("Ignore missing categories")), &data.ignoreMissingEPGCats, trVDR("no"), trVDR("yes"))); AddHelp(tr("Help$If a selected category is not part of the summary of an event this normally excludes this event from the search results. To avoid this, set this option to 'Yes', but please handle this with care to avoid a huge amount of results.")); } } Add(new cMenuEditStraItem(tr("Use channel"), &data.useChannel, 4, UseChannelSel)); if (data.useChannel==1) { Add(new cMenuEditChanItem(tr(" from channel"), &channelMin)); Add(new cMenuEditChanItem(tr(" to channel"), &channelMax)); } if (data.useChannel==2) { // create the char array for the menu display if (menuitemsChGr) delete [] menuitemsChGr; menuitemsChGr = ChannelGroups.CreateMenuitemsList(); int oldchannelGroupNr = channelGroupNr; channelGroupNr = ChannelGroups.GetIndex(channelGroupName); if (channelGroupNr == -1) { if (oldchannelGroupNr > 0 && oldchannelGroupNr <= ChannelGroups.Count()) // perhaps its name was changed channelGroupNr = oldchannelGroupNr; else channelGroupNr = 0; // no selection } else channelGroupNr++; Add(new cMenuEditStraItem(IndentMenuItem(tr("Channel group")), &channelGroupNr, ChannelGroups.Count()+1, menuitemsChGr)); } Add(new cMenuEditBoolItem( tr("Use time"), &data.useTime, trVDR("no"), trVDR("yes"))); if (data.useTime == true) { Add(new cMenuEditTimeItem(tr(" Start after"), &data.startTime)); Add(new cMenuEditTimeItem(tr(" Start before"), &data.stopTime)); } Add(new cMenuEditBoolItem( tr("Use duration"), &data.useDuration, trVDR("no"), trVDR("yes"))); if (data.useDuration == true) { Add(new cMenuEditTimeItem(tr(" Min. duration"), &data.minDuration)); Add(new cMenuEditTimeItem(tr(" Max. duration"), &data.maxDuration)); } Add(new cMenuEditBoolItem( tr("Use day of week"), &data.useDayOfWeek, trVDR("no"), trVDR("yes"))); if (data.useDayOfWeek) { if (data.DayOfWeek < 0) { UserDefDayOfWeek = data.DayOfWeek; data.DayOfWeek = 7; } Add(new cMenuEditStraItem(IndentMenuItem(tr("Day of week")), &data.DayOfWeek, 8, DaysOfWeek)); } Add(new cMenuEditStraItem(tr("Use blacklists"), &data.blacklistMode, 4, BlacklistModes)); if (EPGSearchConfig.showFavoritesMenu) Add(new cMenuEditBoolItem( tr("Use in favorites menu"), &data.useInFavorites, trVDR("no"), trVDR("yes"))); int countSearchTemplates = 0; if ((countSearchTemplates = cTemplFile::CountSearchResultsTemplates()) > 1) { Add(new cMenuEditStraItem(tr("Result menu layout"), &data.menuTemplate, countSearchTemplates, cTemplFile::SearchTemplates)); } Add(new cMenuEditStraItem( tr("Use as search timer"), &data.useAsSearchTimer, 3, SearchActiveModes)); if (data.useAsSearchTimer) { Add(new cMenuEditStraItem(IndentMenuItem(tr("Action")), &data.action, 5, SearchTimerModes)); if (data.action == searchTimerActionSwitchOnly) { Add(new cMenuEditIntItem(IndentMenuItem(tr("Switch ... minutes before start")), &data.switchMinsBefore, 0, 99)); Add(new cMenuEditBoolItem(IndentMenuItem(tr("Unmute sound")), &data.unmuteSoundOnSwitch, trVDR("no"), trVDR("yes"))); } if (data.action == searchTimerActionAnnounceAndSwitch) { Add(new cMenuEditIntItem(IndentMenuItem(tr("Ask ... minutes before start")), &data.switchMinsBefore, 0, 99)); Add(new cMenuEditBoolItem(IndentMenuItem(tr("Unmute sound")), &data.unmuteSoundOnSwitch, trVDR("no"), trVDR("yes"))); } if (data.action == searchTimerActionRecord) { Add(new cMenuEditBoolItem( tr(" Series recording"), &data.useEpisode, trVDR("no"), trVDR("yes"))); Add(new cMenuEditStrItem(IndentMenuItem(tr("Directory")), data.directory, sizeof(data.directory), tr(AllowedChars))); Add(new cMenuEditIntItem(IndentMenuItem(tr("Delete recordings after ... days")), &data.delAfterDays, 0, 999)); if (data.delAfterDays > 0) Add(new cMenuEditIntItem(IndentMenuItem(IndentMenuItem(tr("Keep ... recordings"))), &data.recordingsKeep, 0, 999)); Add(new cMenuEditIntItem(IndentMenuItem(tr("Pause when ... recordings exist")), &data.pauseOnNrRecordings, 0, 999)); Add(new cMenuEditBoolItem(IndentMenuItem(tr("Avoid repeats")), &data.avoidRepeats, trVDR("no"), trVDR("yes"))); if (data.avoidRepeats) { Add(new cMenuEditIntItem(IndentMenuItem(tr("Allowed repeats"),2), &data.allowedRepeats, 0, 99)); if (data.allowedRepeats > 0) Add(new cMenuEditIntItem(IndentMenuItem(tr("Only repeats within ... days"),2), &data.repeatsWithinDays, 0, 999)); Add(new cMenuEditBoolItem(IndentMenuItem(tr("Compare title"),2), &data.compareTitle, trVDR("no"), trVDR("yes"))); Add(new cMenuEditStraItem(IndentMenuItem(tr("Compare subtitle"),2), &data.compareSubtitle, 2, CompareSubtitleModes)); Add(new cMenuEditBoolItem(IndentMenuItem(tr("Compare summary"),2), &data.compareSummary, trVDR("no"), trVDR("yes"))); if (data.compareSummary) Add(new cMenuEditIntItem(IndentMenuItem(tr("Min. match in %"),3), &data.compareSummaryMatchInPercent, 1, 100)); Add(new cMenuEditStraItem(IndentMenuItem(tr("Compare date"),2), &data.compareDate, 4, CompareDateModes)); // show 'Compare categories' only if we have them if (SearchExtCats.Count() > 0) { cSearchExtCat *SearchExtCat = SearchExtCats.First(); int iUsed = 0; int index = 0; while (SearchExtCat) { if (catarrayAvoidRepeats[index]) iUsed++; SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } cString itemtext = cString::sprintf("%s (%d/%d)", tr("Compare categories"), iUsed, SearchExtCats.Count()); Add(new cOsdItem(IndentMenuItem(IndentMenuItem(itemtext)))); } } Add(new cMenuEditIntItem(IndentMenuItem(trVDR("Priority")), &data.Priority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem(IndentMenuItem(trVDR("Lifetime")), &data.Lifetime, 0, MAXLIFETIME)); Add(new cMenuEditIntItem(IndentMenuItem(trVDR("Setup.Recording$Margin at start (min)")), &data.MarginStart, -INT_MAX, INT_MAX)); Add(new cMenuEditIntItem(IndentMenuItem(trVDR("Setup.Recording$Margin at stop (min)")), &data.MarginStop, -INT_MAX, INT_MAX)); Add(new cMenuEditBoolItem(IndentMenuItem(tr("VPS")), &data.useVPS, trVDR("no"), trVDR("yes"))); } if (data.action == searchTimerActionRecord) { Add(new cMenuEditStraItem(IndentMenuItem(tr("Auto delete")), &data.delMode, 3, DelModes)); if (data.delMode == 1) Add(new cMenuEditIntItem(IndentMenuItem(IndentMenuItem(tr("after ... recordings"))), &data.delAfterCountRecs, 0, 999)); else if (data.delMode == 2) Add(new cMenuEditIntItem(IndentMenuItem(IndentMenuItem(tr("after ... days after first rec."))), &data.delAfterDaysOfFirstRec, 0, 999)); } } SetCurrent(Get(current)); } cMenuEditSearchExt::~cMenuEditSearchExt() { if (searchExt && addIfConfirmed) delete searchExt; // apparently it wasn't confirmed if (menuitemsChGr) free(menuitemsChGr); if (channelGroupName) free(channelGroupName); if (catarrayAvoidRepeats) free(catarrayAvoidRepeats); if (catvaluesNumeric) free(catvaluesNumeric); if (contentStringsFlags) free(contentStringsFlags); int i; for(i=0; i<=5; i++) free(SearchModes[i]); for(i=0; i<=7; i++) free(DaysOfWeek[i]); for(i=0; i<=2; i++) free(UseChannelSel[i]); for(i=0; i<=2; i++) free(SearchTimerModes[i]); for(i=0; i<=3; i++) free(BlacklistModes[i]); for(i=0; i<=2; i++) free(DelModes[i]); for(i=0; i<=2; i++) free(SearchActiveModes[i]); for(i=0; i<=1; i++) free(CompareSubtitleModes[i]); for(i=0; i<=3; i++) free(CompareDateModes[i]); } eOSState cMenuEditSearchExt::Help() { const char* ItemText = Get(Current())->Text(); eOSState state = osContinue; if(Current() < (int) helpTexts.size()) { char* title = NULL; if (msprintf(&title, "%s - %s", tr("Button$Help"), ItemText)!=-1) { if (strchr(title, ':')) *strchr(title, ':') = 0; state = AddSubMenu(new cMenuText(title, helpTexts[Current()])); free(title); } } return state; } eOSState cMenuEditSearchExt::ProcessKey(eKeys Key) { bool bHadSubMenu = HasSubMenu(); int iTemp_mode = data.mode; int iTemp_useTime = data.useTime; int iTemp_useChannel = data.useChannel; int iTemp_useDuration = data.useDuration; int iTemp_useDayOfWeek = data.useDayOfWeek; int iTemp_useAsSearchTimer = data.useAsSearchTimer; int iTemp_useExtEPGInfo = data.useExtEPGInfo; int iTemp_useContentDescriptor = useContentDescriptors; int iTemp_avoidRepeats = data.avoidRepeats; int iTemp_allowedRepeats = data.allowedRepeats; int iTemp_delAfterDays = data.delAfterDays; int iTemp_action = data.action; int iTemp_delMode = data.delMode; int iTemp_compareSummary = data.compareSummary; eOSState state = cOsdMenu::ProcessKey(Key); if (iTemp_mode != data.mode || iTemp_useTime != data.useTime || iTemp_useChannel != data.useChannel || iTemp_useDuration != data.useDuration || iTemp_useDayOfWeek != data.useDayOfWeek || iTemp_useAsSearchTimer != data.useAsSearchTimer || iTemp_useExtEPGInfo != data.useExtEPGInfo || iTemp_useContentDescriptor != useContentDescriptors || iTemp_avoidRepeats != data.avoidRepeats || iTemp_allowedRepeats != data.allowedRepeats || iTemp_delAfterDays != data.delAfterDays || iTemp_action != data.action || iTemp_delMode != data.delMode || iTemp_compareSummary != data.compareSummary) { Set(); Display(); if ((iTemp_useAsSearchTimer != data.useAsSearchTimer || iTemp_action != data.action) && data.useAsSearchTimer) // if search timer menu is dropped then scroll down to display all contents { int cur = Current(); PageDown(); SetCurrent(Get(cur)); Display(); } } const char* ItemText = Get(Current())->Text(); if (!HasSubMenu()) { if (strlen(ItemText)>0 && strstr(ItemText, tr(" from channel")) == ItemText && ((Key >= k0 && Key <= k9) || Key == kLeft || Key == kRight)) { channelMax = channelMin; Set(); Display(); } } int iOnUserDefDayItem = 0; int iOnDirectoryItem = 0; int iOnUseChannelGroups = 0; int iOnChannelGroup = 0; int iOnAvoidRepeats = 0; int iOnCompareCats = 0; int iOnTerm = 0; int iOnUseBlacklistsSelection = 0; int iOnExtCatItemBrowsable = 0; int iOnUseAsSearchTimer = 0; int iCatIndex = -1; char* catname = NULL; if (!HasSubMenu() && strlen(ItemText)>0) { // check, if on an item of ext. EPG info int iOnExtCatItem = 0; cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { if (strstr(ItemText, IndentMenuItem(SearchExtCat->menuname)) == ItemText) { iOnExtCatItem = 1; if (SearchExtCat->nvalues > 0) iOnExtCatItemBrowsable = 1; iCatIndex = index; catname = SearchExtCat->menuname; break; } index++; SearchExtCat = SearchExtCats.Next(SearchExtCat); } if (strstr(ItemText, tr("Search term")) == ItemText) { if (!InEditMode(ItemText, tr("Search term"), data.search)) // show template for a new search { SetHelp(NULL, NULL, tr("Button$Help"), tr("Button$Templates")); iOnTerm = 1; } } else if (strstr(ItemText, IndentMenuItem(tr("Day of week"))) == ItemText) { if (data.DayOfWeek == 7) { SetHelp(trVDR("Button$Edit")); iOnUserDefDayItem = 1; } else SetHelp(NULL, NULL, tr("Button$Help")); } else if (strstr(ItemText, tr("Use as search timer")) == ItemText) { if (data.useAsSearchTimer == 2) { SetHelp(NULL, NULL, tr("Button$Help"), tr("Button$Setup")); iOnUseAsSearchTimer = 1; } else SetHelp(NULL, NULL, tr("Button$Help")); } else if (strstr(ItemText, IndentMenuItem(tr("Directory"))) == ItemText) { if (!InEditMode(ItemText, IndentMenuItem(tr("Directory")), data.directory)) SetHelp(NULL, NULL, tr("Button$Help"), tr("Button$Select")); iOnDirectoryItem = 1; } else if (strstr(ItemText, tr("Use channel")) == ItemText && data.useChannel == 2) { SetHelp(NULL, NULL, tr("Button$Help"), tr("Button$Setup")); iOnUseChannelGroups = 1; } else if (strstr(ItemText, IndentMenuItem(tr("Channel group"))) == ItemText) { SetHelp(NULL, NULL, tr("Button$Help"), tr("Button$Setup")); iOnChannelGroup = 1; } else if (strstr(ItemText, tr("Use blacklists")) == ItemText && data.blacklistMode == blacklistsSelection) { SetHelp(NULL, NULL, tr("Button$Help"), tr("Button$Setup")); iOnUseBlacklistsSelection = 1; } else if (strstr(ItemText, IndentMenuItem(tr("Avoid repeats"))) == ItemText) { SetHelp(NULL, NULL, tr("Button$Help"), tr("Button$Setup")); iOnAvoidRepeats = 1; } else if (strstr(ItemText, IndentMenuItem(IndentMenuItem(tr("Compare categories")))) == ItemText) { SetHelp(NULL, NULL, tr("Button$Help"), tr("Button$Setup")); iOnCompareCats = 1; } else if (iOnExtCatItem) { if (!InEditMode(ItemText, IndentMenuItem(catname), data.catvalues[iCatIndex]) || SearchExtCats.Get(iCatIndex)->searchmode >= 10) SetHelp(NULL, NULL, tr("Button$Help"), iOnExtCatItemBrowsable?tr("Button$Select"):NULL); } else if (strstr(ItemText, tr("Search term")) != ItemText) SetHelp(NULL, NULL, tr("Button$Help"), NULL); } if (state == osUnknown) { if (HasSubMenu()) return osContinue; switch (Key) { case kOk: if (data.useChannel==1) { cChannel *ch = Channels.GetByNumber(channelMin); if (ch) data.channelMin = ch; else { ERROR(tr("*** Invalid Channel ***")); break; } ch = Channels.GetByNumber(channelMax); if (ch) data.channelMax = ch; else { ERROR(tr("*** Invalid Channel ***")); break; } if (channelMin > channelMax) { ERROR(tr("Please check channel criteria!")); return osContinue; } } if (data.useChannel==2) data.channelGroup = strdup(menuitemsChGr[channelGroupNr]); if ((data.useTitle || data.useSubtitle || data.useDescription) && (int(strlen(data.search)) < 3) && !Interface->Confirm(tr("Edit$Search text too short - use anyway?"))) break; if (searchExt) { *searchExt = data; if (data.DayOfWeek == 7) searchExt->DayOfWeek = UserDefDayOfWeek; // transfer cat selection for 'avoid repeats' back to search cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; searchExt->catvaluesAvoidRepeat = 0; while (SearchExtCat) { if (catarrayAvoidRepeats[index]) searchExt->catvaluesAvoidRepeat += (1<searchmode >= 10) { if (searchExt->catvalues[index]) free(searchExt->catvalues[index]); msprintf(&searchExt->catvalues[index], "%d", catvaluesNumeric[index]); } SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } searchExt->SetContentFilter(useContentDescriptors?contentStringsFlags:NULL); if (data.blacklistMode == blacklistsSelection) { searchExt->blacklists.Clear(); cBlacklistObject* blacklistObj = blacklists.First(); while(blacklistObj) { searchExt->blacklists.Add(new cBlacklistObject(blacklistObj->blacklist)); blacklistObj = blacklists.Next(blacklistObj); } } else searchExt->blacklists.Clear(); if (addIfConfirmed) { cMutexLock SearchExtsLock(&SearchExts); searchExt->ID = SearchExts.GetNewID(); SearchExts.Add(searchExt); } if (searchExt->useAsSearchTimer && !EPGSearchConfig.useSearchTimers) // enable search timer thread if necessary { cSearchTimerThread::Init((cPluginEpgsearch*) cPluginManager::GetPlugin("epgsearch"), true); INFO(tr("Search timers activated in setup.")); } SearchExts.Save(); addIfConfirmed = false; } return osBack; case kRed: if (iOnUserDefDayItem) state = AddSubMenu(new cMenuEditDaysOfWeek(&UserDefDayOfWeek)); break; case kBlue: if (iOnDirectoryItem && !InEditMode(ItemText, IndentMenuItem(tr("Directory")), data.directory)) state = AddSubMenu(new cMenuDirSelect(data.directory)); if (iOnUseChannelGroups || iOnChannelGroup) { if (channelGroupName) free(channelGroupName); channelGroupName = strdup(menuitemsChGr[channelGroupNr]); state = AddSubMenu(new cMenuChannelGroups(&channelGroupName)); } if (iOnAvoidRepeats) state = AddSubMenu(new cMenuRecsDone(searchExt)); if (iOnCompareCats) state = AddSubMenu(new cMenuSearchEditCompCats(catarrayAvoidRepeats)); if (iOnTerm) state = AddSubMenu(new cMenuEPGSearchTemplate(&data, NULL, addIfConfirmed)); if (iOnUseBlacklistsSelection) state = AddSubMenu(new cMenuBlacklistsSelection(&blacklists)); if (iOnExtCatItemBrowsable) state = AddSubMenu(new cMenuCatValuesSelect(data.catvalues[iCatIndex], iCatIndex, SearchExtCats.Get(iCatIndex)->searchmode)); if (iOnUseAsSearchTimer) state = AddSubMenu(new cMenuSearchActivSettings(&data)); break; case kGreen: state = osContinue; break; case kYellow: case kInfo: state = Help(); break; default: break; } } if ((iOnUseChannelGroups || iOnChannelGroup || iOnCompareCats || iOnTerm || iOnExtCatItemBrowsable) && bHadSubMenu && !HasSubMenu()) // return form submenu { if (iOnTerm) { if (data.DayOfWeek < 0) { UserDefDayOfWeek = data.DayOfWeek; data.DayOfWeek = 7; } if (data.useChannel == 1) { channelMin = data.channelMin->Number(); channelMax = data.channelMax->Number(); } if (data.useChannel == 2) { channelGroupNr = ChannelGroups.GetIndex(data.channelGroup); channelGroupName = strdup(data.channelGroup); } if (SearchExtCats.Count() > 0) { cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { catarrayAvoidRepeats[index] = (data.catvaluesAvoidRepeat & (1< 0) { cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { if (SearchExtCat->searchmode >= 10) catvaluesNumeric[index] = atoi(data.catvalues[index]); SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } } Set(); Display(); } return state; } // --- cMenuEditDaysOfWeek -------------------------------------------------------- cMenuEditDaysOfWeek::cMenuEditDaysOfWeek(int* DaysOfWeek, int Offset, bool Negate) :cOsdMenu(tr("Edit user-defined days of week"),30) { #if VDRVERSNUM >= 10728 SetMenuCategory(mcPlugin); #endif int i=0; offset = Offset; negate = Negate; pDaysOfWeek = DaysOfWeek; if (negate) *pDaysOfWeek = -*pDaysOfWeek; for(i=0; i<7; i++) Days[(i+offset)%7]=((*pDaysOfWeek) & (int)pow(2,i))?1:0; for(i=0; i<7; i++) Add(new cMenuEditBoolItem( WeekDayName((i+1)%7), &Days[(i+1)%7], trVDR("no"), trVDR("yes"))); SetHelp(NULL); } eOSState cMenuEditDaysOfWeek::ProcessKey(eKeys Key) { if (Key == kBack && negate) *pDaysOfWeek = -*pDaysOfWeek; eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch (Key) { case kOk: *pDaysOfWeek = 0; for(int i=0; i<7; i++) *pDaysOfWeek += Days[i]?(int)pow(2,(i+7-offset)%7):0; if (negate) *pDaysOfWeek = -*pDaysOfWeek; state = osBack; break; default: break; } } return state; } // --- cMenuSearchEditCompCats -------------------------------------------------------- cMenuSearchEditCompCats::cMenuSearchEditCompCats(int* catarrayAvoidRepeats) :cOsdMenu(tr("Compare categories"),30) { #if VDRVERSNUM >= 10728 SetMenuCategory(mcPlugin); #endif search_catarrayAvoidRepeats = catarrayAvoidRepeats; edit_catarrayAvoidRepeats = (int*) malloc(SearchExtCats.Count() * sizeof(int)); cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { edit_catarrayAvoidRepeats[index] = catarrayAvoidRepeats[index]; cString menutext = cString::sprintf("%s %s", tr("Compare"), SearchExtCat->menuname); Add(new cMenuEditBoolItem(menutext, &edit_catarrayAvoidRepeats[index], trVDR("no"), trVDR("yes"))); SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } } cMenuSearchEditCompCats::~cMenuSearchEditCompCats() { free(edit_catarrayAvoidRepeats); } eOSState cMenuSearchEditCompCats::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch (Key) { case kOk: { cSearchExtCat *SearchExtCat = SearchExtCats.First(); int index = 0; while (SearchExtCat) { search_catarrayAvoidRepeats[index] = edit_catarrayAvoidRepeats[index]; SearchExtCat = SearchExtCats.Next(SearchExtCat); index++; } } state = osBack; break; default: break; } } return state; } // --- cMenuBlacklistsSelection -------------------------------------------------------- cMenuBlacklistsSelection::cMenuBlacklistsSelection(cList* pBlacklists) :cOsdMenu(tr("Select blacklists"),30) { #if VDRVERSNUM >= 10728 SetMenuCategory(mcPlugin); #endif blacklists = pBlacklists; blacklistsSel = new int[Blacklists.Count()]; cMutexLock BlacklistLock(&Blacklists); cBlacklist* blacklist = Blacklists.First(); int index = 0; while(blacklist) { blacklistsSel[index] = false; cBlacklistObject* blacklistObjSel = blacklists->First(); while(blacklistObjSel) { if (blacklistObjSel->blacklist->ID == blacklist->ID) { blacklistsSel[index] = true; break; } blacklistObjSel = blacklists->Next(blacklistObjSel); } blacklist = Blacklists.Next(blacklist); index++; } SetHelp(tr("Button$Invert selection"), tr("Button$All yes"), tr("Button$All no"), tr("Button$Setup")); Set(); } cMenuBlacklistsSelection::~cMenuBlacklistsSelection() { if (blacklistsSel) delete [] blacklistsSel; } // --- cMenuBlacklistsSelectionItem ---------------------------------------------------------- class cMenuBlacklistsSelectionItem : public cMenuEditBoolItem { const char* name; public: cMenuBlacklistsSelectionItem(const char *Name, int *Value, const char *FalseString = NULL, const char *TrueString = NULL): cMenuEditBoolItem(Name, Value, FalseString, TrueString) { name = Name; } int Compare(const cListObject &ListObject) const { cMenuBlacklistsSelectionItem *p = (cMenuBlacklistsSelectionItem*)&ListObject; return strcasecmp(name, p->name); } }; void cMenuBlacklistsSelection::Set() { int current = Current(); Clear(); cMutexLock BlacklistLock(&Blacklists); cBlacklist* blacklist = Blacklists.First(); int index = 0; while(blacklist) { Add(new cMenuBlacklistsSelectionItem(blacklist->search, &blacklistsSel[index], trVDR("no"), trVDR("yes"))); blacklist = Blacklists.Next(blacklist); index++; } SetCurrent(Get(current)); Sort(); } eOSState cMenuBlacklistsSelection::ProcessKey(eKeys Key) { bool bHadSubMenu = HasSubMenu(); eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch (Key) { case kOk: { cMutexLock BlacklistLock(&Blacklists); blacklists->Clear(); cBlacklist* blacklist = Blacklists.First(); int index = 0; while(blacklist) { if (blacklistsSel[index++]) blacklists->Add(new cBlacklistObject(blacklist)); blacklist = Blacklists.Next(blacklist); } } state = osBack; break; case kRed: case kGreen: case kYellow: { cMutexLock BlacklistLock(&Blacklists); cBlacklist* blacklist = Blacklists.First(); int index = 0; while(blacklist) { blacklistsSel[index] = (Key == kGreen?1:(Key == kRed?1-blacklistsSel[index]:0)); blacklist = Blacklists.Next(blacklist); index++; } Set(); Display(); return osContinue; } break; case kBlue: state = AddSubMenu(new cMenuBlacklists); break; default: break; } } if (bHadSubMenu && !HasSubMenu()) // return form submenu { Clear(); delete [] blacklistsSel; blacklistsSel = new int[Blacklists.Count()]; cMutexLock BlacklistLock(&Blacklists); cBlacklist* blacklist = Blacklists.First(); int index = 0; while(blacklist) { blacklistsSel[index] = false; cBlacklistObject* blacklistObjSel = blacklists->First(); while(blacklistObjSel) { if (blacklistObjSel->blacklist->ID == blacklist->ID) { blacklistsSel[index] = true; break; } blacklistObjSel = blacklists->Next(blacklistObjSel); } blacklist = Blacklists.Next(blacklist); index++; } Set(); Display(); } return state; } // --- cMenuCatValuesSelect -------------------------------------------------------- cMenuCatValuesSelect::cMenuCatValuesSelect(char* CatValues, int CatIndex, int SearchMode) :cOsdMenu(tr("Values for EPG category"), 1, 40) { #if VDRVERSNUM >= 10728 SetMenuCategory(mcPlugin); #endif catValues = CatValues; catIndex = CatIndex; searchMode = SearchMode; cSearchExtCat* SearchExtCat = SearchExtCats.Get(catIndex); if (SearchExtCat) { sel_cats.assign(SearchExtCat->nvalues, false); for(int i=0; invalues; i++) { char *pstrSearchToken, *pptr; char *pstrSearch=strdup(catValues); pstrSearchToken=strtok_r(pstrSearch, ",;|~", &pptr); while(pstrSearchToken) { if(SearchExtCat->values[i] && strcmp(SearchExtCat->values[i], skipspace(pstrSearchToken))==0) sel_cats[i] = true; pstrSearchToken=strtok_r(NULL, ",;|~", &pptr); } free(pstrSearch); } } Set(); SetHelp(trVDR("Button$On/Off"), NULL, NULL, tr("Button$Apply")); } void cMenuCatValuesSelect::Set() { int current = Current(); int selCount = 0; Clear(); string SearchMode = string(tr("Search mode")) + ": "; if (searchMode == 0) SearchMode += tr("phrase"); else if (searchMode == 1) SearchMode += tr("all words"); else if (searchMode == 2) SearchMode += tr("at least one word"); else if (searchMode == 3) SearchMode += tr("match exactly"); else if (searchMode == 4) SearchMode += tr("regular expression"); else if (searchMode == 10) SearchMode += tr("less"); else if (searchMode == 11) SearchMode += tr("less or equal"); else if (searchMode == 12) SearchMode += tr("greater"); else if (searchMode == 13) SearchMode += tr("greater or equal"); else if (searchMode == 14) SearchMode += tr("equal"); else if (searchMode == 15) SearchMode += tr("not equal"); cOsdItem* sItem = new cOsdItem(SearchMode.c_str()); Add(sItem); sItem->SetSelectable(false); cSearchExtCat* SearchExtCat = SearchExtCats.Get(catIndex); if (SearchExtCat) { for(int i=0; invalues; i++) { cString entry = cString::sprintf("%c\t%s", sel_cats[i]?'*':' ', SearchExtCat->values[i]); if (sel_cats[i]) selCount++; Add(new cOsdItem(entry)); } } SetCurrent(Get(current)); if (SearchExtCat) { cString title = cString::sprintf("%s (%d/%d)", tr("Values for EPG category"), selCount, SearchExtCat->nvalues); if (*title) SetTitle(title); } Display(); } eOSState cMenuCatValuesSelect::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch (Key) { case kOk: case kRed: if (Current()>0) { cSearchExtCat* SearchExtCat = SearchExtCats.Get(catIndex); if (SearchExtCat && SearchExtCat->searchmode >= 10 && catValues) // only one numeric value, so jump back { strcpy(catValues, SearchExtCat->values[Current()-1]); state = osBack; } else { sel_cats[Current()-1] = !sel_cats[Current()-1]; Set(); Display(); } } break; case kBlue: { *catValues = 0; cSearchExtCat* SearchExtCat = SearchExtCats.Get(catIndex); if (SearchExtCat) { for(int i=0; invalues; i++) { if (sel_cats[i]) { if (*catValues) strcat(catValues, ", "); strcat(catValues, SearchExtCat->values[i]); } } } state = osBack; break; } default: break; } } return state; } // --- cMenuSearchActivSettings -------------------------------------------------------- cMenuSearchActivSettings::cMenuSearchActivSettings(cSearchExt *SearchExt) :cOsdMenu(tr("Activation of search timer"), 25) { #if VDRVERSNUM >= 10728 SetMenuCategory(mcPlugin); #endif searchExt = SearchExt; if (searchExt) { Add(new cMenuEditDateItem(tr("First day"), &searchExt->useAsSearchTimerFrom, NULL)); Add(new cMenuEditDateItem(tr("Last day"), &searchExt->useAsSearchTimerTil, NULL)); } } eOSState cMenuSearchActivSettings::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch (Key) { case kOk: state = osBack; break; default: break; } } return state; } epgsearch-1.0.1.beta3/epgsearchext.h0000644000175000017500000001554412112105236016336 0ustar winniwinni/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #ifndef __EPGSEARCHEXT_H #define __EPGSEARCHEXT_H #include #include #include #include #include #include #include #include "log.h" #include "epgsearchtools.h" #define MAXOSDTEXTWIDTH 45 typedef enum { blacklistsOnlyGlobal = 0, blacklistsSelection, blacklistsAll, blacklistsNone } blacklistModes; typedef enum { searchTimerActionRecord=0, searchTimerActionAnnounceViaOSD, searchTimerActionSwitchOnly, searchTimerActionAnnounceAndSwitch, searchTimerActionAnnounceViaMail } searchTimerAction; class cSearchExt; class cBlacklist; class cSearchResult : public cListObject { public: const cEvent* event; const cSearchExt* search; const cBlacklist* blacklist; bool needsTimer; cSearchResult(const cEvent* Event, const cSearchExt* Search) : event(Event), search(Search), blacklist(NULL), needsTimer(true) {} cSearchResult(const cEvent* Event, int searchID); cSearchResult(const cEvent* Event, const cBlacklist* Blacklist) : event(Event), search(NULL), blacklist(Blacklist), needsTimer(true) {} }; class cSearchResults : public cList { public: void SortBy(int(*compar)(const void *, const void *)) { int n = Count(); cListObject *a[n]; cListObject *object = objects; int i = 0; while (object && i < n) { a[i++] = object; object = object->Next(); } qsort(a, n, sizeof(cListObject *), compar); objects = lastObject = NULL; for (i = 0; i < n; i++) { a[i]->Unlink(); count--; Add(a[i]); } } bool Lookup(const cEvent* Event) { cSearchResult* r = First(); while(r) { if (r->event == Event) return true; r = Next(r); } return false; } }; class cBlacklistObject; class cTimerObj; class cTimerObjList; class cSearchExt : public cListObject { friend class cMenuEditSearchExt; friend class cMenuEditTemplate; public: int ID; char search[MaxFileName]; int options; int useTime; int startTime; int stopTime; int useChannel; int useCase; int mode; int useTitle; int useSubtitle; int useDescription; int useDuration; int minDuration; int maxDuration; int useAsSearchTimer; int useDayOfWeek; int DayOfWeek; int useEpisode; char directory[MaxFileName]; int Priority; int Lifetime; int MarginStart; int MarginStop; int useVPS; int action; std::string contentsFilter; int useExtEPGInfo; char** catvalues; cChannel *channelMin; cChannel *channelMax; char* channelGroup; int avoidRepeats; int compareTitle; int compareSubtitle; int compareSummary; int compareSummaryMatchInPercent; int compareDate; int allowedRepeats; unsigned long catvaluesAvoidRepeat; int repeatsWithinDays; int delAfterDays; int recordingsKeep; int switchMinsBefore; int pauseOnNrRecordings; int blacklistMode; cList blacklists; int fuzzyTolerance; int useInFavorites; int menuTemplate; int delMode; int delAfterCountRecs; int delAfterDaysOfFirstRec; time_t useAsSearchTimerFrom; time_t useAsSearchTimerTil; int ignoreMissingEPGCats; int unmuteSoundOnSwitch; bool skipRunningEvents; static char *buffer; public: cSearchExt(void); virtual ~cSearchExt(void); cSearchExt& operator= (const cSearchExt &SearchExt); virtual bool operator< (const cListObject &ListObject); const char *Search(void) { return search; } int Options(void) { return options; } int StartTime(void) { return startTime; } int StopTime(void) { return stopTime; } int UseChannel(void) { return useChannel; } cChannel *ChannelMin(void) { return channelMin; } cChannel *ChannelMax(void) { return channelMax; } cEvent * GetEventBySearchExt(const cSchedule *schedules, const cEvent *Start, bool inspectTimerMargin = false); bool MatchesExtEPGInfo(const cEvent* e); const char *ToText(); bool Parse(const char *s); bool ParseExtEPGValues(const char *s); bool ParseExtEPGEntry(const char *s); bool ParseBlacklistIDs(const char *s); bool Save(FILE *f); char* BuildFile(const cEvent* pEvent) const; cSearchResults* Run(int PayTVMode = -1, bool inspectTimerMargin = false, int evalLimitMins = 0, cSearchResults* pPrevResults = NULL, bool suppressRepeatCheck = false); void CheckRepeatTimers(cSearchResults* pResults); void CheckExistingRecordings(cSearchResults* pResults); void CopyFromTemplate(const cSearchExt* templ, bool ignoreChannelSettings = false); cSearchResults* GetBlacklistEvents(int MarginStop = 0); void OnOffTimers(bool); void DeleteAllTimers(); cTimerObjList* GetTimerList(cTimerObjList* timerList); int GetCountRecordings(); bool IsActiveAt(time_t t); bool HasContent(int contentID); void SetContentFilter(int* contentStringsFlags); bool MatchesContentsFilter(const cEvent* e); }; class cSearchExts : public cList, public cMutex { private: char *fileName; bool allowComments; virtual void Clear(void) { cMutexLock SearchExtsLock(this); free(fileName); fileName = NULL; cList::Clear(); } public: cSearchExts(void) { fileName = NULL; allowComments = false; } virtual ~cSearchExts() { Clear(); free(fileName); } public: bool Load(const char *FileName = NULL); bool Save(void); void Update(void); int GetNewID(void); cSearchExt* GetSearchFromID(int ID); void RemoveBlacklistID(int ID); bool Exists(const cSearchExt* SearchExt); cSearchExts* Clone(); bool CheckForAutoDelete(cSearchExt* SearchExt); void SortBy(int(*compar)(const void *, const void *)); }; extern cSearchExts SearchExts; extern cSearchExts SearchTemplates; #endif epgsearch-1.0.1.beta3/doc-src/0000755000175000017500000000000012100027260015021 5ustar winniwinniepgsearch-1.0.1.beta3/doc-src/de/0000755000175000017500000000000012100027260015411 5ustar winniwinniepgsearch-1.0.1.beta3/doc-src/de/epgsearchtemplates.conf.5.txt0000644000175000017500000000337612100027260023132 0ustar winniwinni=head1 NAME F - Die gespeicherten Suchtimer-Vorlagen =head1 BESCHREIBUNG Fr die Suchtimer knnen Vorlagen angelegt werden. Diese werden hier gespeichert. =head1 FORMAT Diese Datei hat dasselbe Format wie die Datei F. Fr den Aufbau verweise ich auf C. =head1 SIEHE AUCH C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/epgsearchcats.conf.5.txt0000644000175000017500000001074612100027260022065 0ustar winniwinni=head1 NAME F - Die Kategorien des erweiterten EPGs, sofern vorhanden. =head1 BESCHREIBUNG Wenn man das EPG aus dem Internet bezieht, z.B. von Hrzu, enthlt das EPG erweiterte Daten. Zustzlich zum Titel, Untertitel un der Beschreibung findet man dann eine Liste der Darsteller, Jahr des Drehs, Episode der Serie, Kategorie und Genre des Film, etc. Damit epgsearch diese verwenden kann mssen die Felder des erweiterten EPGs Variablen zugeordnet werden. Einige Beispieldateien werden dem Plugin mitgeliefert und finden sich im Verzeichnis "conf". Um eine eigene F zu erstellen dient das mitgelieferte Tool F. Es scannt das vorhandene EPG und erstellt eine F. Diese sollte an die eigenen Wnscche angepasst werden, eine Formatbeschreibung findet sich im Kopf der Datei. =head1 FORMAT Auszug aus einer F: -------------------------------------------------------------------- This is just a template based on your current epg.data. Please edit! Perhaps a category or its value list should be removed. Also the 'name in menu' should be adjusted to your language. The order of items determines the order listed in epgsearch. It does not depend on the ID, which is used by epgsearch. Format: ID|category name(,format)|name in menu|values separated by ',' (option)|searchmode - 'ID' should be a unique positive integer (changing the id later on will force you to reedit your search timers!) - 'category name' is the name in your epg.data you can optionally add a format specifier for numeric values e.g. Episode,%02i - 'name in menu' is the name displayed in epgsearch. - 'values' is an optional list of possible values if you omit the list, the entry turns to an edit field in epgsearch, else it's an list of items to select from - 'searchmode' is an optional parameter specifying the mode of search: text comparison: 0 - the whole term must appear as substring 1 - all single terms (delimiters are ',', ';', '|' or '~') must exist as substrings. This is the default search mode. 2 - at least one term (delimiters are ',', ';', '|' or '~') must exist as substring. 3 - matches exactly 4 - regular expression numerical comparison: 10 - less 11 - less or equal 12 - greater 13 - greater or equal 14 - equal 15 - not equal -------------------------------------------------------------------- =head1 BEISPIELE (Die Zeilen sind gekrzt, daher unvollstndig) Beispiel fr EPG von Hrzu, bezogen von epgdata.com mit tvmovie2vdr. 1|Category|Kategorie|Information,Kinder,Musik,Serie,Show,Spielfilm,Sport|2 2|Genre|Genre|Abenteuer,Action,Wirtschaft,Wissen,Zeichentrick|2 3|Format|Video-Format|16:9,4:3|2 4|Audio|Audio|Dolby Surround,Dolby,Hoerfilm,Stereo|2 5|Year|Jahr||2 6|Cast|Besetzung||2 7|Director|Regisseur||2 8|Moderator|Moderation||2 9|Rating|Bewertung|Groartig besonders wertvoll,Annehmbar,Schwach|2 10|FSK|FSK|6,12,16,18|2 11|Country|Land||2 12|Episode|Episode||4 13|Themes|Thema||4 =head1 SIEHE AUCH C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/epgsearch.conf.5.txt0000644000175000017500000001233412100027260021205 0ustar winniwinni=head1 NAME F - Die gespeicherten Suchtimer =head1 BESCHREIBUNG Die in epgsearch angelegten Suchtimer werden in dieser Datei gespeichert. Sie sollte nicht manuell editiert werden. Verwende stattdessen lieber SVDRP. =head1 FORMAT Aufgrund von mglichen Formatnderungen enthlt die Datei eine Versionsangabe. Die Format-Version befindet sich in der ersten Zeile der Datei. Der allgemeine Feldtrenner ist C<':'>. Folgende Felder sind mglich: 1 - Einmalige Suchtimer ID 2 - Suchstring 3 - Verwende Zeit? 0/1 4 - Startzeit in HHMM 5 - Stopzeit in HHMM 6 - Verwende Kanal? 0 = nein, 1 = Intervall, 2 = Kanalgruppe, 3 = nur FTA 7 - Wenn 'verwende Kanal' = 1 dann ist Kanal ID[|Kanal ID] im VDR Format, Eintrge oder min/max Eintrge getrennt durch |, wenn 'Verwende Kanal' = 2 dann der Kanalgruppenname 8 - Beachte Gross-/Kleinschreibung? 0/1 9 - Suchmodus: 0 - Der gesamte Suchbegriff muss genau so enthalten sein 1 - Alle Suchbegriffe (Trenner sind Leerzeichen,',', ';', '|' oder '~') mssen enthalten sein. 2 - Mindestens ein Suchbegriff muss enthalten sein (Trenner sind Leerzeichen, ',', ';', '|' oder '~'). 3 - Der Suchbegriff muss genau zutreffen 4 - Regulrer Ausdruck 10 - Suche in Titel? 0/1 11 - Suche in Untertitel? 0/1 12 - Suche in Beschreibung? 0/1 13 - Verwende Lnge? 0/1 14 - Minimale Lnge der Sendung in HHMM 15 - Maximale Lnge der Sendung in HHMM 16 - Verwende als Suchtimer? 0/1 17 - Verwende Tag der Woche? 0/1 18 - Tag der Woche (0 = Sonntag, 1 = Montag...; -1 Sonntag, -2 Montag, -4 Dienstag, ...; -7 So, Mo, Di) 19 - Verwende als Serienaufnahme? 0/1 20 - Verzeichnis fr Aufnahme 21 - Prioritt der Aufnahme 22 - Lebensdauer der Aufnahme 23 - Zeitpuffer am Anfang in Minuten 24 - Zeitpuffer am Ende in Minuten 25 - Verwende VPS? 0/1 26 - Aktion: 0 = Lege Timer an 1 = Benachrichtige nur per OSD (kein Timer) 2 = Schalte nur um (kein Timer) 27 - Verwende erweitertes EPG? 0/1 28 - Felder des erweiterten EPGs. Dieser Eintrag hat folgendes Format (Trenner ist '|' fr jede Kategorie, '#' trennt ID vom Wert): 1 - Die ID der Kategorie des erweiterten EPGs, festgelegt in F, s. C 2 - Wert des erweiterten EPGs fr diese Kategorie (Ein ':' wird bersetzt in "!^colon^!", z.B. "16:9" -> "16!^colon^!9") 29 - vermeide Wiederholungen? 0/1 30 - erlaubte Anzahl Wiederholungen 31 - Vergleiche Titel bei Prfung auf Wiederholung? 0/1 32 - Vergleiche Untertitel bei Prfung auf Wiederholung? 0/1 33 - Vergleiche Beschreibung bei Prfung auf Wiederholung? 0/1 34 - Vergleiche erweitertes EPG bei Prfung auf Wiederholung? Dieser Eintrag ist ein Bitfeld von Kategorie IDs. 35 - Erlaube Wiederholungen nur innerhalb x Tagen 36 - Lsche eine Aufnahme automatisch nach x Tagen 37 - Aber behalte mindestens x Aufnahmen 38 - Schalte x Minuten vor der Sendung um, wenn Aktion = 2 39 - Pausiere das Anlegene von Timern wenn x Aufnahmen vorhanden sind 40 - Modus der Ausschlussliste: 0 = Aus, 1 = Whle aus, 2 = Alle 41 - Verwende diese Ausschluss-Suchtimer, IDs getrennt durch '|' 42 - Fuzzy Toleranz fr Suche 43 - Verwende diese Suche im Favoriten Men, 0 = Nein, 1 = Ja 44 - ID einer Menvorlage fr das Suchergebnis Folgende Zeichen werden bei der Speicherung bersetzt: : => | | => !^pipe^! Es mssen nicht alle Felder belegt sein. Gefordert sind lediglich die ersten 11. =head1 BEISPIELE #version 2 - DONT TOUCH THIS! 1:Kommissar Beck:0:::2:ffRecht:0:0:1:0:0:0:::1:0:0:1:%Category%~%Genre%:50:99:10:60:0:0:0::1:0:1:1:0:0:0:0:0 2:* Sgebrecht:0:::2:Hauptsender:0:0:0:0:0:0:::0:0:0:0:%Category%~%Genre%:50:99:10:10:0:0:1:1#|2#|3#|4#|5#|6#Marianne Sgebrecht|7#|8#|9#|10#|11#|12#|13#:1:0:1:0:0:0:0:0:0 =head1 SIEHE AUCH C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/epgsearchswitchtimers.conf.5.txt0000644000175000017500000000374112100027260023655 0ustar winniwinni=head1 NAME F - Die gespeicherten Umschalttimer =head1 BESCHREIBUNG In epgsearch kann man ber das Programmen und die Suchtimer Umschalttimer anlegen, die einem zu beginn der Sendung auf die Sendung hinweisen oder gleich umschalten. Die Umschalttimer werden in dieser Datei gespeichert. =head1 FORMAT Der allgemeine Feldtrenner ist C<':'>. Folgende Felder sind mglich: 1 - Kanal 2 - Event ID 3 - Startzeit 4 - Vorlaufzeit 5 - Nur ankndigen =head1 BEISPIELE S19.2E-1-1089-12060:52221:1153322700:1:0 =head1 SIEHE AUCH C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/epgsearchblacklists.conf.5.txt0000644000175000017500000000431512100027260023261 0ustar winniwinni=head1 NAME F - Die gespeicherten Auschlusslisten-Suchtimer =head1 BESCHREIBUNG In epgsearch knnen Ausschlusslisten (Blacklists) angelegt werden. Dies sind im Grunde normale Suchtimer die in der Datei F gespeichert werden. Zu jedem Suchtimer kann man dann einen oder mehrere Eintrge aus der Ausschlussliste auswhlen. =head2 Funktion Suchtimer "Krimi" verwendet Ausschlusssuchtimer "Tatort" Ausschlusssuchtimer "Tatort" sucht "Tatort" Es werden alle Krimis gesucht und anschliessend wird nachgesehen ob ein Ergebnisse auf den Ausschlusssuchtimer zutrifft. Dieses wird dann verworfen. =head1 FORMAT Diese Datei hat dasselbe Format wie die Datei F. Fr den Aufbau verweise ich auf C. =head1 SIEHE AUCH C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/timersdone.conf.5.txt0000644000175000017500000000426312100027260021417 0ustar winniwinni=head1 NAME F - Liste von anstehenden Timern, die von Suchtimern erzeugt wurden. =head1 BESCHREIBUNG Diese Datei enthlt eine Liste von anstendenden Timern, die von Suchtimern erzeugt wurden. Wenn die Setup-Option 'Timer nach Lschen neuprogrammieren' auf nein steht, benutzt epgsearch diese Liste, um zu prfen, ob ein Timer bereits angelegt wurde und erstellt den Timer in diesem Fall nicht nochmals. Sobald die zugehrige Aufnahme stattgefunden hat, wird der Timer automatisch aus dieser Liste entfernt. =head1 FORMAT Pro Zeile ein Timer, die Felder werden durch ':' getrennt. Folgende Felder existieren: 1 - Kanal-Kennung 2 - Startzeit 3 - Stopzeit 4 - Suchtimer-ID 5 - Titel der Sendung 6 - Untertitel der Sendung =head1 SIEHE AUCH C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT und LIZENZ Copyright (c) 2005-2006 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/noannounce.conf.5.txt0000644000175000017500000000263412100027260021411 0ustar winniwinni=head1 NAME F - Liste von Sendungen, die nicht mehr per OSD angekndigt werden sollen. =head1 BESCHREIBUNG Diese Datei enthlt eine Liste von Sendungen die markiert wurden, sodass diese nicht mehr durch den Suchtimer-Hintergrund-Thread per OSD angekndigt werden. Wenn whrend der Ankndigung einer Sendung eine der Tasten '0', ... '9' oder 'Ok' gedrckt wird, wird nachgefragt, ob zuknftige Ankndigungen vollstndig (bei den Tasten '0' oder 'Ok') oder nur fr die nchsten x Tage (bei den Tasten '1' bis '9') unterdrckt werden sollen. Besttigt man diese Abfrage durch ein erneutes 'Ok', wird die Einstellung entsprechend bernommen. =head1 FORMAT Pro Zeile eine Sendung, die Felder werden durch ':' getrennt. Folgende Felder existieren: 1 - Titel 2 - Episode 3 - Kanal-Kennung 4 - Startzeit 5 - Zeitpunkt fr nchste Ankndigung =head1 SIEHE AUCH C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT und LIZENZ Copyright 2005 - 2007 Christian Wieninger Dieses Dokument wird unter den Bedingungen der Gnu Public License (GPL) verffentlicht. Alle Angaben sind nach bestem Wissen, aber natrlich ohne Gewhr (no warranty in any kind). epgsearch-1.0.1.beta3/doc-src/de/epgsearchuservars.conf.5.txt0000644000175000017500000001314012100027260022774 0ustar winniwinni=head1 NAME F - Die Uservariablen =head1 BESCHREIBUNG In dieser Datei knnen Variablen definiert werden die dann in epgsearch in allen Feldern, in denen Variablen mglich sind, zur Verfgung stehen. =head1 FORMAT Die Variablen selbst sind in dem Format %Variablenname% aufgebaut. "Variablenname" kann aus alphanumerischen Zeichen bestehen, Leerzeichen und Sonderzeichen sind nicht erlaubt. Zwischen Gross-/und Kleinschreibung wird nicht unterscheiden. Beispiele fr mgliche Namen: %Serie% %DokuVar1% %ThemesSubtitleDate1% =head2 Zuweisung Die Zuweisung eines Wertes erfolgt so: %Serie%=Neue Serie~Krimi Hier wird der Variablen %Serie% die Zeichenkette "Neue Serie~Krimi" zugewiesen. Es wird immer eine Zeichenkette zugewiesen. Leerzeichen werden daher auch als Leerzeichen mit bernommen. %Pfad%=%Serie% Hier wird der Variablen %Pfad% der Inhalt der Variablen %Serie% zugewiesen. Das lsst sich beliebig verwenden. %Pfad%=%Serie%~Tatort Pfad enthlt hier den String "Neue Serie~Krimi~Tatort". =head2 Kontroll-Strukturen Einfache "if then else" Konstrukte sind mgliche. Innerhalb dieser Konstrukte knnen keine Strings, wohl aber Variablen zugwiesen werden. Leerzeichen werden ignoriert. %Foo%=Verschiedenes %Variable%=%Pfad% ? %Pfad% : %Foo% Ist Pfad nicht leer, weise %Variable% den Inhalt aus %Pfad% zu, sonst den Inhalt aus %Foo%. "%Pfad% ?" bedeutet also "nicht leer?". Es sind auch andere Prfungen mglich. %Variable%=%Pfad%!=5 ? %Pfad% : %Foo% "%Pfad%!=5 ?" bedeutet "ist %Pfad% ungleich 5?" Es knnen auch Variablen verglichen werden. %Fuenf%=5 %Variable%=%Pfad%!=%Fuenf% ? %Pfad% : %Foo% Folgende Prfungen sind mglich: == ist gleich != ist nicht gleich =head2 Systemaufruf Es knnen auch externe Programme/Scripte aufgerufen werden. Die zurck- gegebene Zeichenkette wird dann einer Variablen zugewiesen. %Ergebnis%=system(scriptname,%Variable1% %Variable2% -f %Variable3% --dir=%Variable4% --dummy) Ruft das Script "scriptname" mit den Parametern "%Variable1%", "%Variable2%", usw. auf. Das Ergebnis wird der Variablen %Ergebnis% zugewiesen. Es sind beliebig viele Variablen mglich. Wenn ntig, umfasst epgsearch die Variablen automatisch mit "". Das Script darf nur eine Zeichenkette ohne Zeilenumbruch zurckgeben. Erfolgt keine Rckgabe wird der Variablen %Ergebnis% eine leere Zeichenkette zugewiesen. =head2 Verfgbare Variablen Folgende Variablen sind bereits intern definiert und knnen verwendet werden. %title% - Title der Sendung %subtitle% - Subtitle der Sendung %time% - Startzeit im Format HH:MM %timeend% - Endzeit im Format HH:MM %date% - Startzeit im Format TT.MM.YY %datesh% - Startdatum im Format TT.MM. %time_w% - Name des Wochentages %time_d% - Tag der Sendung im Format TT %time_lng% - Startzeit in Sekunden seit 1970-01-01 00:00 %chnr% - Kanalnummer %chsh% - Kanalname kurz %chlng% - Kanalname lang %chdata% - VDR's interne Kanaldarstellung (z.B. 'S19.2E-1-1101-28106') %summary% - Beschreibung %htmlsummary% - Beschreibung, alle CR ersetzt durch '
' %eventid% - Event ID %colon% - Das Zeichen ':' %datenow% - Aktuelles Datum im Format TT.MM.YY %dateshnow% - Aktuelles Datum im Format TT.MM. %timenow% - Aktuelle Zeit im Format HH:MM %videodir% - VDRs Aufnahme-Verzeichnis (z.B. /video) %plugconfdir% - VDRs Verzeichnis fr Plugin-Konfigurationsdateien (z.B. /etc/vdr/plugins) %epgsearchdir% - epgsearchs Verzeichnis fr Konfiguratzionsdateien (z.B. /etc/vdr/plugins/epgsearch) Desweiteren knnen die in der Datei F definierten Variablen verwendet werden. Siehe dazu C. =head1 BEISPIELE # Wochentag, Datum, Uhrzeit %Datum%=%time_w% %date% %time% # Themes oder Subtitle oder Datum %ThemesSubtitleDate1%=%Subtitle% ? %Subtitle% : %Datum% %ThemesSubtitleDate%=%Themes% ? %Themes% : %ThemesSubtitleDate1% # Rufe das Script auf das den Aufnahmepfad erzeugt %DokuScript%=system(doku.pl,%Title%,%Subtitle%,%Episode%,%Themes%,%Category%,%Genre%) %Doku%=%DokuScript% =head1 SIEHE AUCH C, C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/epgsearch.1.txt0000644000175000017500000013004712100027260020257 0ustar winniwinni=head1 NAME F - Suchtimer und Ersatz fr VDR's Standard-Programm-Men =head1 BESCHREIBUNG EPG-Search kann als Ersatz fr VDR's Standard-Programm-Men verwendet werden. Es sieht genauso aus, erweitert es aber um einige zustzliche Funktionen. Ein weiterer Punkt sind die sog. Suchtimer die dafr sorgen, dass Timer automatisch programmiert werden. - Befehle fr EPG-Eintrge mit verschiedenen integrierten Befehlen wie z.B. 'Wiederholungen anzeigen', 'Suche anlegen'. Man kann eigene Befehle hinzufgen, um z.B. einen VDRAdmin Autotimer anzulegen. - Bis zu 4 weitere Zeitpunkte im Men 'Was luft jetzt?' neben 'Jetzt' und 'Nchste', sowie ein optionales Favoritenmen. - Suche im EPG: Anlegen von wiederverwendbaren Abfragen, die auch als 'Suchtimer' verwendet werden knnen. - Suchtimer: Sucht im Hintergrund nach Sendungen und erzeugt einen Timer bei passenden EPG-Eintrgen (hnlich zu VDRAdmins Autotimern) oder informiert ber die Sendung via OSD. - Vermeidung von doppelten Aufnahmen der gleichen Sendung * Timer-Vorschau * Erkennung abgebrochener Aufnahmen * Fuzzy-Vergleich von Sendungen - Fortschrittsbalken in 'Jetzt' und 'Nchste' - Zeit im Men 'Jetzt', 'Nchste' kann per Tastendruck verschoben werden, z.B. was luft 'Jetzt' + 30 Minuten - Startmen 'Programm' oder 'Jetzt' einstellbar. - das Men zur detaillierten EPG-Anzeige (Zusammenfassung) erlaubt den Sprung zur vorherigen/nchsten Sendung - Untersttzung erweiterter EPG-Infos in Suchtimern - Erweiterung des Timer-Edit-Mens um Verzeichnisse, benutzerdefinierte Wochentage und Untertitel-Auswahl - Timer Konfliktcheck, informiert ber OSD-Meldung - Timer Konfliktmen, zeigt die Konflikte an und erleichtert die Konfliktlsung - Email-Benachrichtigungen ber Suchtimer-Updates und Timer-Konflikte Teile der Quelltexte basieren auf dem repeating-epg-patch von Gerhard Steiner, der mir die Erlaubnis gab, diese zu verwenden. Danke fr seine Arbeit! =head1 OPTIONEN =over 4 =item -f file, --svdrpsendcmd=file Pfad zu svdrpsend fr externe SVDRP-Kommunikation (Standard ist interne Kommunikation, deshalb ist dieser Paramter normalerweise nicht notwendig) =item -c path, --config=path zur Angabe eines eigenen Konfigurationsverzeichnisses fr alle epgsearch-Dateien, Standard ist '/epgsearch' =item -l file, --logfile=file zur Angabe eines abweichenden Dateipfades fr epgsearch's Log-File (Standard ist epgsearch.log in epgsearch's Konfig-Verzeichnis) =item -v n, --verbose=n verbose level fr das Log-File. Wert 0 bedeutet kein Logging. Weiter Werte sind 1 (allgemeine Meldungen), 2 (detaillierte Meldungen), 3 (fr Debug-Zwecke) =item -r, --reloadmenuconf bewirkt ein Neuladen der epgsearchmenu.conf bei jedem Plugin-Aufruf am OSD. Kann fr das Testen eines selbst angepaten Men-Layouts praktisch sein. =item -m file, --mailcmd=file das externe Kommando fr den Emailversand. Als Standard wird 'sendEmail.pl' benutzt. Wenn ein abweichendes Kommando oder Skript verwendet wird, muss sichergestellt sein, dass das gleiche Paramter-Interface verwendet wird, wie bei sendEmail.pl. =back =head1 Inhalt 1. Beschreibung 1.1 Men Befehle 1.2 Men Suche 1.2.1 Men Suche editieren 1.2.2 Men Suchergebnisse 1.3 Erweitertes 'Jetzt' und 'Nchste' 1.4 Men Setup 23. Suchtimer 2.1 'Wiederholungen vermeiden' - Im Detail 2.2 Wie funktioniert der Vergleichstest zwischen 2 Sendungen? 2.3 Wie und wo wird der Vergleichstest eingesetzt? 3. Verwendung der Suche durch andere Plugins oder Skripte 4. Verwendung erweiterter EPG Infos 5. Ersetzen des Standardmen 6. Addons =head1 1. Beschreibung Auf den ersten Blick sieht EPG-Search wie der Programm-Men-Punkt des VDR aus. Ein Tastendruck auf '0' schaltet die Farbtasten um, so dass weitere Funktionen erreicht werden knnen (die vorgegebene Zuweisung kann per Setup angepasst werden): =head2 1.1 Men Befehle Dieses Men zeigt Befehle an, die auf den ausgewhlten Meneintrag angewandt werden knnen. Es gibt 8 vorgegebene Befehle: - Wiederholung: Zeigt Wiederholungen an - Aufnehmen - Umschalten - Suche anlegen: schaltet zum Suchmen und erzeugt eine Suche mit dem Namen der aktuellen Sendung als Suchbegriff (um die manuelle Erfassung zu vermeiden - Suche in Aufnahmen: durchsucht die Aufnahmen nach einer Sendung mit diesem Namen - Als 'bereits aufgezeichnet' markieren: Hiermit wird die ausgewhlte Sendung in die Datei epgsearchdone.data bernommen und epgsearch angewiesen, diese Sendung nicht aufzunehmen, falls der zugehrige Suchtimer mit "Wiederholung vermeiden" geschaltet ist. Ein bereits erzeugter Timer wird beim nchsten Suchtimer-Update automatisch gelscht. - In/Aus Umschaltliste?: Zum Bearbeiten der Umschaltliste. Wenn eine Sendung in der Umschaltliste enthalten ist, wird kurz vor Beginn eine Ankndigung eingeblendet und dann umgeschaltet. Um die gesamte Umschaltliste einzusehen, bitte 'Suche/Aktionen/Zeige Umschaltliste' aufrufen. - Erzeuge Ausschlussliste: Eine Ausschlussliste wird verwendet um bestimmte Sendungen bei der Verwendung von Suchtimern zu ignorieren. Ein Suchtimer kann beliebige Ausschlusslisten verwenden. Man kann eigene Befehle hinzufgen, indem man die Datei epgsearchcmds.conf im epgsearch-Konfig-Verzeichnis editiert. Eine Beispiel-Datei mit Bespielscripts liegt dem Plugin bei (s. Unterverzeichnis 'scripts', stammt von vdr-wiki.de. Danke an die Autoren). Das Format der Datei ist identisch zu VDRs commands.conf oder reccmds.conf. Wenn ein Befehl ausgefhrt wird, werden folgende Parameter bergeben: $1: Titel des Programmeintrags $2: Startzeit als time_t-Wert (wie im Shutdown-Skript) $3: Endzeit $4: Programmplatz $5: langer Kanalname $6: Untertitel des Programmeintrags, "" falls nicht vorhanden Zum Ausfhren eines Befehls aus dem Hauptmen ohne ffnen des Befehlsmens gengt es, die zugehrige Nummer des Befehls zu drcken. =head2 1.2 Men Suche Hier kann man eine Suche im EPG erzeugen, editieren, lschen und ausfhren. Bedienung und Verhalten ist hnlich zu VDR's Timer-Men. =head3 1.2.1 Men Suche editieren Das meiste in diesem Men ist selbsterklrend, deshalb nur einige Anmerkungen zu: =over 4 =item - B Suchbegriff. Will man nach mehreren Worten suchen, dann bitte mit Leerzeichen trennen. Lsst man den Suchbegriff leer (in Verbindung mit Suchmodus 'Ausdruck') wird alles akzeptiert. Das kann praktisch sein, um z.B. alles zu suchen, was zu einer bestimmten Zeit auf einem bestimmten Sender kommt. Mit 'Blau' kann man auch eine Vorlage fr eine Suche bernehmen. Falls eine Vorlage als Standard definiert wurde, wird bei einer neuen Suche automatisch der Inhalt der Standard-Vorlage verwendet. Hinweis: Die unscharfe Suche ist auf 32 Zeichen begrenzt! =item - B 'Ausdruck' sucht nach diesem Ausdruck innerhalb eines EPG-Eintrags. 'alle Worte' erfordert, dass jedes Wort im EPG-Eintrag vorkommt, 'ein Wort' dagegen nur, dass zumindest ein Wort auftaucht. 'exakt' vergleicht den gesamten Suchbegriff mit dem EPG-Eintrag (praktisch bei kurzen Titeln wie z.B. "Alf"). 'regulrer Ausdruck' erlaubt die Angabe eines regulren Ausdrucks zur Suche. Ein fhrender und abschlieender '/' ist nicht notwendig. Als Standard werden POSIX extended regular expressions verwendet. Wer lieber mit Perl kompatiblen regulren Ausdrcken arbeitet, muss lediglich im Makefile des Plugins #HAVE_PCREPOSIX=1 in HAVE_PCREPOSIX=1 ndern und neu kompilieren. (Dafr ist pcreposix notwendig, das mit libpcre von www.pcre.org installiert wird, aber auf den meisten Distributionen bereits vorhanden sein sollte). Eine Beschreibung des Suchprozesses gibt es im MANUAL. =item - B Einige Provider liefern Kennungen fr den Inhalt einer Sendung, z.B. "Film/Drama", "Dokumentation",...(erst ab vdr-1.7.11 verfgbar) Hiermit knnen diesen Kennungen ausgewhlt werden. Es ist auch eine Mehrfachauswahl mglich, die dann in allen Kennungen bereinstimmen muss (UND-Verknpfung). =item - B (nur verfgbar, wenn konfiguriert. Siehe weiter unten 'Verwendung erweiterter EPG Infos') =item - B Wenn 'Ja' gewhlt ist, verhindert das, dass eine Sendung aus dem Suchergebnis ausgeschlossen wird, falls die entsprechende Kategorie nicht im EPG vorhanden ist. Vorsicht: Ohne weitere Suchkriterien kann das zu einer Flut von Timern fhren. =item - B sucht nur im angegebenen Kanalbereich, der hinterlegten Kanalgruppe, z.B. 'ffentl. Rechtl.' oder 'Sportsender'... oder in FTA-Sendern. ACHTUNG: Nach einer nderung der Kanal-Reihenfolge sollten unbedingt diese Einstellungen der Suchtimer kontrolliert werden! =item - B Neben den Wochentagen kann auch eine benutzerdefinierte Auswahl getroffen werden, um z.B. nur Montags und Freitags zu suchen. Die benutzerdefinierte Auswahl findet sich am Ende der Liste Son, Mon, ..., Sam, benutzerdefiniert =item - B Ausschlusslisten knnen benutzt werden, um unerwnschte Sendungen auszuschlieen. Hier knnen nur globale, eine oder mehrere oder alle Ausschlusslisten selektiert werden. Falls ein Suchergebnis auch in einer der gewhlten Ausschlusslisten erscheint, wird es verworfen. =item - B Nur verfgbar, wenn im Setup aktiviert. Mit dieser Option kann eine Suche zur Verwendung im Favoritenmen markiert werden. Dieses Men listet alle Suchergebnisse von Suchen mit dieser Option. =item - B Nur verfgbar, wenn mehr als eine Menvorlage fr Suchergebnisse in epgsearchmenu.conf angegeben wurde. Mit dieser Option kann ein anderes Layout fr die Suchergebnisse dieser Suche gewhlt werden. =item - B falls ja, sucht das Plugin im Hintergrund nach passenden Sendungen und erzeugt dafr einen Timer (im Setup muss dazu die Verwendung von Suchtimern aktiv sein). Bei der Einstellung lt sich ber die Taste 'Blau' ein Zeitfenster einstellen, in dem der Suchtimer aktiv sein soll. =item - B Standard ist 'Aufnehmen', also das Erzeugen eines Timers fr das Suchergebnis. Man kann aber auch whlen, dass nur eine Ankndigung der Sendung per OSD vorgenommen werden soll, sobald diese gefunden wird. Eine weitere Mglichkeit ist 'nur umschalten'. Dadurch wird automatisch eine Minute vor Beginn der Sendung auf deren Kanal gewechselt. Ebenso kann mit 'Ankndigen und Umschalten' die Sendung vor ihrem Beginn angekndigt werden und mit 'Ok' zum entsprechenden Kanal gewechselt werden. =item - B falls ja, wird die Aufnahme in einem Ordner mit dem Seriennamen gespeichert. Die Aufnahme selbst erhlt den Episondennamen. Falls es keinen gibt, wird Datum und Uhrzeit als Episondenname verwendet. =item - B hier kann man ein Verzeichnis angeben, in dem die Aufnahme gespeichert wird, z.B. 'SciFi'. Mit der Taste 'Blau' kann ein Verzeichnis gewhlt werden, das bereits bei anderen Sucheintrgen verwendet wird. Die Liste kann auerdem durch Eintrge in der Datei epgsearchdirs.conf erweitert werden (pro Zeile ein Verzeichnis, ohne das fhrende video-Verzeichnis, s. auch MANUAL). Wenn man erweiterte EPG-Infos von einem Provider erhlt, knnen im Verzeichnis-Eintrag auch Variablen wie "%Genre%" oder "%Category%" verwendet werden. Diese werden durch die aktuellen erw. EPG-Infos ersetzt, sobald ein Timer erzeugt wird. Siehe MANUAL 'Using variables in the directory entry of a search timer') =item - B Manchen Aufnahmen sollen nur ein paar Tage existieren, z.B. Tagesschau. Mit diesem Feature kann man epgsearch sagen, dass es die Aufnahme automatisch nach ... Tagen lschen soll =item - B Wenn die angegebene Anzahl von Aufnahmen existiert, dann pausiert epgsearch mit dem Erzeugen neuer Timer. Erst nach dem Lschen einer oder mehrerer Aufnahmen, wird wieder nach neuen Sendungen gesucht. =item - B Wenn man keine Wiederholungen aufnehmen will, versucht dieses Feature festzustellen, ob eine Sendung bereits aufgenommen/programmiert wurde und berspringt diese dann. Bitte vor Verwendung den Abschnitt 'Wiederholungen vermeiden - Im Detail' weiter unten lesen. =item - B Will man eine gewisse Anzahl von Wiederholungen einer Sendung erlauben, kann dies hier hinterlegt werden. =item - B Falls Wiederholungen nur innerhalb einer anzugebenden Anzahl Tage erlaubt werden sollen, kann dies hier eingestellt werden. 0 entspricht unbegrenzt. =item - B Einstellung, ob beim Test, ob eine Sendung identisch ist, auch der Titel verglichen werden soll. =item - B Einstellung, ob beim Test, ob eine Sendung identisch ist, auch der Untertitel verglichen werden soll. Bei 'falls vorhanden' stuft epgsearch zwei Sendungen nur dann als identisch ein, wenn die Episodennamen gleich sind und nicht leer. =item - B Einstellung, ob beim Test, ob eine Sendung identisch ist, auch die Inhaltsbeschreibung verglichen werden soll. Dabei wird zunchst alles aus dem Inhalt entfernt, das einer Kategorienangabe gleicht. Der verbleibende Text wird dann verglichen. Ist dieser zum Prozentsatz der folgenden Option hnlich (im Sinne des Levinshtein-Distance-Algorithmus) wird er als gleich behandelt. =item - C Die notwendige bereinstimmung zweier Beschreibung in %. =item - B Manchmal wird eine Sendung hufig innerhalb einer gewissen Zeitspanne (Tag, Woche, Monat,...) wiederholt, die einzelnen Sendungen lassen sich aber anhand des EPG Inhalts nicht unterscheiden. Somit ist der Zeitpunkt also die einzige Information. Um damit zu vergelichen, kann man hier die entsprechende Zeitspanne auswhlen, um die Wiederholungen zu ignorieren. =item - B ber die Schaltflche 'Einstellungen' kann angegeben werden welche Kategorien ebenfalls miteinander verglichen werden sollen. =item - B Jeder Suchtimer kann fr diese Parameter eigene Einstellungen haben. Die Voreinstellung wird im Setup vorgenommen. =item - B aktiviert VPS, falls im VDR-Setup aktiv und fr die gefundene Sendung auch VPS-Informationen vorhanden sind. =item - B zum automatischen Lschen eines Suchttimers bei folgenden Bedingungen: * nach x Aufnahmen, oder * nach x Tagen nach erster Aufnahme Gezhlt werden dabei nur erfolgreiche Aufnahmen. Das Lschen erfolgt direkt nach dem Ende der entsprechenden Aufnahme. =back Um den Status 'Als Suchtimer verw.' zu ndern, ohne das Men zu ffnen, kann die Taste '2' verwendet werden. Dies ruft direkt den 2. Befehl im Befehlsmen auf. =head3 1.2.2 Men Suchergebnisse Dieses Men zeigt die Suchergebnisse an. Ein 'T' sagt aus, dass es zu diesem Eintrag bereits einen Timer gibt, ein 't', dass es nur teilweise aufgenommen wird, also wie im Standard-Programm-Men. =head2 1.3 Erweitertes 'Jetzt' and 'Nchste' Im Setup knnen bis zu 4 zustzliche Zeiten, als Erweiterung zu 'Jetzt' und 'Nchste', angegeben werden um die Taste Grn zu erweitern. Z.B. 'nachmittags', 'abends', 'sptabends'. Zeiten, die bereits verstrichen sind, werden bersprungen, man erhlt abends also kein 'nachmittags'. Ausnahme: Ist ein Zeitpunkt nicht mehr als 20 Stunden in der Zukunft wird das Men des nchsten Tages angezeigt. In diesen Men kann die aktuell angezeigte Zeit durch Drcken auf FastRew und FastFwd verschoben werden um die Zeit nach hinter oder vorne zu verstellen. Falls diese Tasten auf der Fernbedienung nicht existieren, kann diese Funktion durch Umschalten mit '0' erreicht werden. Die Tasten Grn und Gelb wechseln dann zu '<<' und '>>'. Das Umschalten kann ber das Setup angepasst werden. Man kann einen Fortschrittsbalken im Men 'Jetzt'/'Nchste' anzeigen lassen. =head2 1.4 Men Setup =head3 1.4.1 Allgemein =over 4 =item - B Damit wird der Eintrag 'Suche' im Hauptmen ausgeblendet. Achtung: wenn das Plugin der Taste Grn zugeordnet ist, dann bewirkt das Ausblenden, dass wieder das VDR-Standardmen gerufen wird (um das zu vermeiden s. unten). =item - B Falls nicht ausgeblendet, kann hier der Name des Hauptmen-Eintrags hinterlegt werden. Vorgabe ist 'Programmfhrer'. Hinweis: Wenn man den Eintrag abweichend von der Vorgabe setzt, ist der Eintrag nicht mehr abhngig von der gewhlten OSD-Sprache. Setzt man den Eintrag wieder auf den Default oder auf leer ist die Abhngigkeit wieder gegeben. =item - B Auswahl von 'Programm' oder 'Jetzt' als Startmen. =back =head3 1.4.2 EPG Mens =over 4 =item - B Hier kann das Verhalten der 'Ok'-Taste bestimmt werden. Man kann damit die Inhaltsangabe anzeigen oder zum entsprechenden Sender wechseln. Hinweis: Die Funktion der Taste 'Blau' (Umschalten/Info/Suche) hngt von dieser Einstellung ab. =item - B Auswahl, ob man den Standard ('Aufnehmen') oder 'Befehle' als Vorbelegung mchte. =item - B Auswahl, ob man den Standard ('Umschalten') oder 'Suche' als Vorbelegung mchte. =item - B Im Men 'Jetzt' kann ein Fortschrittsbalken angezeigt werden, der den Fortschritt der laufenden Sendung anzeigt. =item - B auswhlen, um eine fhrende Programmnummer vor jedem EPG-Eintrag anzuzeigen. =item - B zur Anzeige einer Trennzeile zwischen Kanalgruppen im Men 'bersicht - Jetzt' ... =item - B zur Anzeige einer Trennzeile zwischen Sendungen unterschiedlicher Tage im Men 'Programm'. =item - B Zeigt auch Radiokanle an. =item - B Bei einer sehr groen Kanalliste lt sich der Men-Aufbau mit dieser Einstellung durch eine Einschrnkung der angezeigten Kanle beschleunigen. Mit '0' wird das Limit aufgehoben. Wenn der aktuelle Kanal ber dem Limit liegt, wird das Limit ignoriert und wieder alle Kanle angezeigt. =item - B Falls 'Ja' wird ein Timer sofort erzeugt, sobald man 'Aufnehmen' drckt, sonst wird das Timer-Edit-Men angezeigt. =item - B zur Anzeige von Programmen ohne EPG, um auf diese umschalten zu knnen oder einen Timer zu programmieren =item - B Falls 'Ja' wird nach Drcken von 'Aufnahme' sofort ein Timer angelegt, falls 'Nein' erscheint das Timer-Edit-Men. =item - B In den Mens 'Programm', 'Jetzt', 'Nchste', 'Benutzerdef. Zeit 1', ... kann die angezeigte Zeit durch drcken von FastRew, FastFwd verschoben werden. Die Anzahl Minuten fr den Sprung kann hier angepasst werden. =item - B Falls die Tasten FastRew, FastFwd auf der Fernbedienung nicht vorhanden sind, dann auf 'ja' setzen. Wenn die Taste '0' gedrckt wird, werden somit auch die Tasten Grn/Gelb auf z.B. '<<' und '>>' umgeschaltet. =item - B Das Favoritenmen kann dazu verwendet werden, eine Liste von bevorzugten Sendungen anzuzeigen, die innerhalb der nchsten 24 Stunden laufen. Je nach Einstellung erscheint dieses Men vor oder nach den EPG-Mens mit benutzerdef. Zeiten. Die Auswahl von Sendungen wird durch setzen der Option 'In Favoriten-Men verw.' innerhalb einer Suche geregelt. =item - B Mit diesem Wert wird die Zeitspanne eingestellt, fr die Favoriten angezeigt werden sollen. =back =head3 1.4.3 Benutzerdef. EPG-Zeiten =over 4 =item - B Bis zu 4 benutzerdefinierte Zeiten knnen zu 'Jetzt' und 'Nchste' hinzugefgt werden. =item - B Name der benutzerdef. Zeit, z.B. 'Nachmittags', 'Abends', 'Sptabends'. =item - B zugehrige Uhrzeit. =back =head3 1.4.4 Timer-Programmierung =over 4 =item - B Beim normalen Programmieren eines Timers verwendet epgsearch ein erweitertes Timer-Edit-Men, das einen Verzeichniseintrag, benutzerdefinierte Wochentage und die Vervollstndigung um Untertitel anbietet. Falls man einen gepatchten VDR verwendet der ebenfalls ein erweitertes Timer-Edit-Men anbietet und lieber dieses verwenden will, dann einfach diese Option auf 'Ja' setzen. =item - B Dieser Eintrag wird beim normalen Programmieren eines Timers verwendet. Man kann auch EPG-Variablen verwenden (z.B.. 'Meine Filme~%Category%~%Genre%'). Wird das Timer-Edit-Men aufgerufen versucht epgsearch alle Variablen durch die Werte in der Beschreibung der Sendung zu ersetzen. Konnten nicht alle ersetzt werden, bleibt der Verzeichniseintrag leer. =item - B Beim manuellen Programmieren eines Timers kann epgsearch den Untertitel automatisch im Dateinamen ergnzen, wodurch die sptere Aufnahme in einem Unterverzeichnis fr diese Episode gespeichert wird. Hier whlt man wie die Ergnzung gemacht werden soll. 'Intelligent' versucht zu prfen, ob es Sinn macht und prft dazu die Lnge einer Sendung. Ist diese lnger als 80min wird keine Untertitel ergnzt. =item - B Manuell angelegte Timer knnen auf nderungen im EPG berprft werden. Hier kann die Standardeinstellung fr die Prfmethode je Kanal hinterlegt werden. Folgende Prfmethoden existieren: * ohne berwachung * anhand Sendungskennung: geprft wird anhand einer Kennung, die durch den Sender vergeben wird. (Achtung: nicht jeder Sender liefert vernnftige Kennungen!) * anhand Sender/Uhrzeit: geprft wird anhand der Sendung, die am besten zur Dauer der ursprnglichen Sendung passt. Nicht alle Sender liefern eine vernnftige Sendungskennung. Deshalb kann hier die Standardeinstellung fr jeden Kanal einzeln gesetzt werden. Bei der Programmierung eines manuellen Timers wird diese im Timer-Edit-Men vorgegeben, falls das epgsearch-eigene Men benutzt wird. =back =head3 1.4.5 Suche und Suchtimer =over 4 =item - B falls ja, untersucht das Plugin im Hintergrund die EPG-Daten und erzeugt Timer, falls passende Eintrge gefunden werden. Dies betrifft nur Sucheintrge, die mit 'Als Suchtimer verwenden' markiert sind. =item - B Das Intervall in Minuten, in dem die Hintergrundsuche vorgenommen wird. =item - B Falls nicht der Standard-SVDRP-Port 6419 (2001 vor vdr-1.7.15) verwendet wird, dann bitte hier anpassen, damit die Suchtimer funktionieren. =item - B Voreinstellungen =item - B zum Unterdrcken von Sendungs-Ankndigungen whrend einer aktiven Wiedergabe. =item - B epgsearch merkt sich standardmig welche Timer bereits durch Suchtimer angelegt wurden und programmiert diese nicht erneut, wenn sie gelscht wurden. Zum Abschalten dieses Verhaltens bitte 'Ja' whlen. =item - B Falls EPG von externen Anbietern bezogen wird, kann es vorkommenm, dass hier auch mal etwas schiefluft und somit wegen fehlendem EPG Aufzeichnungen verlorengehen. Hiermit kann geprft werden, ob fr die nchsten ... Stunden EPG bei den gewnschten Sendern vorhanden ist. Mit '0' wird die Prfung deaktiviert. =item - C falls ja, erscheint die Warnung als OSD-Einblendung =item - C falls ja, wird die Warnung per Mail versandt. Bitte das Email-Konto unter Email-Benachrichtigung konfigurieren. =item - C hier die Kanalgruppe auswhlen, fr die die Prfung durchgefhrt werden soll. Gegebenefalls zuvor unter Kanalgruppen anlegen. =item - B Auf 'Ja' setzen, wenn man bei der Suche nach Wiederholungen keine Sendungen von PayTV-Sendern haben will. =item - B Hier knnen Suchvorlagen verwaltet werden, die beim Anlegen neuer Suchen verwendet werden knnen. =item - B Hier knnen Ausschlusslisten verwalten werden. Diese knnen innerhalb einer Suche verwendet werden um unerwnschte Sendungen zu vermeiden. Eine Ausschlussliste kann auch als global gekennzeichnet werden. Da die Standardeinstellung beim Suchtimer fr die Option 'Ausschlusslisten verw.' auf 'nur globale' steht, kann man somit einfach unerwnschte Sendungen von allen Suchtimern ausschlieen. Ausnahme: Falls beim Suchtimer die Option 'Ausschlusslisten verw.: keine' gewhlt ist, hat eine globale Ausschlussliste keine Auswirkung. Ebenso werden globale Ausschlusslisten bei der Suche nach Wiederholungen ber das OSD ignoriert. =item - B verwaltet die Kanalgruppen, die als Suchkriterium in einer Suche verwendet werden knnen. Die Verwaltung ist auch im Edit-Men einer Suche mglich. =back B: wenn der EPG aus einer externen Quelle bezogen wird, sollte dafr gesorgt werden, dass die Suchtimer-Updates whrend des EPG-Updates abgeschaltet sind. Der Grund dafr ist, dass epgsearch Timer lscht, denen keine Sendungen zugeordnet sind. Whrend der neue EPG an VDR bermittelt wird, kann diese Situation auftreten. Am einfachsten geht das mit dem SVDRP-Befehl SETS im EPG-Update-Skript: svdrpsend plug epgsearch SETS off svdrpsend plug epgsearch SETS on =head3 1.4.6 Timer-Konflikt-Prfung =over 4 =item - B Falls ein Timer fehlschlagen wird, dessen Prioritt unter dem angegebene Wert liegt, wird darauf nicht per OSD-Nachricht hingewiesen und der Konflikt wird als 'nicht relevant' in der Konflikt-bersicht angezeigt. =item - B Falls ein Konflikt nicht lnger als die angegebene Anzahl Minuten dauert, wird darauf nicht per OSD-Nachricht hingewiesen und der Konflikt wird als 'nicht relevant' in der Konflikt-bersicht angezeigt. =item - B Hier kann der Zeitraum der Prfung angegeben werden. =item - B Das bewirkt eine Konfliktprfung nach jeder manuellen Timer-Programmierung und erzeugt eine OSD-Nachricht, falls der neue/genderte Timer in einen Konflikt verwickelt ist. =item - B Hier auf 'Ja' setzen, wenn die Konfliktprfung beim Beginn jeder Aufnahme erfolgen soll. Im Falle eines Konflikts wird dann sofort eine Nachricht angezeigt. Diese erscheint nur, wenn der Konflikt innerhalb der nchsten 2 Stunden auftritt. =item - B Hier kann eingestellt werden, ob eine Konfliktprfung nach jedem Suchtimer-Update erfolgen soll. Falls nicht: =item - B gibt an nach wievielen Minuten im Hintergrund eine automatische Konfliktprfung erfolgen soll. Bei relevanten Konflikten erfolgt eine Nachricht per OSD. Mit '0' wird diese Funktion deaktiviert. =item - B Wenn nchster Konflikt in ... Minuten eintritt, verwende folgendes Prfintervall. =over 4 =item - B um einen Konflikt in Krze nicht zu bersehen, kann hier ein krzeres Prfintervall eingestellt werden. =back =item - B Bitte auf 'Ja' setzen, wenn whrend einer Wiedergabe keine OSD-Benachrichtigungen ber Timer-Konflikte gewnscht sind. Die Benachrichtigung erfolgt trotzdem, wenn der nchste Konflikt innerhalb der nchsten 2 Stunden auftritt. =back Bitte ebenfalls den Abschnitt 'Working with the timer conflict menu' im MANUAL bercksichtigen. =head3 1.4.7 Email-Benachrichtigungen (Bitte sicherstellen, dass 'sendEmail.pl' im Pfad der ausfhrbaren Dateien liegt und 'epgsearchupdmail.templ' und 'epgsearchconflmail.templ' im Konfig-Verzeichnis von epgsearch existieren!) =over 4 =item - B Diese Option aktivieren, wenn man eine Email-Benachrichtigung wnscht, sobald der Suchtimer-Hintergrund-Thread - neue Timer angelegt hat - vorhandene Timer gendert hat - Timer gelscht hat, weil diese wegen EPG-nderungen oder anderen Benutzeraktionen nicht mehr gltig sind. (Dazu muss ebenfalls die Option 'Verwende Suchtimer' im Suchtimer-Setup aktiv sein.) =item - B Fr Benachrichtigungen zu Suchtimern kann hier angegeben werden, welchen Mindestabstand in Stunden die Mails haben sollen. Sobald die entsprechende Zeit verstrichen ist, wird eine Mail nach dem nchsten Suchtimer-Update versandt. Der Wert '0' bedeutet keine Verzgerung und bewirkt einen sofortigen Mailversand. =item - B Diese Option aktivieren, wenn man eine Email-Benachrichtigung bei Timer-Konflikten wnscht. Es werden nur Konflikte gemeldet, die laut Setup-Einstellungen 'relevant' sind. Neue Benachrichtigungen werden nur versandt, sobald sich etwas bei den Konflikten verndert. (Dazu muss ebenfalls die Option 'Nach jedem Suchtimer-Update' oder 'nach ... Minuten' im Timer-Konflikt-Setup aktiv sein.) =item - B Hier bitte die volle (!) Email-Adresse hinterlegen, an die die Nachrichten verschickt werden sollen. Hinweis: Einigen Provider (z.B. Arcor) erlauben nicht die gleiche Adresse fr Sender und Empfnger. =item - B Zur Auswahl stehen - sendEmail.pl: ein einfaches Skript, das auch auf Systemen ohne konfigurierten Mailserver den Versand von Emails erlaubt. Das Skript wird mit epgsearch ausgeliefert und sollte im $PATH liegen. - sendmail: setzt ein korrekt aufgesetzes Mailsystem voraus. =item - B Hier bitte die volle (!) Email-Adresse hinterlegen, von der die Nachricht versandt werden soll. =item - B Der Name des SMTP Servers, ber den der Mailversand erfolgt. =item - B 'Ja' whlen wenn das Emailkonto eine SMTP-Authentifizierung fr den Emailversand bentigt. =item - B Hier bitte den Benutzernamen angeben, falls das Email-Konto mit Authentifizierung arbeitet. =item - B Hier bitte das Passwort angeben, falls das Email-Konto mit Authentifizierung arbeitet. Achtung: Das Passwort wird im Klartext gespeichert. Man muss selber dafr sorgen, dass das System sicher ist und nicht authorisierten Personen kein Zugriff auf VDR-Konfigurations-Dateien mglich ist. =back Nach Angabe der Email-Konto-Daten bitte mit 'Test' prfen, ob alles funktioniert. Wenn mit 'sendEmail.pl' gearbeitet wird, sollte am Ende der Test-Ausgabe etwas wie 'Email sent successfully' auftauchen. Die Testfunktion gibt es bei der Methode 'sendmail' leider nicht. Bitte ebenfalls den Abschnitt 'Email notifications' im Manual bercksichtigen. =head1 2. Suchtimer Das ist ziemlich das gleiche wie VDRAdmin's Autotimer, bentigt jedoch kein externes Programm. Beim Anlegen einer Suche kann man die Option setzen, ob diese als Suchtimer verwendet werden soll. Das Plugin sucht nun im Hintergrund in bestimmten Zeitabstnden (->Setup->Update Intervall [min]) nach passenden Sendungen und erzeugt Timer fr die Ergebnisse. Gerade fr Serien ist dies sehr praktisch, weshalb es in der Suche die Option "Serienaufnahme" gibt. In diesem Fall wird ein Timer mit zustzlichem Episodennamen angelegt. Die Aufnahme erscheint dann in einem Ordner mit dem Seriennamem. Falls es keinen Episodennamen gibt wird stattdessen automatisch Datum und Uhrzeit verwendet. Die Suchtimer-Funktion muss ausserdem im Setup aktiviert werden. Falls fr SVDRP nicht der Standardport verwendet wird, bitte ebenfalls im Setup eintragen. Falls man eine Hintergrund-Suche manuell anstoen will, gengt ein touch /etc/vdr/plugins/epgsearch/.epgsearchupdate Das kann ebenfalls Teil des shutdown-Skripts sein (hier sollte man dann noch einen sleep von ein paar Sekunden anhngen, damit das Plugin Zeit hat, den Scan zu beenden). Mehr Infos zu Suchtimern gibts im MANUAL unter 'Description of the search process' und 'How do Search Timers work?'. =head1 2.1 'Wiederholungen vermeiden' - Im Detail Hier soll erklrt werden wie die Option 'Wiederholungen vermeiden' eines Suchtimers funktioniert. Nicht immer lsst sich durch entsprechende Suchkriterien vermeiden, dass auch Timer fr Wiederholungen erzeugt werden. Um das zu verhindern, versucht das Feature 'Wiederholungen vermeiden' vor dem Programmieren einer Sendung zu prfen, ob eine gleiche Sendung schon mal aufgenommen wurde oder ein Timer existiert, der die gleiche (nicht dieselbe!) Sendung aufzeichnet. Ist dies der Fall, wird kein Timer fr die zu berprfende Sendung erzeugt. =head2 2.2 Wie funktioniert der Vergleichstest zwischen 2 Sendungen? Fr den Test auf Gleichheit zwischen 2 Sendungen gibt es viele Einstellmglichkeiten beim Suchtimer. Man kann whlen, ob Titel, Untertitel, Beschreibung und bestimmte Kategorien innerhalb der Beschreibung einer Sendung mit den jeweiligen Angaben einer anderen Sendung verglichen werden sollen. Der Vergleich der einzelnen Angaben selbst prft immer auf vollstndige Identitt. Die Beschreibung einer Sendung bildet hier aber eine Ausnahme. Hier wird zunchst alles aus dem Text entfernt, das einer Kategorie-Angabe gleicht, z.B. 'Bewertung: Tagestipp'. Als Kategorie-Angabe wird alles gewertet, was am Anfang einer Zeile maximal 40 Zeichen hat, von einem ':' gefolgt wird und dann maximal weitere 60 Zeichen hat. Hintergrund fr dieses Rausschneiden sind die oft vorhandenen Bewertungen wie 'Tagestipp', die bei der Wiederholung aber nicht mehr enthalten sind. Der verbleibende Text wird nun zunchst in der Lnge verglichen. Ist der Unterschied grer als 90% wird die Beschreibung als unterschiedlich gewertet. Andernfalls wird ber den Levinsthein-Distance-Algorithmus (LD), der einen Fuzzy-Textvergleich macht, ein Test vorgenommen. Hier wird die Beschreibung als gleich akzeptiert, wenn LD mehr als 90% Identitt zurckgibt. Da dieser Algorithmus ziemlich laufzeitintensiv ist (O(mn)), sollte nach Mglichkeit nicht nur 'Vergleiche Beschreibung' als einziges Vergleichskriterium ausgewhlt werden, sondern am besten immer nur in Kombination mit anderen Vergleichen. =head2 2.3 Wie und wo wird der Vergleichstest eingesetzt? Wie zuvor erwhnt wird bei einem Suchtimer-Update fr Suchtimer mit diesem Feature zustzlich geprft, ob eine Sendung bereits irgendwann schon aufgezeichnet wurde, oder in der Timerliste ein Timer steht, der die gleiche Sendung aufzeichnen wrde. Letzteres sollte klar sein, whrend fr ersteres das File epgsearchdone.data ins Spiel kommt. Nach jeder Aufnahme, die durch einen Suchtimer mit 'Wiederholung vermeiden' erzeugt wurde, werden alle Angaben zu dieser Sendung im genannten File gespeichert. ber das Aktionenmen im Men 'Suche' kann man sich alle Sendungen, die ein solcher Timer bisher aufgenommen hat, anzeigen lassen und diese auch bearbeiten. In dieses File werden nur Aufnahmen aufgenommen, die bezglich der Timerangaben korrekt begonnen und auch beendet wurden. D.h. dass teilweise unvollstndige Aufnahmen nicht registriert werden und somit beim nchsten Suchtimer-Update automatisch ein neuer Timer fr diese Sendung erzeugt wird, falls gefunden. B Man sieht, dass das ganze Feature stark von der Qualitt und dem Umfang des verwendeten EPGs abhngt. Hat man einen entsprechenden Suchtimer angelegt, ist es sinnvoll erstmal zu prfen, ob er auch das richtige macht. Dazu gibt es fr solche Timer im Suchergebnis-Men auf der Taste 'Blau' die zustzliche Belegung 'Timer-Vorschau'. Sendungen, die noch keinen Timer haben ('T'), aber fr die einer aufgrund des Features beim nchsten Suchtimer-Update programmiert wrde, haben dort ein 'P' stehen. Hinweis: Mchte man wegen Konflikten einen bereits programmierten Timer nicht verwenden, dann sollte dieser im Timermen deaktiviert werden. Beim nchsten Suchtimer-Update wird dann einfach die nchste mgliche Wiederholung programmiert, falls vorhanden. B Damit das Programmieren oder Nicht-Programmieren von Timern gerade bei Verwendung dieses Features besser nachvollziehbar ist, wurde ein Logfile fr epgsearch eingefhrt. Startet man epgsearch mit einem Loglevel >= 2 (-P'epgsearch -v 2) werden beim Suchtimer-Update in der Datei epgsearch.log hilfreiche Infos abgelegt. Siehe MANUAL fr 'command line options'. =head1 3. Verwendung der Suche durch andere Plugins oder Skripte Siehe C. =head1 4. Verwendung erweiterter EPG Infos Einige EPG Provider liefern zustzliche EPG Infos wie die Art der Sendung, das Video und Audio Format, die Besetzung,... in der Beschreibung der Sendung. Anmerkung: Dies hat nichts mit den content descriptors seit vdr-1.7.11 zu tun, die als zustzliche Daten nach einem gemeinsamen Standard aufgeliefert werden. Leider liefern nicht alle Provider diese Daten oder setzen die Kennungen nicht korrekt. Deshalb gibt es den Ansatz der "erweiterten EPG Infos", der versucht diese Information aus der Inhaltsbeschreibung zu extrahieren. Mit tvmovie2vdr oder epg4vdr knnen diese Daten in den VDR importiert werden. Somit kann man also z.B. einfach einen Suchtimer erzeugen, der alle Tagestipps findet, die in 16:9 ausgestrahlt werden. Um diese Informationen in Suchtimern zu verwenden, muss anhand der Datei epgsearchcats.conf im epgsearch-Konfig-Verzeichnis eine Konfiguration vorgenommen werden. Das Format dieser Datei ist folgendes: ID|category name|name in menu|values separated by ','(option)|searchmode(option) - 'ID' sollte eine eindeutige ganze Zahl sein Achtung: ndert man spter aus irgendeinem Grund diese ID mssen die Suchtimer neu editiert werden! - 'category name' ist der Name der Info lt. EPG Provider, z.B. 'Genre' - 'name in menu' ist der Name im Men von epgsearch. - 'values' ist eine optionale Liste von Werten fr diese Info. - 'searchmode' gibt optional an, wie gesucht werden soll: Textvergleich: 0 - Der gesamte Begriff muss als Substring erscheinen 1 - Die einzelnen Worte (getrennt durch ',', ';', '|' oder '~') mssen alle als Substring auftauchen. Diese Einstellung ist der Standardwert. 2 - mindestens ein Wort (getrennt durch ',', ';', '|' oder '~') muss als Substring auftauchen 3 - exakte bereinstimmung 4 - als regulrer Ausdruck Numerischer Vergleich: 10 - kleiner 11 - kleiner oder gleich 12 - grer 13 - grer oder gleich 14 - gleich 15 - ungleich Beispiel-Dateien fr epgsearchcats.conf kommen mit dem Plugin im Verzeichnis 'conf'. Einfach die passende ins epgsearch-Konfig-Verzeichnis als epgsearchcats.conf kopieren, VDR neu starten und dann das Eingabe-Men eines Suchtimers aufrufen. Weil das Aufsetzen einer neuen epgsearchcats.conf ziemlich lstig ist, habe ich ein kleines Tool 'createcats' mitgeliefert, das den Groteil der Arbeit erledigt. Es sollte mit dem Plugin bersetzt worden sein und sich im Quellverzeichnis befinden. Einfach folgendermaen aufrufen: createcats /pfad_zu/epg.data Dieses Tool scannt nun die vorhandenen EPG infos und versucht daraus die erweiterten Infos zu extrahieren. Das Ergebnis ist eine neue epgsearchcats.conf, die aber noch editiert werden muss, weil sicher nicht alles genau passt. Danach ins epgsearch-Konfig-Verzeichnis kopieren. (Mehr ber createcats im Manual 'Using createcats') Details: epgsearch durchsucht die Zusammenfassung einer Sendung nach dem Namen einer Kategorie gefolgt von ': '. Das geschieht fr alle Kategorien, fr die im Suchtimer ein Wert gesetzt wurde. Die Suche bercksichtigt die Gro/Kleinschreibung sowohl bezglich des Kategorie-Namens als auch des Wertes. =head1 5. Ersetzen des Standardmen Um das Plugin als Ersatz fr VDR's Standard-Men zu verwenden, gengt es die Zeile Green @epgsearch in die Datei keymacros.conf zu setzen. Falls kein weiterer Meneintrag im Hauptmen erscheinen soll, dann den Eintrag des Plugins zunchst im Setup ausblenden. Um das Plugin trotzdem mit der Taste "Grn" aufrufen zu knnen, knnte man z.B. mein launcher-Plugin verwenden und die Zeile Green @launcher x in die keymacros.conf schreiben, wobei x die Position von epgsearch innerhalb des launcher listings ist. Ein weiterer Ansatz ist ein Patch gegen VDR, der das Standardmen 'Programm' gegen epgsearch austauscht. Hierzu VDR mit dem Patch vdr-replace-schedulemenu.diff.gz aus dem Patches-Verzeichnis patchen. Danke an den Autor Uwe/egal@vdrportal. Bei Anwendung dieses Patches sollte der Eintrag Green Schedule heien. Dieser Patch ist bereits in manchen Patchsammlungen, z.B. Bigpatch, enthalten. =head1 6. Addons Mit epgsearch werden 2 weitere 'Mini'-Plugins ausgeliefert. Beide Plugins erfordern, dass epgsearch ebenfalls installiert ist (epgsearch kann aber aus dem Hauptmen ausgeblendet werden): =over 4 =item - B Wer nur die Suchfunktionen und/oder die Suchtimer von epgsearch verwenden mchte oder einfach einen eigenen Hauptmeneintrag fr die Suche wnscht, kann dies mit diesem Plugin erreichen. Es wird damit ein Hauptmeneintrag "Suche" erzeugt, der einen direkt in das Suchenmen fhrt. Aktivierung im VDR-Startskript mit "-Pepgsearchonly". =item - B Die Timer-Konfliktprfung kann ebenfalls als eigener Hauptmeneintrag angelegt werden. ber eine Setup-Option lt sich auch das Ergebniss der letzten Konfliktprfung direkt im Hauptmen anzeigen. Aktivierung im VDR-Startskript mit "-Pconflictcheckonly". =back Viel Spass! Christian Wieninger =head1 Ausfhrliche Beschreibung Die ausfhrliche Beschreibung der internen Funktionen des Plugins findest Du in der Datei MANUAL, die dem Plugin beigelegt sein sollten. Ob Du diese auf deinem System hast verrt dir C Sollte Deine Distribution diese Dateien nicht enthalten, kannst Du sie dir online durchlesen L L L =head1 SIEHE AUCH C, C, C, C, C, C, C, C, C, C =head1 DATEIEN F Enthlt die Suchtimer. Siehe C. F Enthlt die Kategorien des erweiterten EPG. Siehe C. F Enthlt Befehle hnlich der commands.conf, die auf EPG-Eintrge angewandt werden knnen. Siehe C. F Enthlt Pfade die beim Bearbeiten eines Suchtimers ausgewhlt werden knnen. Siehe C. F Enthlt die vom User gewhlte Konfiguration der OSD Mendarstellung. Siehe C. F Enthlt die User-Variablen. Siehe C. F Enthlt die done-Liste. Siehe C. F Enthlt die Umschalttimer. Siehe C. F Enthlt die Ausschlussliste. Siehe C. F Enthlt die Kanalgruppen. Siehe C. F Enthlt die Vorlagen fr Suchtimer. Siehe C. =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/epgsearchcmds.conf.5.txt0000644000175000017500000000445112100027260022055 0ustar winniwinni=head1 NAME F - EPG-Befehle =head1 BESCHREIBUNG Diese Datei enthlt hnlich der commands.conf oder der reccmds.conf Befehle, die auf die in der Programmbersicht ausgewhlte Sendung angewandt werden knnen. Intern besitzt epgsearch 8 nicht vernderbare EPG-Befehle. Wenn eine F existiert, werden die darin aufgefhrten Befehle beginnend mit Nummer 9 gelistet. =head2 Sprachen Man kann fr verschiedene Sprachen unterschiedliche Dateien anlegen. Sie mssen dann z.B. F fr deutsch oder F fr englisch heissen. Wenn eine Datei entsprechend der im VDR eingestellten Sprache existiert wird diese geladen. Existiert eine solche nicht wird versucht F zu laden. =head1 FORMAT Befehlsname : Befehl =head1 BEISPIELE epg2taste (de): /usr/local/vdr/epg2taste.sh =head1 SIEHE AUCH C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/epgsearchchangrps.conf.5.txt0000644000175000017500000000420412100027260022730 0ustar winniwinni=head1 NAME F - Liste der Kanalgruppen =head1 BESCHREIBUNG In epgsearch kann man Sender zu Kanalgruppen zusammenfassen die dann in den Suchtimern verwendet werden knnen. Hierdurch knnen fr viele Suchtimer auf einmal die durchsuchten Kanle zentral neu konfiguriert werden. In dieser Datei werden die Kanalgruppen gespeichert. =head1 FORMAT Jede Zeile eine Kanalgruppe. Jede Zeile beginnt mit dem Gruppennamen, dahinter, getrennt durch '|', die Liste der Kanle. =head1 BEISPIELE (Die Zeilen sind gekrzt, daher unvollstndig) Private|S19.2E-133-33-46|S19.2E-133-33-51 ProsiebenSat.1|S19.2E-133-33-46|S19.2E-133-33-47 RTL World|S19.2E-1-1089-12003||S19.2E-1-1089-12090 =head1 SIEHE AUCH C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/epgsearchmenu.conf.5.txt0000644000175000017500000001145612100027260022076 0ustar winniwinni=head1 NAME F - Konfiguration der Mendarstellung =head1 BESCHREIBUNG Die Darstellung des Mens des Plugins kann auf die eigenen Wnsche angepasst werden. Die Konfiguration erfolgt mit Hilfe dieser Datei. =head1 FORMAT In dieser Datei knnen den Variablen MenuWhatsOnNow MenuWhatsOnNext MenuWhatsOnElse MenuSchedule MenuSearchResults Zeichenketten zugewiesen werden die die Darstellung der Mens im OSD regeln. Eine Besonderheit stellt MenuSearchResults. Hier kann man der Variablen MenuSearchResults eine beliebige Zeichenkette anhngen: MenuSearchResultsSerienlayout=... Dies bewirkt das man beim Editieren eines Suchtimers nun auch dieses Layout unter dem Namen "Serienlayout" auswhlen kann. So kann man jedem Suchtimer seine eigene OSD Darstellung verpassen. Es knnen alle Variablen verwendet werden. Die Variablen aus dem erweiterten EPG, die in der F konfigurierten sowie die folgenden internen: %title% - Title der Sendung %subtitle% - Subtitle der Sendung %time% - Startzeit im Format HH:MM %date% - Startzeit im Format TT.MM.YY %datesh% - Startdatum im Format TT.MM. %time_w% - Name des Wochentages %time_d% - Tag der Sendung im Format TT %time_lng% - Startzeit in Sekunden seit 1970-01-01 00:00 %t_status% - Timerstatus ('T', 't', 'R') %v_status% - VPS Status %r_status% - Running Status %status% - Kompletter Status, das selbe wie '%t_status%%v_status%%r_status%' Fr die Mens "Was luft jetzt" und "Suchergebniss", also die Variablen MenuWhatsOnNow und MenuSearchResults, stehen fnf weitere Variablen zur Verfgung: %chnr% - Kanalnummer %chsh% - Kanalname kurz %chlng% - Kanalname lang %chdata% - VDR's interne Kanaldarstellung (z.B. 'S19.2E-1-1101-28106') %progr% - Grafischer Fortschrittsbalken (nicht fr das Men "Suchergenis") %progrT2S% - Fortschrittsbalken im text2skin Stil (nicht fr das Men "Suchergenis") Es wird bei den Variablen nicht zwischen Gross-/Kleinschreibung unterschieden. Ein Eintrag besteht aus bis zu 6 Tabellenspalten, die Spalten werden durch '|' getrennt. Der letzte Eintrag jeder Spalte kann die Spaltenbreite durch angabe einer Breite in Zeichen festlegen. Die Breitenangabe wird durch ':' vom Variablennamen getrennt. Wenn du Trenner wie '~', '-' oder '#' verwendest um einzelne Bestandteile zu trennen, z.B. %title% ~ %subtitle%, dann achtet epgsearch darauf das ein solcher Trenner nicht am Ende einer Spalte steht. Die einzelnen Spaltenbreiten sollten angepasst werden, das Aussehen ist vom verwendeten Skin abhngig. Wenn diese Datei verndert werden soll whrend VDR luft kann man dem Plugin den Startparamter '-r' oder '--reloadmenuconf' bergeben, die Datei wird dann bei jedem ffnen des Mens neu eingelesen. =head1 BEISPIELE MenuWhatsOnNow=%chnr%:3|%progrt2s%:5| %time% %t_status%:8|%category%:6| %title% ~ %subtitle%:35 MenuWhatsOnNext=%chnr%:3|%time% %t_status%:8|%category%:8| %title% ~ %subtitle%:35 MenuWhatsOnElse=%chnr%:3|%time% %t_status%:8|%category%:8| %title% ~ %subtitle%:35 MenuSchedule=%time% %t_status%:8|%genre%:14| %title% ~ %subtitle%:35 MenuSearchResults=%chnr%:3|%datesh% %time% %t_status%:14|%genre%:8| %title%%colon% %subtitle%:35 MenuFavorites=%chnr%:3|%datesh% %time% %t_status%:14|%genre%:8| %title%%colon%%subtitle%:35 =head1 SIEHE AUCH C, C, C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/de/epgsearchdirs.conf.5.txt0000644000175000017500000000570012100027260022066 0ustar winniwinni=head1 NAME F - Liste von Aufnahmepfaden zur einfachen Auswahl =head1 BESCHREIBUNG In epgsearch, speziell beim Editieren von Suchtimern, muss man hufig ganze Verzeichnisspfade eingeben. Da dies oft mhselig ist, knnen in dieser Datei hufig genutzte Pfade vorgegeben werden, die dann im Men einfach ausgewhlt werden knnen. =head1 FORMAT Pro Zeile ein Pfad. Pfade knnen Variablen enthalten. Verwendet werden knnen interne Variablen, die Variablen des erweiterten EPG (F) sowie die in der Datei F konfigurierten Variablen. Folgende internen Variablen stehen zur Verfgung: %title% - Title der Sendung %subtitle% - Subtitle der Sendung %time% - Startzeit im Format HH:MM %date% - Startzeit im Format TT.MM.YY %datesh% - Startdatum im Format TT.MM. %time_w% - Name des Wochentages %time_d% - Tag der Sendung im Format TT %chnr% - Kanalnummer %chsh% - Kanalname kurz %chlng% - Kanalname lang Fr weitere Variablen siehe C und C. Im Auswahlmen werden die Pfade alphabetisch sortiert dargestellt. Pfade die Variablen enthalten stehen am Anfang der Liste. =head1 BEISPIELE %Category%~%Genre% %Category%~%Genre%~%Title%~%Episode%: %Subtitle% Information~Natur~%Title%~%Episode%: %Subtitle% %Serie% Spielfilm~Action Spielfilm~Doku Spielfilm~Drama Spielfilm~Horror Musik Sport Show Serie =head1 SIEHE AUCH C, C, C =head1 AUTOR (man pages) Mike Constabel =head1 FEHLER MELDEN Fehlerberichte bitte im Bugtracker. L Mailinglist: L =head1 COPYRIGHT and LIZENZ Copyright 2004-2010 Christian Wieninger Dieses Programm ist freie Software. Sie knnen es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation verffentlicht, weitergeben und/oder modifizieren, entweder gem Version 2 der Lizenz oder (nach Ihrer Option) jeder spteren Version. Die Verffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Oder rufen Sie in Ihrem Browser http://www.gnu.org/licenses/old-licenses/gpl-2.0.html auf. Der Author kann ber cwieninger@gmx.de erreicht werden. Die Projektseite ist http://winni.vdr-developer.org/epgsearch Der MD5-Code ist abgeleitet aus dem Message-Digest Algorithm von RSA Data Security, Inc.. epgsearch-1.0.1.beta3/doc-src/en/0000755000175000017500000000000012112103675015433 5ustar winniwinniepgsearch-1.0.1.beta3/doc-src/en/createcats.1.txt0000644000175000017500000000722712100027260020451 0ustar winniwinni=head1 NAME B - helps you creating your own F =head1 SYNOPSIS B [OPTIONS] F =head1 DESCRIPTION This tool is deliverd with the plugin and should exist in the plugins source directory after compilation. It helps you in creating your own epgsearchcats.conf, if the samples in directory 'conf' don't fit your needs. createcats takes your epg.data as argument and scans it for suitable EPG infos. Such an info is a set of a category name and a coresponding value at the beginning of a line (represented with '|') and has the form '|category: value', e.g. |Genre: Action So simply call it with B /path_to/epg.data The output is a file epgsearchcats.conf, that should be copied to your plugins config dir. Before using it, you should do some customizing, since not all things in the file will be suitable to be used as extended EPG info. =head1 OPTIONS The full set of arguments is: usage: B [OPTIONS] F -m N, --minappearance=N the minimum number a category has to appear to be used -v N, --maxvalues=N values of a category are omitted if they exceed this number -l N, --maxlength=N the maximum length of a text to be accepted as a category value -h, --help this help Some notes: =over 4 =item -m N, --minappearance=N createcats counts how often a category is used in your current epg.data. If this is less than N, then this category will not be part of the resulting epgsearchcats.conf. =item -v N, --maxvalues=N if the number of values for a category is more than N then createcats will not output a value list for this category. As a consequence in epgsearch the menu item gets an edit item, that can be filled with every text. Else, the item gets a selection item, that lets you select from a list of values. =item -l N, --maxlength=N if the text length of a value is more than N, this value is not part of the value list. =back B Results are best, if your current EPG is as big as possible. So update it, if you are using an external EPG provider, before calling createcats. Please edit this file now, since it will contain also things not suitable. After that copy it to your plugins config directory. =head1 SEE ALSO C, C, C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bugreports (german): L Mailinglist: L =head1 COPYRIGHT and LICENSE Copyright (C) 2004-2010 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/epgsearchtemplates.conf.5.txt0000644000175000017500000000324312100027260023135 0ustar winniwinni=head1 NAME F - Searchtimer templates =head1 DESCRIPTION In epgsearch searchtimer templates can be created for easy creating new searchtimers. These templates are saved in this file. =head1 SYNTAX This file has the same syntax as the epgsearch.conf. So please refer to F, see C. =head1 SEE ALSO C, C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bug reports (german): L Mailing list: L =head1 COPYRIGHT and LICENSE Copyright (C) 2004-2010 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/epgsearchcats.conf.5.txt0000644000175000017500000001024012100027260022064 0ustar winniwinni=head1 NAME F - Configuration of the additional EPG information =head1 DESCRIPTION Some EPG providers deliver additional EPG information like the type of event, the video and audio format, cast,... Using tvm2vdr or epg4vdr you can import this into vdr. To use this information with search timers one has to configure it with the file epgsearchcats.conf in your plugins config directory. Sample files for F are delivered with the plugin in the directory 'conf'. Simply copy the one that fits for you to your plugins config directory with filename epgsearchcats.conf and then have a look to the search timers edit menu (after a restart of VDR). Since setting up a new F is a lot of work, I've added a small tool 'createcats', that makes the biggest part of the job. It should have been compiled with the plugin and exists in the sources directory. See C for information about how to use it. B epgsearch scans the summary of an event for the category name followed by ': ' for all categories that have a corresponding value set in the search timer. The search is case sensitive regarding the category name as also the value. =head1 SYNTAX ID|category name(,format)|name in menu|values separated by ','(option)|searchmode(option) - 'ID' should be a unique positive integer (changing the id later on will force you to re-edit your search timers!) - 'category name' is the name as delivered by the EPG provider, e.g. 'Genre' you can optionally provide a format specifier for numeric values, e.g. Episode,%02i - 'name in menu' is the name displayed in epgsearch. - 'values' is an optional list of possible values - 'searchmode' specifies the search mode: text comparison: 0 - the whole term must appear as substring 1 - all single terms (delimiters are ',', ';', '|' or '~') must exist as substrings. This is the default search mode. 2 - at least one term (delimiters are ',', ';', '|' or '~') must exist as substring. 3 - matches exactly 4 - regular expression numerical comparison: 10 - less 11 - less or equal 12 - greater 13 - greater or equal 14 - equal 15 - not equal =head1 EXAMPLE (Lines are shortened for correct displaying) Example for EPG from Hrzu, downloaded from epgdata.com with tvmovie2vdr. 1|Category|Kategorie|Information,Kinder,Musik,Serie,Show,Spielfilm,Sport|2 2|Genre|Genre|Abenteuer,Action,Wirtschaft,Wissen,Zeichentrick|2 3|Format|Video-Format|16:9,4:3|2 4|Audio|Audio|Dolby Surround,Dolby,Hoerfilm,Stereo|2 5|Year|Jahr||2 6|Cast|Besetzung||2 7|Director|Regisseur||2 8|Moderator|Moderation||2 9|Rating|Bewertung|Groartig besonders wertvoll,Annehmbar,Schwach|2 10|FSK|FSK|6,12,16,18|2 11|Country|Land||2 12|Episode|Episode||4 13|Themes|Thema||4 =head1 SEE ALSO C, C, C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bug reports (german): L Mailing list: L =head1 COPYRIGHT and LICENSE Copyright (C) 2004-2010 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/epgsearch.conf.5.txt0000644000175000017500000001322412100027260021216 0ustar winniwinni=head1 NAME F - The searchtimers =head1 DESCRIPTION This file contains the searchtimers. Do not edit it manually, you should use SVDRP. =head1 SYNTAX Due to some new features there was a change in the format. The format is now signed with a comment in the first line. The field delimiter is B<':'>: 1 - unique search timer id 2 - the search term 3 - use time? 0/1 4 - start time in HHMM 5 - stop time in HHMM 6 - use channel? 0 = no, 1 = Interval, 2 = Channel group, 3 = FTA only 7 - if 'use channel' = 1 then channel id[|channel id] in VDR format, one entry or min/max entry separated with |, if 'use channel' = 2 then the channel group name 8 - match case? 0/1 9 - search mode: 0 - the whole term must appear as substring 1 - all single terms (delimiters are blank,',', ';', '|' or '~') must exist as substrings. 2 - at least one term (delimiters are blank, ',', ';', '|' or '~') must exist as substring. 3 - matches exactly 4 - regular expression 10 - use title? 0/1 11 - use subtitle? 0/1 12 - use description? 0/1 13 - use duration? 0/1 14 - min duration in hhmm 15 - max duration in hhmm 16 - use as search timer? 0/1 17 - use day of week? 0/1 18 - day of week (0 = Sunday, 1 = Monday...; -1 Sunday, -2 Monday, -4 Tuesday, ...; -7 Sun, Mon, Tue) 19 - use series recording? 0/1 20 - directory for recording 21 - priority of recording 22 - lifetime of recording 23 - time margin for start in minutes 24 - time margin for stop in minutes 25 - use VPS? 0/1 26 - action: 0 = create a timer 1 = announce only via OSD (no timer) 2 = switch only (no timer) 3 = announce via OSD and switch (no timer) 4 = announce via mail 27 - use extended EPG info? 0/1 28 - extended EPG info values. This entry has the following format (delimiter is '|' for each category, '#' separates id and value): 1 - the id of the extended EPG info category as specified in epgsearchcats.conf 2 - the value of the extended EPG info category (a ':' will be translated to "!^colon^!", e.g. in "16:9") 29 - avoid repeats? 0/1 30 - allowed repeats 31 - compare title when testing for a repeat? 0/1 32 - compare subtitle when testing for a repeat? 0/1/2 0 - no 1 - yes 2 - yes, if present 33 - compare description when testing for a repeat? 0/1 34 - compare extended EPG info when testing for a repeat? This entry is a bit field of the category IDs. 35 - accepts repeats only within x days 36 - delete a recording automatically after x days 37 - but keep this number of recordings anyway 38 - minutes before switch (if action = 2) 39 - pause if x recordings already exist 40 - blacklist usage mode (0 none, 1 selection, 2 all) 41 - selected blacklist IDs separated with '|' 42 - fuzzy tolerance value for fuzzy searching 43 - use this search in favorites menu (0 no, 1 yes) 44 - id of a menu search template 45 - auto deletion mode (0 don't delete search timer, 1 delete after given count of recordings, 2 delete after given days after first recording) 46 - count of recordings after which to delete the search timer 47 - count of days after the first recording after which to delete the search timer 48 - first day where the search timer is active (see parameter 16) 49 - last day where the search timer is active (see parameter 16) 50 - ignore missing EPG categories? 0/1 51 - unmute sound if off when used as switch timer 52 - percentage of match when comparing the summary of two events (with 'avoid repeats') 53 - HEX representation of the content descriptors, each descriptor ID is represented with 2 chars 54 - compare date when testing for a repeat? (0=no, 1=same day, 2=same week, 3=same month) A ':' in the search term or the directory entry will be translated in a '|'. If a '|' exists in the search term, e.g. when using regular expressions, it will be translated to "!^pipe^!" (I know it's ugly ;-)) There's no need to fill all fields, only the first 11 fields must exist. =head1 EXAMPLE #version 2 - DON'T TOUCH THIS! 1:Kommissar Beck:0:::2:ffRecht:0:0:1:0:0:0:::1:0:0:1:%Category%~%Genre%:50:99:10:60:0:0:0::1:0:1:1:0:0:0:0:0 2:* Sgebrecht:0:::2:Hauptsender:0:0:0:0:0:0:::0:0:0:0:%Category%~%Genre%:50:99:10:10:0:0:1:1#|2#|3#|4#|5#|6#Marianne Sgebrecht|7#|8#|9#|10#|11#|12#|13#:1:0:1:0:0:0:0:0:0 =head1 SEE ALSO C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bug reports (german): L Mailing list: L =head1 COPYRIGHT and LICENSE Copyright (C) 2004-2010 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/epgsearchswitchtimers.conf.5.txt0000644000175000017500000000357212100027260023671 0ustar winniwinni=head1 NAME F - The list of switchtimer =head1 DESCRIPTION In epgsearch switchtimer can be created via the program menu or the searchtimers. These switchtimer can switch the channel at the beginning of the event or only inform you about the start via OSD. The switchtimers are saved in this file. =head1 SYNTAX The delimiter is ':'. This fields are possible: 1 - Channel 2 - Event ID 3 - Start time 4 - Minutes to switch before event 5 - Only inform via OSD 6 - unmute sound if off =head1 EXAMPLE S19.2E-1-1089-12060:52221:1153322700:1:0 =head1 SEE ALSO C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bug reports (german): L Mailing list: L =head1 COPYRIGHT and LICENSE Copyright (C) 2004-2010 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/epgsearchblacklists.conf.5.txt0000644000175000017500000000417212100027260023274 0ustar winniwinni=head1 NAME F - Blacklist =head1 DESCRIPTION You can create blacklists in epgsearch and use them in searchtimers. A blacklist entry is like a normal searchtimer which is saved in the file F. While editing an searchtimer you can select one ore more blacklist entries. =head2 USAGE Searchtimer "Action" use blacklist "Damme". Blacklist entry "Damme" searches "Damme" First the searchtimer searches all films with "Action". Then for each search result epgsearch will test if the result matches against "Damme". If so, the result will be dismissed. =head1 SYNTAX This file uses the same syntax as F except that theres no field. So there's a shift by one field from this position. Because that, see C. =head1 SEE ALSO C, C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bug reports (german): L Mailing list: L =head1 COPYRIGHT and LICENSE Copyright (C) 2004-2010 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/timersdone.conf.5.txt0000644000175000017500000000375012100027260021431 0ustar winniwinni=head1 NAME F - list of current timers created by search timers =head1 DESCRIPTION This file contains the current timers that were created by search timers. If the setup option 'Recreate timers after deletion' is set to 'no', epgsearch uses this list to determine if a timer was already created and cancels further timer creations. If a corresponding recording was made for any timer in this list, the timer is automatically removed from it. =head1 FORMAT Timers are stored one per line, where the fields are separated with ':'. The following fields exists: 1 - channel-ID 2 - start time 3 - stop time 4 - search timer ID 5 - event title 6 - event episode =head1 SEE ALSO C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bug reports (german): L Mailing list: L =head1 COPYRIGHT and LICENSE Copyright (c) 2005-2006 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/epgsearch.4.txt0000644000175000017500000011341112100027260020270 0ustar winniwinni=head1 NAME F - Searchtimer and replacement of the VDR program menu =head1 OVERVIEW Since the README get bigger and bigger this man page shall be used to explain some things in detail. So it's not really a manual, but an extended README. =head1 CONTENT 1. Using variables in the directory entry of a search timer 2. The format of epgsearch.conf 3. Description of the search process 4. How do Search Timers work? 5. How to trigger a search timer update? 6. The sources of the 'Select directory' menu 7. Language dependent commands for EPG 8. Usage from other plugins or scripts 9. SVDRP interface 10. Customizing the EPG menus 11. Working with the timer conflict menu 12. User defined variables 13. Email notifications 14. The conf.d subdirectory =head1 1. Using variables in the directory entry of a search timer If you are using extended EPG information, you can use variables as part of a directory entry of a search timer. These variables always have the form '%variable%'. The name of a variable corresponds with the internal name of an extended EPG info, as specified in the file epgsearchcats.conf (samples can be found in subdirectory 'conf'). Example: 1|Category|Kategorie|Information,Kinder,Musik,Serie,Show,Spielfilm,Sport|3 The category with ID 1 has the internal name 'Category'. So you could use it with '%Category%'. The names are not case sensitive. Sample directory entries could look like this: My Movies~%Category% Childrens Movies~%category% %CATEGORY%~%genre% There are also three other variables: %Title%, %Subtitle% and %chlng%. If you don't use %Title%, the title is always automatically appended to the directory entry, when a timer will be created. If you set 'serial recording' to 'yes' in your search timer then also the subtitle will be automatically appended. So the directory entry %Category%~%Genre%~%Title%~%Subtitle% is the same as %Category%~%Genre% (with 'serial recording' set to 'yes'). The %chlng% variable gets replaced with the name of the channel. Attention: Automatically appending title and subtitle will not be done, if you use the variables %Title% or %Subtitle% in the directory entry. This allows one to form directory entries like this one: %Category%~%Genre%~%Title%~%Episode%~%Subtitle% There are also the following search variables: %search.query% that will be replaced with the query of the search timer %search.series% that is '1', if the search has its 'Series recording' flag set, else '0'. See also C. =head1 2. The format of epgsearch.conf Due to some new features there was a change in the format. The format is now signed with a comment in the first line. The field delimiter is B<':'>: 1 - unique search timer id 2 - the search term 3 - use time? 0/1 4 - start time in HHMM 5 - stop time in HHMM 6 - use channel? 0 = no, 1 = Interval, 2 = Channel group, 3 = FTA only 7 - if 'use channel' = 1 then channel id[|channel id] in vdr format, one entry or min/max entry separated with |, if 'use channel' = 2 then the channel group name 8 - match case? 0/1 9 - search mode: 0 - the whole term must appear as substring 1 - all single terms (delimiters are blank,',', ';', '|' or '~') must exist as substrings. 2 - at least one term (delimiters are blank, ',', ';', '|' or '~') must exist as substring. 3 - matches exactly 4 - regular expression 5 - fuzzy searching (specify tolerance in parameter 42, not available for EPG categories) 10 - use title? 0/1 11 - use subtitle? 0/1 12 - use description? 0/1 13 - use duration? 0/1 14 - min duration in minutes 15 - max duration in minutes 16 - use as search timer? 0/1/2 (with 2 one can specify time margins in parameter 48/49 where the search timer is active) 17 - use day of week? 0/1 18 - day of week (0 = Sunday, 1 = Monday...; -1 Sunday, -2 Monday, -4 Tuesday, ...; -7 Sun, Mon, Tue) 19 - use series recording? 0/1 20 - directory for recording 21 - priority of recording 22 - lifetime of recording 23 - time margin for start in minutes 24 - time margin for stop in minutes 25 - use VPS? 0/1 26 - action: 0 = create a timer 1 = announce only via OSD (no timer) 2 = switch only (no timer) 27 - use extended EPG info? 0/1 28 - extended EPG info values. This entry has the following format (delimiter is '|' for each category, '#' separates id and value): 1 - the id of the extended EPG info category as specified in epgsearchcats.conf 2 - the value of the extended EPG info category (a ':' will be translated to "!^colon^!", e.g. in "16:9") 29 - avoid repeats? 0/1 30 - allowed repeats 31 - compare title when testing for a repeat? 0/1 32 - compare subtitle when testing for a repeat? 0=no/1=yes/2=yes-if present 33 - compare description when testing for a repeat? 0/1 34 - compare extended EPG info when testing for a repeat? This entry is a bit field of the category IDs. 35 - accepts repeats only within x days 36 - delete a recording automatically after x days 37 - but keep this number of recordings anyway 38 - minutes before switch (if action = 2) 39 - pause if x recordings already exist 40 - blacklist usage mode (0 none, 1 selection, 2 all) 41 - selected blacklist IDs separated with '|' 42 - fuzzy tolerance value for fuzzy searching 43 - use this search in favorites menu (0 no, 1 yes) 44 - number of the search menu template to use (only available if multiple search result templates are defined in epgsearchmenu.conf) 45 - auto deletion mode (0 don't delete search timer, 1 delete after given count of recordings, 2 delete after given days after first recording) 46 - count of recordings after which to delete the search timer 47 - count of days after the first recording after which to delete the search timer 48 - first day where the search timer is active (see parameter 16) 49 - last day where the search timer is active (see parameter 16) 50 - ignore missing EPG categories? 0/1 51 - unmute sound if off when used as switch timer 52 - the minimum required match in percent when descriptions are compared to avoid repeats (-> 33) A ':' in the search term or the directory entry will be translated in a '|'. If a '|' exists in the search term, e.g. when using regular expressions, it will be translated to "!^pipe^!" (I know it's ugly ;-)) See also C. =head1 3. Description of the search process First, for each broadcasting a search text divided by '~' is created, depending on the settings of 'Use title', 'Use subtitle' and 'Use description': title~subtitle~description If "Match case" is not set, the search text and the search term are transformed to lower case. Now depending on the search mode, the search term will be looked up in the search text: =over 4 =item - 'Phrase' matches if the search term is found anywhere in the search text. =item - 'at least one word', 'all words' first the search term will be split in single words. Delimiters are a blank and the characters ',' ';' '|' '~'. Then we check if at least one or all words appear in the search text. =item - 'match exactly' matches if search term and search text are identical. =item - 'regular expression' the search is done with a regular expression. You don't need a leading and trailing '/' in your search term. Two standards of regular expression are supported: extended POSIX and Perl compatible regular expressions (PCRE) (see F). =back If the search was successful until now, the other criterions (start time, duration, week day) are checked. =head1 4. How do Search Timers work? With each update, the plugin first sorts the search timers by timer priority (descending) and search term and then searches for new matches of your search timers. If a new match is found then a new timer is created. For serial recordings, the subtitle is appended to the recording directory. Many providers deliver the subtitle just 1-2 days before the event. The plugin uses then a date/time string for the subtitle, but replaces this one later if the subtitle is present. Start and end times of a broadcasting often vary a little bit. To avoid getting many different timers for the same event, the plugin checks before adding a new timer, if there is one, that has start and end times which only differ by a maximum of 10 minutes (or the events duration if this is less then 10 minutes). If so, the present timer is modified, else a new timer is created. If the timer was set to inactive there will be no update. Also manually corrected priority or lifetime will not be changed when updating. If you have set 'Announce only (no timer)' to yes, no timer is created. Instead you get an OSD message about the event. This message is displayed at each scan, but only if there is no timer for the event. =head1 5. How to trigger a search timer update? the update of search timers runs in its own thread. There are several ways to trigger it: =over 4 =item - automatically after VDR starts there is always an update (after a few seconds). After this, the setup option 'Update interval' tells epgsearch when the next update should be done repeatedly (in minutes). =item - manually extern the thread observes the file '.epgsearchupdate' in the plugins config directory. When you touch /path_to_file/.epgsearchupdate this will also trigger an update. So this is a simple solution to make an update e.g. by a script. =item - manually intern calling actions or pressing '3' in the menu of searches asks also for an update. =item - from other plugins =back there's a service 'Epgsearch-updatesearchtimers-v1.0' that can be used with the service interface of VDR from other plugins with the option to inform via OSD when the update has finished =head1 6. The sources of the 'Select directory' menu This menu displays directories, that can be used for search timers or ordinary timers. The items displayed are read from the following sources: * current recording directories * current timer directories * directories used in search timers * directories specified in F, see C * entries in VDR's folders.conf The menu merges theses directories and displays only distinct directories. With key 'yellow' one can change the depth of the directories shown. If there are items, that contain category variables like '%genre%', these entries are always shown before any other directories. They are also not level dependent, but are always shown with their full directory. If this menu is called from the timer edit menu and an item is selected that contains the variables "%title%" or "%subtitle" then the 'file' item of the timer gets cleared, since title or subtitle already exist in the 'directory' item. This list can also be accessed via the SVDRP command 'LSRD'. =head1 7. Language dependent commands for EPG If you like to have a language dependent list of commands simply translate your present F to your preferred OSD language and store it with the filename epgsearchcmds-XXX.conf, where XXX is the language code from i18n.c: { "eng,dos", "deu,ger", "slv", "ita", "dut,nla,nld", "por", "fra,fre", "nor", "fin,smi", "pol", "esl,spa", "ell,gre", "sve,swe", "rom,rum", "hun", "cat,cln", "rus", "hrv", "est", "dan", } If there are more codes for one language (e.g. "deu,ger") choose one of them. If there is no language dependent file, epgsearch loads the file F. See also C. =head1 8. Usage from other plugins or scripts Searching the EPG and other functionality can be used by other plugins or scripts. There are two approaches: =head2 8.1. File-based (intended for use in scripts) Therefore simply create the file '.epgsearchrc' in the plugins config directory with the following lines in it: Search=your search term Searchmode=x // 0=phrase, 1=and, 2=or, 3=regular expression ChannelNr=x // add this line, to search on a specific channel UseTitle=x // 1(default) or 0 UseSubtitle=x // 1(default) or 0 UseDescr=x // 1(default) or 0 Then call Epgsearch via svdrpsend (you must have assigned a key to it), e.g. svdrpsend HITK green At startup Epgsearch will look for this file and give you the search results for your search, if it exists. After that the file is removed. A sample script F, that searches for the repeats of a recording exists in the scripts subdirectory of Epgsearch. =head2 8.2. via Plugin-Interface (intended for use in plugins) A plugin can directly call two functions of epgsearch with only some lines of source code: - searching the EPG for some criteria and display the result list - extended timer edit menu I have added a quick and dirty dummy plugin (source/vdr-epgsearchclient-0.0.1.tgz), that demonstrates the usage. =head1 9. SVDRP interface epgsearch implements a SVDRP interface, that can be accessed for example like this svdrpsend PLUG epgsearch LSTS the following commands are available: =head2 search management: * 'LSTS [ID]' to list all searches, or the one with the passed ID (format is the same as epgsearch.conf) * 'NEWS ' to add a new search REMARK: the value of element ID is ignored. epgsearch will always assign the next free ID * 'DELS ' to delete the search with ID * 'EDIS ' to modify an existing search * 'UPDS [OSD]' to update the search timers. Passing the optional keyword 'OSD' pops up an OSD message after the update has finished. * 'MODS ID ON|OFF' turns on/off the option 'Use as search timer'. * 'UPDD' to reload the file epgsearchdone.data, e.g. after an external tool has modified it. * 'SETS ' to temporarily activate or cancel the search timer background thread. * 'FIND ' for searching the EPG input is the same as with 'NEWS'. output is a list of found events formatted as 'NEWT' lines. So they can be immediately used to create a new timer for an event. * 'QRYS < ID(s) >' to get the results for a search with the given ID. Multiple IDs can also be passed and have to be separated with '|'. The results are formatted like this: search ID : // the ID of the corresponding search timer event ID : // VDR event ID title : // event title, any ':' will be converted to '|' episode name : // event short text, any ':' will be converted to '|' event start : // event start in seconds since 1970-01-01 event stop : // event stop in seconds since 1970-01-01 channel : // channel ID in VDR's internal representation (e.g. 'S19.2E-1-1101-28106') timer start : // timer start in seconds since 1970-01-01 (only valid if timer flag is > 0) timer stop : // timer stop in seconds since 1970-01-01 (only valid if timer flag is > 0) timer file : // timer file (only valid if timer flag is > 0) timer flag : // 0 = no timer needed, 1 = has timer, 2 timer planned for next update) * 'QRYS ' to get the results for a search with the given search settings. * 'QRYF [hours]' to get the results for the favorites menu, see QRYS for result format. The optional parameter specifies the number of hours to evaluate and defaults to 24h. * 'MENU [PRG|NOW|SUM]' calls one of the main menus of epgsearch or the summary of the current event. * 'UPDT' reloads the search timers from epgsearch.conf =head2 channel group management: * 'LSTC [channel group name]' list all channel groups or if given the one with name 'group name' * 'NEWC ' create a new channel group, format as in epgsearchchangrps.conf * 'EDIC ' modify an existing channel group, format as in epgsearchchangrps.conf * 'DELC ' delete an existing channel group * 'RENC ' rename an existing channel group =head2 blacklist management: * 'LSTB [ID]' to list all blacklists, or the one with the passed ID (format is the same as epgsearchblacklists.conf) * 'NEWB ' to add a new blacklist REMARK: the value of element ID is ignored. epgsearch will always assign the next free ID * 'DELB ' to delete the blacklist with ID * 'EDIB ' to modify an existing blacklist =head2 search template management: * 'LSTT [ID]' to list all search templates, or the one with the passed ID (format is the same as epgsearch.conf) * 'NEWT ' to add a new search template REMARK: the value of element ID is ignored. epgsearch will always assign the next free ID * 'DELT ' to delete the search template with ID * 'EDIT ' to modify an existing search template * 'DEFT [ID]' returns the ID of the default search template. When passing an ID it activates the corresponding template as default. =head2 extended EPG categories: * 'LSTE [ID] to get the extended EPG categories defined in epgsearchcats.conf or the one with the given ID. (format is the same as epgsearchcats.conf) =head2 misc: * 'SETP [option]' returns the current value of the given setup option or a list of all options with their current values. The following options can be accessed: - ShowFavoritesMenu - UseSearchTimers =head2 timer conflicts: * 'LSCC [REL]' returns the current timer conflicts. With the option 'REL' only relevant conflicts are listed. The result list looks like this for example when we have 2 timer conflicts at one time: 1190232780:152|30|50#152#45:45|10|50#152#45 '1190232780' is the time of the conflict in seconds since 1970-01-01. It's followed by list of timers that have a conflict at this time: '152|30|50#152#45' is the description of the first conflicting timer. Here: '152' is VDR's timer id of this timer as returned from VDR's LSTT command '30' is the percentage of recording that would be done (0...100) '50#152#45' is the list of concurrent timers at this conflict '45|10|50#152#45' describes the next conflict =head1 10. Customizing the EPG menus The file F in your epgsearch config directory is used to store the entries for customizing the EPG menus. You specify the look of each menu (What's on now, What's on next, What's on at ..., Schedule, Search results, Favorites) with a separate line. Here's a sample: MenuWhatsOnNow=%chnr%:3|%progrt2s%:5| %time% %t_status%:8|%category%:6| %title% ~ %subtitle%:35 MenuWhatsOnNext=%chnr%:3|%time% %t_status%:8|%category%:8| %title% ~ %subtitle%:35 MenuWhatsOnElse=%chnr%:3|%time% %t_status%:8|%category%:8| %title% ~ %subtitle%:35 MenuSchedule=%time% %t_status%:8|%genre%:14| %title% ~ %subtitle%:35 MenuSearchResults=%chnr%:3|%datesh% %time% %t_status%:14|%genre%:8| %title%%colon% %subtitle%:35 MenuFavorites=%chnr%:3|%time%:6|%timespan%:7|%t_status%:14|%genre%:8| %title%%colon%%subtitle%:35 E.g. the entry 'MenuWhatsOnNow' tells epgsearch how you would like to build a line for the menu 'What's on now'. This would create a menu line starting with the channel number, followed by a progress bar in text2skin style, a space of one char, the start time, the timer status, the EPG category (like "movie") and finally the title and subtitle. The values for MenuWhatsOnNext, MenuWhatsOnElse, MenuSchedule, MenuSearchResults, MenuFavorites specify the menu 'What's on next', 'What's on at ...', 'Schedule', 'Search results' and 'Favorites' respectively. If you do not specify one entry, epgsearch uses its default menu look. 'MenuSearchResults' has something special: If you want to have different layouts for your search results depending on the search, you can use more then one menu template. Simply define e.g. an additional MenuSearchResultsTip of the Day=%chnr%:3|%time_w%:4|%t_status%:3|%genre%:10|%title%%colon% %subtitle%:35 This will produce an additional menu item "Result menu layout" in the edit menu of a search where you can choose between the default menu template and your own templates. In the example above you will get "Tip of the Day" as selection entry, since epgsearch simply cuts the leading "MenuSearchResults". When you display the search results the chosen template will be used instead of the default one. The following variables exist: %time% - start time in format HH:MM %timeend% - end time in format HH:MM %date% - start date in format DD.MM.YY %datesh% - start date in format DD.MM. %date_iso% - start date in format YYYY-MM-DD. %year% - year with century %month% - month (1-12) %day% - day (1-31) %week% - week number of the year (Monday as the first day of the week) as a decimal number [01,53] %time_w% - weekday name %time_d% - start day in format TT %time_lng% - start time in seconds since 1970-01-01 00:00 %timespan% - timespan from now to the beginning of an event, e.g. 'in 15m' or the time an event is already running, e.g. '10m'. %length% - length in seconds %title% - title %subtitle% - subtitle %summary% - summary %htmlsummary% - summary, where all CR are replaced with '
' %eventid% - numeric event ID %liveeventid% - encoded event ID as used in the frontend 'live' %t_status% - timer status ('T', 't', 'R') %v_status% - VPS status %r_status% - running status %status% - complete status, the same as '%t_status%%v_status%%r_status%' %% - a value from the extended EPG categories, specified in epgsearchcats.conf, like %genre% or %category% for the 'Whats on...' and 'Search results' menu there are also: %chnr% - channel number %chsh% - the short channel name %chlng% - the 'normal' channel name %chdata% - VDR's internal channel representation (e.g. 'S19.2E-1-1101-28106') %progr% - graphical progress bar (not for menu 'Search results'), requires VDRSymbols font %progrT2S% - progress bar in text2skin style (not for menu 'Search results') some independent variables: %colon% - the sign ':' %datenow% - current date in format DD.MM.YY %dateshnow% - current date in format DD.MM. %date_iso_now% - current date in format YYYY-MM-DD %timenow% - current time in format HH:MM %videodir% - VDR video directory (e.g. /video) %plugconfdir% - VDR plugin config directory (e.g. /etc/vdr/plugins) %epgsearchdir% - epgsearch config directory (e.g. /etc/vdr/plugins/epgsearch) The variables are not case sensitive. You can also use variables for extended EPG categories defined in F or use your own user defined variables defined in F An entry consists of up to 6 tables separated with '|'. The last entry of each table should declare the table width in chars, separated with ':'. If you use a separator like '~', '-' or '#' to separate items like title or subtitle, e.g. %title% ~ %subtitle%, and the subtitle is empty, then epgsearch will try to fix this automatically to avoid a trailing separator. You should vary the tab width values to fit your needs, since the look often depends on the selected skin. epgsearchmenu.conf is not reloaded with every plugin call, since this is only useful when testing the conf file. To activate the permanent reload for testing your conf, pass the new start parameter '-r' or '--reloadmenuconf' in your runvdr. There's a sample F in the subdirectory "conf". For a quick try copy it to your epgsearch config directory (e.g. /etc/vdr/plugins/epgsearch). To enable icons from the VDRSymbols font simply put the line WarEagleIcons=1 to F. The VDRSymbols font is available at http://andreas.vdr-developer.org/fonts/download.html NOTE: As long as there is a file epgsearchmenu.conf with an entry for a special menu, all setup settings regarding the look of this menu are ignored. See also C. =head1 11. Working with the timer conflict menu If a conflict is detected within the periodic conflict background check you get an OSD message which informs you about it. Pressing 'Ok' you will get a menu that displays all relevant conflicts. You can manually call this menu in epgsearch in the menu 'Search/Actions'. Besides the relevant conflicts (relevance is controlled via the setup options of epgsearch) there may also be conflicts which are not classified as important. If so, you can press 'Show all' to get the complete list. The menu title always displays the number of relevant conflicts and the total number. The list displays first the time when a conflict appears and then all timers that will fail here. A timer entry consists of the channel number and its name followed by the timer priority and the percentage value that shows how much of the timer will be recorded. Finally the timer's file entry is displayed. When you select a timer entry and press 'Ok' or 'Details' you get a new menu which displays all concurrent timers. This menu allows you to resolve the conflict by - searching a repeat for an event - disabling a timer - deleting a timer - changing the timers start- or stop-time or its priority - executing any other commands on this timer An entry of this menu consists of the sign '>' to indicate an active timer, the channel number, the start and stop time, the priority, the number of the device that will do the recording (or 'C' for conflict) and the timer's file entry. Pressing 'Ok' on a timer entry will show you its event description if present. If one returns from this menu to the conflict overview menu there will be an automatic update to see if a conflict was really resolved. Some changes to a timer (like modifying start/stop or deleting a timer) in the conflict details menu also cause an immediate return to the overview menu and produce an update. Note: There's a 'hidden' setup option epgsearch.ConflCheckCmd, that allows executing a command for each timer causing a conflict. You have to set this directly in VDRs setup.conf like this: epgsearch.ConflCheckCmd = system(your_script_handling_the_conflict.sh, any_arguments like %timer.file%) (Please have a look at 'Calling a system command' below for the possible arguments) One could use this for example to forward a timer to another VDR machine in case of a conflict. This command is evaluated for each timer causing a conflict whenever an automatic conflict check is running. When calling the conflict check via OSD the command is not evaluated. =head1 12. User defined variables You can create your own variables to be used in any place that supports variables, like the default recording directory for manually created timers, the recording directory of a search timer or in your customized EPG menus. Put them in the file F. Variables looks like %Variablename%. "Variablename" can be consist of any alphanumerical character. Space and special characters are not allowed. The variable names are case-insensitive. Examples for possible names: %Series% %DocuVar1% %ThemesSubtitleDate1% =head2 Assignment %Series%=New series~Thriller The variable %Series% will be assigned with the string "New series~Thriller". Assignments are always strings. Spaces stay spaces. %Path%=%Series% The variable %Path% gets the content of the variable %Series%. You can do nearly everything: %Path%=%Serie%~Lost The variable %Path% contains now the string "New series~Thriller~Lost". =head2 Control structures You can use simple "if then else" constructions. These constructions cannot contain strings, only variables. Spaces are ignored. %Foo%=Other %Variable%=%Path% ? %Path% : %Foo% If %Path% is not empty, assign the content of %Path% to %Variable%, otherwise the content of %Foo%. "%Path% ?" means "not empty?". You can use other checks. %Variable%=%Path%!=5 ? %Path% : %Foo% "%Path%!=5 ?" means "is %Path% equal 5?" You can also compare variables. %Five%=5 %Variable%=%Path%!=%Five% ? %Path% : %Foo% Other possible checks: == equal != not equal =head2 Calling a system command You can call external commands. The returned string will be assigned to a variable %uservar%=system(scriptname[, parameters]) Calls the script "scriptname" with the parameters defined in the optional list of 'parameters'. This can be an arbitrary expression containing other user variables, but not again a system call or a conditional expression. Sample: %myVar%=system(/usr/local/bin/myscript.sh, -t %title% -s %subtitle% -u %myOtherVar%) The script must return a string B line break! If the script returns nothing, an empty string will be assigned to the Variable %Result%. =head2 Calling a TCP service You can call a TCP service with the following syntax: %uservar%=connect(, , []) This will connect to through the given port and pass the optional given data. can be an IP address or the domain name of the TCP service. The result returned by the service must be terminated with a line feed. =head2 Get the length of an argument When passing any values to the connect or system command it can be helpful to have the length of an argument for simple parsing. This can be done with %uservar%=length() Sample: %length_title%=length(%title%) =head2 Possible variables for a list of already builtin variables refer to the section "Customizing the EPG menus" Furthermore you can use every variable defined in F. See C. =head2 EXAMPLES # Weekday, Date, Time %DateStr%=%time_w% %date% %time% # Themes or Subtitle or Date %ThemesSubtitleDate1%=%Subtitle% ? %Subtitle% : %DateStr% %ThemesSubtitleDate%=%Themes% ? %Themes% : %ThemesSubtitleDate1% # Calls this script to get a recording path %DocuScript%=system(doku.pl, -t %Title% -s %Subtitle% -e %Episode% -th %Themes% -c %Category% -g %Genre%) %Docu%=%DocuScript% =head1 13. Email notification If you want to get email notifications about timers added/modified/removed by the search timer thread or about timer conflicts, first copy the script 'sendEmail.pl' to the place where your executables are (e.g. /usr/local/bin) and then configure your email account in the setup. Press 'Test' to check if it works. There should be something like 'Email successfully sent' at the end of the output. The content of the mails is defined by the files - epgsearchupdmail.templ (for search timer update notifications) - epgsearchconflmail.templ (for timer conflict notifications) You can find sample files in the 'conf' directory. Copy them to the epgsearch config directory (e.g. /etc/vdr/plugins/epgsearch). =head2 Customizing the notifications mails The content of the mails can be customized in many ways. You can use plain text or HTML (see the sample conf/epgsearchupdmail-html.templ). For an update mail you have to define the following sections: - "subject" to be used as mail subject - "mailbody" the body of the mail: put %update.newtimers% in the place where the list of new timers should appear. The same for %update.modtimers%, %update.deltimers% and %update.newevents% for the list of changed or deleted timers and event announcements. - "timer" the description of one timer and "event" with the description of one event. This section is used to display one timer within a timer list, e.g. in %update.newtimers%. The same for "event". All sections are optional, e.g. if you don't use event announcements you can drop "%update.newevents%" in the mailbody and the "event" section. But of course you should have at least a mailbody ;-) Each section is enclosed in a pseudo XML tag. The following variables can be used in the section : - %update.newtimers% - will be replaced with the list of new timers created with this update. The timers are displayed as defined in the section '' - %update.countnewtimers% - the number of new timers - %update.modtimers% - same as %update.newtimers% but for modified timers. - %update.countmodtimers% - the number of modified timers - %update.deltimers% - same as %update.newtimers% but for deleted timers. (Note: a deleted timer has eventually no event assigned to it. So all event variables within the timer section will be substituted to an empty string.) - %update.countdeltimers% - the number of deleted timers - %update.newevents% - will be replaced with the list of events to announce. These events are the search result of search timers with the action "announce by mail". The events are displayed as defined in the section '' - %update.countnewevents% - the number of new events - %colon% - the sign ':' - %datenow% - current date in format TT.MM.YY - %dateshnow% - current date in format TT.MM. - %timenow% - current time in format HH:MM The following variables can be used in the section : - %timer.date% - date of the timer - %timer.start% - start time of the timer - %timer.stop% - stop time of the timer - %timer.file% - recording directory of the timer - %timer.chnr% - channel number - %timer.chsh% - short channel name - %timer.chlng% - channel name - %timer.search% - name of the search timer, that created the timer - %timer.searchid% - id of the search timer, that created the timer - %timer.modreason% - the reason for a timer modification in plain text - %timer.liveid% - encoded timer ID as used in the frontend 'live' - any event variable (as in '10. Customizing the EPG menus') - any extended EPG variable as defined in epgsearchcats.conf - any user variable (as in '12. User defined variables') The following variables can be used in the section : - any event variable (as in '10. Customizing the EPG menus') - %search% - the name of the search timer that triggered this event - %searchid% - the ID of the corresponding search timer - any extended EPG variable as defined in epgsearchcats.conf - any user variable (as in '12. User defined variables') For a conflict notification mail the following sections exist: - "subject" to be used as mail subject - "mailbody" the body of the mail. Put %conflict.conflicts% in the place where the list of conflict times should appear (Note: there can be more than one timer conflict at the same time!). A conflict time uses the section 'conflictsat' to display its content. - "conflictsat" the description of one time where one or more conflicts exists. Put %conflict.confltimers% in the place where the list of conflict timers should appear. - "confltimer" the description of one conflicting timer The following variables can be used in the section : - %conflict.count% - complete number of timer conflicts - %conflict.conflicts% - list of times with conflicting timers The following variables can be used in the section : - %conflict.date% - date of the conflict - %conflict.time% - time of the conflict - %conflict.confltimers% - list of conflicting timers for this time The section can use the same variables as the section in an update mail (see above). =head1 14. The conf.d subdirectory epgsearch supports a configuration mechanism well-known in linux. The settings of the configuration files - epgsearchuservars.conf - epgsearchdirs.conf - epgsearchmenu.conf - epgsearchcats.conf can also be given in a file with arbitrary name in the subdirectory conf.d in /epgsearch. This allows one to quickly test different setups only by exchanging files instead of editing them. The format of these files is [
] ... [
] ... where is one of the following: - epgsearchuservars - epgsearchdirs - epgsearchmenu - epgsearchcats The format follows the one in the corresponding configuration file. Comments beginning with # are allowed, also blank lines. At startup epgsearch first reads its 'regular' configuration files and then the conf.d subdirectory. It's allowed to overwrite variables already defined in other files (although this is signaled with a warning in epgsearch's log file.). =head1 SEE ALSO C, C, C, C, C, C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bug reports (german): L Mailing list: L =head1 COPYRIGHT and LICENSE Copyright (C) 2004-2010 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/noannounce.conf.5.txt0000644000175000017500000000406512100027260021423 0ustar winniwinni=head1 NAME F - list of events that have been marked to not be announced via OSD =head1 DESCRIPTION This file contains a list of events that have been marked to not be announced via OSD by the search timer background thread. If the user presses one of the keys 'Ok', '0', ... '9' while the announcement of an event is displayed, he will be asked if further announcements of this event should be disabled for ever (user hit '0' or 'Ok') or for the next 'x' days (user hit '1' to '9'). After pressing 'Ok' again, this setting will be stored. =head1 FORMAT Events are stored one per line, where the fields are separated with ':'. The following fields exists: 1 - title 2 - short text 3 - channel ID 4 - start time 5 - next announce time =head1 SEE ALSO C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bug reports (german): L Mailing list: L =head1 COPYRIGHT and LICENSE Copyright (C) 2004-2010 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/epgsearchuservars.conf.5.txt0000644000175000017500000001203412100027260023007 0ustar winniwinni=head1 NAME F - User defined variables =head1 DESCRIPTION In this file you can defines variables which then can be used in epgsearch in any play where variables are possible. =head1 SYNTAX Variables looks like %Variablename%. "Variablename" can be consist of any alphanumerical character. Space and special characters are not allowed. The variable names are case-insensitive. Examples for possible names: %Series% %DocuVar1% %ThemesSubtitleDate1% =head2 Assignment %Series%=New series~Thriller The variable %Series% will be assigned with the string "New series~Thriller". Assignments are always strings. Spaces stay spaces. %Path%=%Series% The variable %Path% gets the content of the variable %Series%. You can do nearly everything: %Path%=%Serie%~Lost The variable %Path% contains now the string "New series~Thriller~Lost". =head2 Control structures You can use simple "if then else" constructions. These constructions cannot contain strings, only variables. Spaces are ignored. %Foo%=Other %Variable%=%Path% ? %Path% : %Foo% If %Path% is not empty, assign the content of %Path% to %Variable%, otherwise the content of %Foo%. "%Path% ?" means "not empty?". You can use other checks. %Variable%=%Path%!=5 ? %Path% : %Foo% "%Path%!=5 ?" means "is %Path% equal 5?" You can also compare variables. %Five%=5 %Variable%=%Path%!=%Five% ? %Path% : %Foo% Other possible checks: == equal != not equal =head2 Calling a system command You can call external commands. The returned string will be assigned to a variable %Result%=system(scriptname,%Variable1% %Variable2% -f %Variable3% --dir=%Variable4% --dummy) Calls the script "scriptname" with the parameters "%Variable1%", "%Variable2%", etc. The result will be stored in %Result%. You can use as many variables as you want. If needed, epgsearch will quote the variable. The script must return a string B line break! If the script returns nothing, an empty string will be assigned to the Variable %Result%. =head2 Possible variables The following variables exist: %time% - start time in format HH:MM %timeend% - end time in format HH:MM %date% - start date in format TT.MM.YY %datesh% - start date in format TT.MM. %time_w% - weekday name %time_d% - start day in format TT %time_lng% - start time in seconds since 1970-01-01 00:00 %title% - title %subtitle% - subtitle %summary% - summary %htmlsummary% - summary, where all CR are replaced with '
' %eventid% - numeric event ID %% - a value from the extended EPG categories, specified in F, like %genre% or %category% %chnr% - channel number %chsh% - the short channel name %chlng% - the 'normal' channel name %chdata% - VDR's internal channel representation (e.g. 'S19.2E-1-1101-28106') %colon% - the sign ':' %datenow% - current date in format TT.MM.YY %dateshnow% - current date in format TT.MM. %timenow% - current time in format HH:MM %videodir% - VDR video directory (e.g. /video) %plugconfdir% - VDR plugin config directory (e.g. /etc/vdr/plugins) %epgsearchdir% - epgsearch config directory (e.g. /etc/vdr/plugins/epgsearch) See also C. =head1 EXAMPLES # Weekday, Date, Time %DateStr%=%time_w% %date% %time% # Themes or Subtitle or Date %ThemesSubtitleDate1%=%Subtitle% ? %Subtitle% : %DateStr% %ThemesSubtitleDate%=%Themes% ? %Themes% : %ThemesSubtitleDate1% # Calls this script to get a recording path %DocuScript%=system(doku.pl,%Title%,%Subtitle%,%Episode%,%Themes%,%Category%,%Genre%) %Docu%=%DocuScript% =head1 SEE ALSO C, C =head1 AUTHOR (man pages) Mike Constabel =head1 REPORT BUGS Bug reports (german): L Mailing list: L =head1 COPYRIGHT and LICENSE Copyright (C) 2004-2010 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch The MD5 code is derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. epgsearch-1.0.1.beta3/doc-src/en/epgsearch.1.txt0000644000175000017500000011503212112103675020276 0ustar winniwinni=head1 NAME F - Searchtimer and replacement of the VDR program menu =head1 OVERVIEW EPG-Search can be used as a replacement for the default schedules menu entry. It looks like the standard schedules menu, but adds some additional functions: - Commands for EPG entries with 5 built-in commands like 'show repeats', 'create search'. One can add own commands for other needs, like adding a VDRAdmin auto-timer. - Add up to 4 user-defined times to 'now' and 'next' and an optional favorites menu - Searching the EPG: Create reusable queries, which can also be used as 'search timers'. - Search timers: Search for broadcasts in the background and add a timer if one matches (similar to VDRAdmin's auto-timers) or simply make an announcement about it via OSD - Avoid double recordings of the same event * timer preview * recognition of broken recordings * fuzzy event comparison - Progress bar in 'What's on now' and 'What's on next' - Shift the time displayed by key press, e.g. 'What's on now' + 30 minutes - Start menu can be setup between 'Schedule' or 'What's on now' - background check for timer conflicts with a timer conflict manager - detailed EPG menu (summary) allows jumping to the next/previous event - support for extended EPG info for search timers - extension of the timer edit menu with a directory item, user defined weekday selection and a subtitle completion. - Timer conflict check, informs you over the OSD about conflicts - Timer conflict menu, show detailed information about the conflicts and let you resolve them - Email notifications about search timer updates and timer conflicts Parts of the sources are based on the repeating-ECG patch from Gerhard Steiner, who gave me the permission to use them. Thanks for his work! =head1 OPTIONS =over 4 =item -f file, --svdrpsendcmd=file the path to svdrpsend for external SVDRP communication (default is internal communication, so this is usually not needed anymore) =item -c path, --config=path to specify a specific config directory for all epgsearch config files, default is '/epgsearch' =item -l file, --logfile=file to specify a specific log file for epgsearch (default log file is epgsearch.log in the epgsearch config directory) =item -v n, --verbose=n verbose level for log file. Value 0 means no logging. Other values are 1 (general messages), 2 (detailed messages), 3 (planned for extra detailed info for debugging purposes) =item -r, --reloadmenuconf reload epgsearchmenu.conf with plugin call. This can be useful when testing customized menu layouts. =item -m file, --mailcmd=file the external command to be used for mail delivery. The default uses 'sendEmail.pl'. If you are using a different command or script make sure that it has the same parameter interface as sendEmail.pl. =back =head1 CONTENT 1. Description 1.1 Menu commands 1.2 Menu search 1.2.1 Menu edit search 1.2.2 Menu search results 1.3 Extended 'now' and 'next' 1.4 Menu setup 2. Search timers 2.1 'Avoid repeats' - internals 2.2 How do we compare two events? 2.3 How and when do we compare? 3. Usage from other plugins or scripts 4. Using extended EPG info 5. Replacing the standard schedule menu 6. Add-ons =head1 1. Description At first glance EPG-Search looks like the schedules menu entry of VDR. By pressing the key '0', one can toggle the bottom color keys to access additional functions (the default assignment of the color keys can be adjusted by setup): =head2 1.1 Menu Commands This menu displays commands that can be executed on the current item. There are 8 built-in commands: - Repeats: Searches for repeats - Record - Switch - Create search Switches to search menu and adds a new search with the name of the current item (to avoid editing the name manually) - Search in recordings: Search the recordings for a broadcast with the same name - Mark as 'already recorded': This puts the selected event in the file epgsearchdone.data and instructs epgsearch to avoid recording this event if an according search timer is set to "avoid repeats". An already created timer will be automatically removed with the next search timer update. - Add/Remove to/from switch list?: Controls the switch list. If there is an event in the switch list, epgsearch will announce it and switch to the event before it starts. To access the complete switch list, call 'Search/Actions/Switch list'. - Create blacklist: A blacklist is used to ignore events when using search timers. A search timer can be setup to ignore events from arbitrary blacklists. You can add your own commands to this menu by editing the file epgsearchcmds.conf in the epgsearch config directory. There's a sample conf file with some sample commands (see directory 'scripts', taken from vdr-wiki.de, thanks to the authors). The format of the file is the same as VDR's commands.conf or reccmds.conf. When a command is executed the following parameters are passed to it: $1: the title of the EPG entry $2: the start time of the EPG entry as time_t value (like in the shutdown script) $3: the end time $4: the channel number of the EPG entry $5: the long channel name of the EPG entry $6: the subtitle of the EPG entry, "" if not present To execute a command from the main menu you can also press its associated number without opening the commands menu. =head2 1.2 Menu search Here you can add, edit, delete and execute your own queries on the EPG. The usage and behavior of this menu is similar to VDR's timer menu. =head3 1.2.1 Menu edit search Most things in this menu are quite clear, so only some notes on: =over 4 =item - B The term to search for. If you like to search for more words, separate them by blanks. Leaving this empty (combined with search mode 'Phrase') will match anything. This is useful, if you search e.g. for anything that starts between some times on a specific channel. With 'blue' you can also select a template for the new search. If one of the templates is set to default, new searches will automatically get the settings of the default template. Note: fuzzy searching is limited to 32 chars! =item - B 'Phrase' searches for the expression within the EPG. 'All words' requires, that each word of the expression occurs in the EPG item. 'at least one word' requires, that only one word occurs in the EPG item. 'Match exactly' requires, that your search term matches exactly the found title, subtitle or description. With 'Regular expression' you can setup a regular expression as search term. You don't need a leading and trailing '/' in the expression. By default these are POSIX extended regular expressions. If you like to have Herl compatible regular expression, simply edit the plugins Makefile and uncomment '#REGEXLIB = pcre' to 'REGEXLIB = pcre' (you will need pcreposix installed, comes with libpcre from www.pcre.org, but it's already part of most distributions). See also C 'Description of the search process'. =item - B Some providers deliver content descriptors in their EPG, like "Movie/Drama", "Documentation",...(available with vdr-1.7.11) Select here the descriptors to search for. Multiple choice is possible, that must match with all given descriptors (AND operator). =item - B Only available if configured, see below 'Using extended EPG info'. =item - B If set to 'Yes' this tells epgsearch that a missing EPG category should not exclude an event from the results. Caution: Using this without any other criterions could flood your timers. =item - B Search only for events in the given channels interval, channel groups or FTA channels only. Channel groups (e.g. sport channels or Pay-TV channels) can be managed with a sub-menu called with 'blue'. ATTENTION: After changing the channels order please check the settings of your search timers! =item - B Besides the weekdays you can also set up a user-defined selection, e.g. search only on Monday and Friday. You'll find the user-defined selection in the list after Friday. =item - B Blacklists are a way to exclude unwanted events. Select only global, one, more or all blacklists here. If any search result is also contained in one of the selected blacklists it will be skipped. =item - B Only available if turned on in setup. With this option you can mark a search to be used in the favorites menu. The search results of all these searches are listed in the favorites menu. =item - B Only available if you have defined more than one menu template for search results in epgsearchmenu.conf. This option is used to assign a different menu layout for the search results of this search. =item - B If set to yes, the plugin will do a background scan of the EPG in certain intervals and add a timer, if there is a match. You have to activate the 'search timers' in the setup. If set to "user defined" one can specify time margins with key 'blue' where the search timer is active or not. =item - B Default action is creating a timer for the search results. But you can also choose to simply announce the found event via OSD as soon as it is found or to automatically switch to the event before it starts. It's also possible to get an announcement via OSD before the event starts and to switch to its channel with 'Ok'. =item - B If set to yes, the recordings will be stored in a folder with the name of the broadcasting and the recordings itself will have the name of the episode. If there is no episode name, the date and time of the recording will be used. =item - B Here you can assign a directory, where the recording should be stored, e.g. 'SciFi'. Use the key 'blue' to select directory entries already used in other search entries or given by entries in the file epgsearchdirs.conf (simply place your directories here one at each line without the leading video directory, also see MANUAL). If your provider delivers extended EPG infos you can also use variables like "%Genre%" or "%Category%" in your directory entry. These are replaced with the current EPG info, when a timer is created. See also C 'Using variables in the directory entry of a search timer'. =item - B Some recordings should only be kept for a few days, like news. With this feature you can tell epgsearch to delete them automatically after ... days. =item - B If the given numbers of recordings currently exists, then epgsearch will not create further timers. After deleting one or more recordings it will go on generating new timers. =item - B If you don't want to record repeats, this feature tries to check if an event was already recorded/programmed and skips it. Please refer to the section 'Avoid repeats - internals' below before using it. =item - B If you like to accept a certain amount of repeats you can give here their number. =item - B Give here the number of days a repeat has to follow its first broadcast. 0 is equal to no restriction. =item - B When comparing to events then specify here if the title should be compared. =item - B When comparing to events then specify here if the subtitle should be compared. With 'if present' epgsearch will classify two events only as equal if their episode names match and are not empty. =item - B When comparing to events then specify here if the description should be compared. For comparison all parts of the description, that look like a category value, are removed first. The remaining text will be compared. If this is similar at the value of the next option (regarding the Levinshtein-Distance algorithm) then it will be accepted as equal. =item - C The needed minimum match of descriptions in percent. =item - B Sometimes an event is repeated many times within some period (day, week, month,...), but one cannot distinguish the repeats based on the EPG contents. So the only information is its time. To use this for comparison select the appropriate period. =item - B With the button 'setup' you can also specify which categories should be compared. As with subtitles an event is different if it has no according category value. =item - B Each search timer can have its own settings for these parameters. Defaults can be adjusted in the plugins setup. =item - B If set to yes, VPS is used, but only, if activated in VDR's setup menu and if the broadcasting has VPS information. =item - B to automatically delete a search timer if the following is true: * after x recordings, or * after x days after the first recording Only complete recordings are counted. The deletion is executed directly after the correspondig recording =back To toggle the flag 'Use as search timer' without editing the search entry you can use the key '2'. This will call directly the second command of the command menu. =head3 1.2.2 Menu search results This menu displays the search results. A 'T' lets you know, that there is already a timer for the event. A 't' means that there's only a partial timer for it, as in standard schedules menu. =head2 1.3 Extended 'now' and 'next' and favorites By setup, one can add up to 4 additional times to extend the green button, e.g. 'afternoon', 'prime time', 'late night'. Times, that are already passed, are skipped (you will not get 'afternoon' at evening) with the exception that a time will be displayed for the next day, if it is less then 20h in the future. In these menus you can shift the currently displayed time by pressing FastRew or FastFwd to move back and forward in time. If you don't have these keys on your remote, you can access this function by pressing '0' to toggle the green and yellow button to '<<' and '>>'. This toggling can be adjusted by setup. You can display a progress bar in 'now' and 'next'. Furthermore you can enable in the setup an favorites list. You can configure your searchtimers ("Use in favorite list") to display their results in you favorite list. This list display event in the next 24 hours ordered by time. =head2 1.4 Menu setup =head3 1.4.1 General =over 4 =item - B This hides the main menu entry 'search'. Attention: when the plugin is assigned to key 'green' then hiding the plugin will give you VDR's standard schedule menu (see below to avoid this). =item - B
If not hidden, the name of main menu entry can be set here. Default is 'Program guide'. Note: If you set it to something different from the default then the main menu entry is no longer dependent on the OSD language. Setting it back to default or empty restores this behavior again. =item - B Select the starting menu 'Schedules' or 'Now' =back =head3 1.4.2 EPG menus =over 4 =item - B Choose here the behavior of key 'Ok'. You can use it to display the summary or to switch to the corresponding channel. Note: the functionality of key 'blue' (Switch/Info/Search) depends on this setting. =item - B Select if you like to have Standard ('Record') or 'Commands' as assignment for key 'red'. =item - B select if you like to have Standard ('Switch') or 'Search' as assignment for key 'blue'. =item - B In the menu 'what's on now' you can display a progress bar, that displays the progress of the current item. =item - B Select this if you like to have a leading channel number before each item in the EPG menus. =item - B Display channel group separators between channel in the menus 'Overview now',... =item - B Display a day separator between events on different days in the schedule menu. =item - B Also list radio channels. =item - B If you have a large channel set you can speed up things when you limit the displayed channels with this setting. Use '0' to disable the limit. If the current channel is above the limit, the limit is ignored and all channels will be displayed again. =item - B<'One press' timer creation:> If set to 'yes' a timer is immediately created when pressing 'Record', else the timer edit menu is displayed. =item - B Display channels without EPG to allow switching or create a timer. =item - B