#include #include #include #include #include #include #include "tools.h" #include "searchtimer.h" // -- cTVGuideSearchTimer ----------------------------------------------------------------- cTVGuideSearchTimer::cTVGuideSearchTimer(void) { strTimer = ""; ID = -1; searchString = ""; useTime = false; startTime = 0000; stopTime = 2359; useChannel = false; #if VDRVERSNUM >= 20301 { LOCK_CHANNELS_READ; channelMin = Channels->GetByNumber(cDevice::CurrentChannel()); channelMax = Channels->GetByNumber(cDevice::CurrentChannel()); } #else channelMin = Channels.GetByNumber(cDevice::CurrentChannel()); channelMax = Channels.GetByNumber(cDevice::CurrentChannel()); #endif channelGroup = ""; useCase = false; mode = 0; useTitle = true; useSubtitle = true; useDescription = true; useDuration = false; minDuration = 0; maxDuration = 2359; useAsSearchTimer = true; useDayOfWeek = false; dayOfWeek = 0; directory = ""; useEpisode = 0; priority = 50; lifetime = 99; marginStart = 5; marginStop = 5; useVPS = false; action = 0; useExtEPGInfo = 0; extEPGInfoValues = ""; avoidRepeats = 1; compareTitle = 1; compareSubtitle = 1; compareSummary = 1; compareSummaryMatchInPercent = 90; compareDate = 0; allowedRepeats = 1; catvaluesAvoidRepeat = 0; repeatsWithinDays = 0; delAfterDays = 0; recordingsKeep = 0; switchMinsBefore = 1; pauseOnNrRecordings = 0; blacklistMode = 0; blacklists = ""; fuzzyTolerance = 1; useInFavorites = 0; menuTemplate = 0; delMode = 0; delAfterCountRecs = 0; delAfterDaysOfFirstRec = 0; useAsSearchTimerFrom = 0; useAsSearchTimerTil = 0; ignoreMissingEPGCats = 0; unmuteSoundOnSwitch = 0; contentsFilter = ""; } cTVGuideSearchTimer::~cTVGuideSearchTimer(void) { } bool cTVGuideSearchTimer::operator < (const cTVGuideSearchTimer& other) const { std::string searchStringOther = other.GetSearchString(); searchStringOther = StrToLowerCase(searchStringOther); std::string thisSearchString = StrToLowerCase(searchString); int comp = thisSearchString.compare(searchStringOther); if (comp < 0) return true; return false; } void cTVGuideSearchTimer::SetTemplate(std::string tmpl) { std::stringstream searchTimerString; searchTimerString << "0:"; searchTimerString << tmpl; strTimer = searchTimerString.str(); } int cTVGuideSearchTimer::DayOfWeek(void) { int vdrDayOfWeek = 0; if (dayOfWeek >= 0) { vdrDayOfWeek = pow(2, (dayOfWeek+6)%7); } else if (dayOfWeek < 0) { int absDayOfWeek = abs(dayOfWeek); for (int i=0; i < 7; i++) { if (absDayOfWeek & (1 << i)) { vdrDayOfWeek += pow(2, (i+6)%7); } } } return vdrDayOfWeek; } void cTVGuideSearchTimer::SetDayOfWeek(int VDRDayOfWeek) { int epgSearchDayOfWeek = 0; for (int i=0; i < 7; i++) { if (VDRDayOfWeek & (1 << i)) { epgSearchDayOfWeek += pow(2, (i+1)%7); } } this->dayOfWeek = epgSearchDayOfWeek * (-1); } /* 0 - unique search timer id 1 - the search term 2 - use time? 0/1 3 - start time in HHMM 4 - stop time in HHMM 5 - use channel? 0 = no, 1 = Interval, 2 = Channel group, 3 = FTA only 6 - 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 7 - match case? 0/1 8 - 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 9 - use title? 0/1 10 - use subtitle? 0/1 11 - use description? 0/1 12 - use duration? 0/1 13 - min duration in hhmm 14 - max duration in hhmm 15 - use as search timer? 0/1 16 - use day of week? 0/1 17 - day of week (0 = Sunday, 1 = Monday...; -1 Sunday, -2 Monday, -4 Tuesday, ...; -7 Sun, Mon, Tue) 18 - use series recording? 0/1 19 - directory for recording 20 - priority of recording 21 - lifetime of recording 22 - time margin for start in minutes 23 - time margin for stop in minutes 24 - use VPS? 0/1 25 - 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 26 - use extended EPG info? 0/1 27 - 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") 28 - avoid repeats? 0/1 29 - allowed repeats 30 - compare title when testing for a repeat? 0/1 31 - compare subtitle when testing for a repeat? 0/1/2 0 - no 1 - yes 2 - yes, if present 32 - compare description when testing for a repeat? 0/1 33 - compare extended EPG info when testing for a repeat? This entry is a bit field of the category IDs. 34 - accepts repeats only within x days 35 - delete a recording automatically after x days 36 - but keep this number of recordings anyway 37 - minutes before switch (if action = 2) 38 - pause if x recordings already exist 39 - blacklist usage mode (0 none, 1 selection, 2 all) 40 - selected blacklist IDs separated with '|' 41 - fuzzy tolerance value for fuzzy searching 42 - use this search in favorites menu (0 no, 1 yes) 43 - id of a menu search template 44 - auto deletion mode (0 don't delete search timer, 1 delete after given count of recordings, 2 delete after given days after first recording) 45 - count of recordings after which to delete the search timer 46 - count of days after the first recording after which to delete the search timer 47 - first day where the search timer is active (see parameter 16) 48 - last day where the search timer is active (see parameter 16) 49 - ignore missing EPG categories? 0/1 50 - unmute sound if off when used as switch timer 51 - percentage of match when comparing the summary of two events (with 'avoid repeats') 52 - HEX representation of the content descriptors, each descriptor ID is represented with 2 chars 53 - compare date when testing for a repeat? (0=no, 1=same day, 2=same week, 3=same month) */ bool cTVGuideSearchTimer::Parse(bool readTemplate) { splitstring s(strTimer.c_str()); std::vector values = s.split(':', 1); int numValues = values.size(); if (numValues < 12) return false; for (int value = 0; value < numValues; value++) { switch (value) { case 0: if (!readTemplate) ID = atoi(values[value].c_str()); break; case 1: if (!readTemplate) { std::string searchStringMasked = values[value]; std::replace(searchStringMasked.begin(), searchStringMasked.end(), '|', ':'); searchString = searchStringMasked; } break; case 2: useTime = atoi(values[value].c_str()); break; case 3: if (useTime) { startTime = atoi(values[value].c_str()); } break; case 4: if (useTime) { stopTime = atoi(values[value].c_str()); } break; case 5: useChannel = atoi(values[value].c_str()); break; case 6: if (useChannel == 0) { channelMin = NULL; channelMax = NULL; } else if (useChannel == 1) { int minNum = 0, maxNum = 0; int fields = sscanf(values[value].c_str(), "%d-%d", &minNum, &maxNum); if (fields == 0) { // stored with ID char *channelMinbuffer = NULL; char *channelMaxbuffer = NULL; int channels = sscanf(values[value].c_str(), "%m[^|]|%m[^|]", &channelMinbuffer, &channelMaxbuffer); #if VDRVERSNUM >= 20301 LOCK_CHANNELS_READ; channelMin = Channels->GetByChannelID(tChannelID::FromString(channelMinbuffer), true, true); #else channelMin = Channels.GetByChannelID(tChannelID::FromString(channelMinbuffer), true, true); #endif if (!channelMin) { esyslog("ERROR: channel '%s' not defined", channelMinbuffer); channelMin = channelMax = NULL; useChannel = 0; } if (channels == 1) channelMax = channelMin; else { #if VDRVERSNUM >= 20301 channelMax = Channels->GetByChannelID(tChannelID::FromString(channelMaxbuffer), true, true); #else channelMax = Channels.GetByChannelID(tChannelID::FromString(channelMaxbuffer), true, true); #endif if (!channelMax) { esyslog("ERROR: channel '%s' not defined", channelMaxbuffer); channelMin = channelMax = NULL; useChannel = 0; } } free(channelMinbuffer); free(channelMaxbuffer); } } else if (useChannel == 2) channelGroup = values[value]; break; case 7: useCase = atoi(values[value].c_str()); break; case 8: mode = atoi(values[value].c_str()); break; case 9: useTitle = atoi(values[value].c_str()); break; case 10: useSubtitle = atoi(values[value].c_str()); break; case 11: useDescription = atoi(values[value].c_str()); break; case 12: useDuration = atoi(values[value].c_str()); break; case 13: minDuration = atoi(values[value].c_str()); break; case 14: maxDuration = atoi(values[value].c_str()); break; case 15: useAsSearchTimer = atoi(values[value].c_str()); break; case 16: useDayOfWeek = atoi(values[value].c_str()); break; case 17: dayOfWeek = atoi(values[value].c_str()); break; case 18: useEpisode = atoi(values[value].c_str()); break; case 19: directory = values[value]; break; case 20: priority = atoi(values[value].c_str()); break; case 21: lifetime = atoi(values[value].c_str()); break; case 22: marginStart = atoi(values[value].c_str()); break; case 23: marginStop = atoi(values[value].c_str()); break; case 24: useVPS = atoi(values[value].c_str()); break; case 25: action = atoi(values[value].c_str()); break; case 26: useExtEPGInfo = atoi(values[value].c_str()); break; case 27: extEPGInfoValues = values[value]; break; case 28: avoidRepeats = atoi(values[value].c_str()); break; case 29: allowedRepeats = atoi(values[value].c_str()); break; case 30: compareTitle = atoi(values[value].c_str()); break; case 31: compareSubtitle = atoi(values[value].c_str()); break; case 32: compareSummary = atoi(values[value].c_str()); break; case 33: catvaluesAvoidRepeat = atol(values[value].c_str()); break; case 34: repeatsWithinDays = atoi(values[value].c_str()); break; case 35: delAfterDays = atoi(values[value].c_str()); break; case 36: recordingsKeep = atoi(values[value].c_str()); break; case 37: switchMinsBefore = atoi(values[value].c_str()); break; case 38: pauseOnNrRecordings = atoi(values[value].c_str()); break; case 39: blacklistMode = atoi(values[value].c_str()); break; case 40: blacklists = values[value]; break; case 41: fuzzyTolerance = atoi(values[value].c_str()); break; case 42: useInFavorites = atoi(values[value].c_str()); break; case 43: menuTemplate = atoi(values[value].c_str()); break; case 44: delMode = atoi(values[value].c_str()); break; case 45: delAfterCountRecs = atoi(values[value].c_str()); break; case 46: delAfterDaysOfFirstRec = atoi(values[value].c_str()); break; case 47: useAsSearchTimerFrom = atol(values[value].c_str()); break; case 48: useAsSearchTimerTil = atol(values[value].c_str()); break; case 49: ignoreMissingEPGCats = atoi(values[value].c_str()); break; case 50: unmuteSoundOnSwitch = atoi(values[value].c_str()); break; case 51: compareSummaryMatchInPercent = atoi(values[value].c_str()); break; case 52: contentsFilter = values[value]; break; case 53: compareDate = atoi(values[value].c_str()); break; default: break; } } return true; } std::string cTVGuideSearchTimer::BuildSearchString(void) { std::stringstream search; // 0 - 2 if (ID > -1) search << ID << ":"; else search << ":"; std::string searchStringMasked = searchString; std::replace(searchStringMasked.begin(), searchStringMasked.end(), ':', '|'); search << searchStringMasked << ":"; search << useTime << ":"; // 3 - 6 if (useTime) { search << *cString::sprintf("%04d", startTime) << ":"; search << *cString::sprintf("%04d", stopTime) << ":"; } else { search << "::"; } search << useChannel << ":"; if (useChannel == 1) { if (channelMin && channelMax) { if (channelMin->Number() < channelMax->Number()) search << std::string(channelMin->GetChannelID().ToString()) << "|" << std::string(channelMax->GetChannelID().ToString()) << ":"; else search << std::string(channelMin->GetChannelID().ToString()) << ":"; } else { search << "0:"; } } else if (useChannel == 2) { search << channelGroup << ":"; } else { search << "0:"; } // 7 - 14 search << useCase << ":"; search << mode << ":"; search << useTitle << ":"; search << useSubtitle << ":"; search << useDescription << ":"; search << useDuration << ":"; if (useDuration) { search << *cString::sprintf("%04d", minDuration) << ":"; search << *cString::sprintf("%04d", maxDuration) << ":"; } else { search << "::"; } //15 - 53 search << useAsSearchTimer << ":"; search << useDayOfWeek << ":"; search << dayOfWeek << ":"; search << useEpisode << ":"; search << directory << ":"; search << priority << ":"; search << lifetime << ":"; search << marginStart << ":"; search << marginStop << ":"; search << useVPS << ":"; search << action << ":"; search << useExtEPGInfo << ":"; search << extEPGInfoValues << ":"; search << avoidRepeats << ":"; search << allowedRepeats << ":"; search << compareTitle << ":"; search << compareSubtitle << ":"; search << compareSummary << ":"; search << catvaluesAvoidRepeat << ":"; search << repeatsWithinDays << ":"; search << delAfterDays << ":"; search << recordingsKeep << ":"; search << switchMinsBefore << ":"; search << pauseOnNrRecordings << ":"; search << blacklistMode << ":"; search << blacklists << ":"; search << fuzzyTolerance << ":"; search << useInFavorites << ":"; search << menuTemplate << ":"; search << delMode << ":"; search << delAfterCountRecs << ":"; search << delAfterDaysOfFirstRec << ":"; search << useAsSearchTimerFrom << ":"; search << useAsSearchTimerTil << ":"; search << ignoreMissingEPGCats << ":"; search << unmuteSoundOnSwitch << ":"; search << compareSummaryMatchInPercent << ":"; search << contentsFilter << ":"; search << compareDate; strTimer = search.str(); return strTimer; } bool cTVGuideSearchTimer::IsActive(void) { if (useAsSearchTimer) return true; return false; } int cTVGuideSearchTimer::GetNumTimers(void) { int numTimers = 0; if (ID < 0) return numTimers; #if VDRVERSNUM >= 20301 LOCK_TIMERS_READ; for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer)) { #else for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { #endif char* searchID = GetAuxValue(timer, "s-id"); if (!searchID) continue; if (ID == atoi(searchID)) numTimers++; free(searchID); } return numTimers; } int cTVGuideSearchTimer::GetNumRecordings(void) { int numRecordings = 0; if (ID < 0) return numRecordings; #if VDRVERSNUM >= 20301 LOCK_RECORDINGS_READ; for (const cRecording *recording = Recordings->First(); recording; recording = Recordings->Next(recording)) { #else for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { #endif if (recording->IsEdited()) continue; if (!recording->Info()) continue; char* searchID = GetAuxValue(recording, "s-id"); if (!searchID) continue; if (ID == atoi(searchID)) numRecordings++; free(searchID); } return numRecordings; } void cTVGuideSearchTimer::GetSearchModes(std::vector *searchModes) { searchModes->push_back(tr("whole term must appear")); searchModes->push_back(tr("all terms must exist")); searchModes->push_back(tr("one term must exist")); searchModes->push_back(tr("exact match")); searchModes->push_back(tr("regular expression")); searchModes->push_back(tr("fuzzy")); } void cTVGuideSearchTimer::GetUseChannelModes(std::vector *useChannelModes) { useChannelModes->push_back(tr("No")); useChannelModes->push_back(tr("Interval")); useChannelModes->push_back(tr("Channel Group")); useChannelModes->push_back(tr("only FTA")); } void cTVGuideSearchTimer::GetCompareDateModes(std::vector *compareDateModes) { compareDateModes->push_back(tr("No")); compareDateModes->push_back(tr("same day")); compareDateModes->push_back(tr("same week")); compareDateModes->push_back(tr("same month")); } void cTVGuideSearchTimer::GetSearchTimerModes(std::vector *searchTimerModes) { searchTimerModes->push_back(tr("Record")); searchTimerModes->push_back(tr("Announce by OSD")); searchTimerModes->push_back(tr("Switch only")); searchTimerModes->push_back(tr("Announce and switch")); searchTimerModes->push_back(tr("Announce by mail")); searchTimerModes->push_back(tr("Inactive record")); } void cTVGuideSearchTimer::GetDelModes(std::vector *delModes) { delModes->push_back(tr("no")); delModes->push_back(tr("count recordings")); delModes->push_back(tr("count days")); } void cTVGuideSearchTimer::Dump(void) { esyslog("tvguide searchtimer: strTimer: %s", strTimer.c_str()); esyslog("tvguide searchtimer: ID: %d", ID); esyslog("tvguide searchtimer: searchString: %s", searchString.c_str()); esyslog("tvguide searchtimer: useTime: %d", useTime); esyslog("tvguide searchtimer: startTime: %d", startTime); esyslog("tvguide searchtimer: stopTime: %d", stopTime); esyslog("tvguide searchtimer: useChannel: %d", useChannel); if (channelMin) esyslog("tvguide searchtimer: channelMin: %s", channelMin->Name()); if (channelMax) esyslog("tvguide searchtimer: channelMax: %s", channelMax->Name()); esyslog("tvguide searchtimer: channelGroup: %s", channelGroup.c_str()); esyslog("tvguide searchtimer: useCase: %d", useCase); esyslog("tvguide searchtimer: mode: %d", mode); esyslog("tvguide searchtimer: useTitle: %d", useTitle); esyslog("tvguide searchtimer: useSubtitle: %d", useSubtitle); esyslog("tvguide searchtimer: useDescription: %d", useDescription); }