Merge pull request #4630 from Red-F/gotham-resume-pvr-lastplayedposition
[vuplus_xbmc] / xbmc / epg / EpgSearchFilter.cpp
1 /*
2  *      Copyright (C) 2012-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "guilib/LocalizeStrings.h"
22 #include "utils/TextSearch.h"
23 #include "utils/log.h"
24 #include "FileItem.h"
25 #include "../addons/include/xbmc_pvr_types.h"
26
27 #include "EpgSearchFilter.h"
28 #include "EpgContainer.h"
29
30 #include "pvr/PVRManager.h"
31 #include "pvr/channels/PVRChannelGroupsContainer.h"
32 #include "pvr/recordings/PVRRecordings.h"
33 #include "pvr/timers/PVRTimers.h"
34
35 using namespace std;
36 using namespace EPG;
37 using namespace PVR;
38
39 void EpgSearchFilter::Reset()
40 {
41   m_strSearchTerm            = "";
42   m_bIsCaseSensitive         = false;
43   m_bSearchInDescription     = false;
44   m_iGenreType               = EPG_SEARCH_UNSET;
45   m_iGenreSubType            = EPG_SEARCH_UNSET;
46   m_iMinimumDuration         = EPG_SEARCH_UNSET;
47   m_iMaximumDuration         = EPG_SEARCH_UNSET;
48   m_startDateTime.SetFromUTCDateTime(g_EpgContainer.GetFirstEPGDate());
49   m_endDateTime.SetFromUTCDateTime(g_EpgContainer.GetLastEPGDate());
50   m_bIncludeUnknownGenres    = false;
51   m_bPreventRepeats          = false;
52
53   /* pvr specific filters */
54   m_iChannelNumber           = EPG_SEARCH_UNSET;
55   m_bFTAOnly                 = false;
56   m_iChannelGroup            = EPG_SEARCH_UNSET;
57   m_bIgnorePresentTimers     = true;
58   m_bIgnorePresentRecordings = true;
59   m_iUniqueBroadcastId       = EPG_SEARCH_UNSET;
60 }
61
62 bool EpgSearchFilter::MatchGenre(const CEpgInfoTag &tag) const
63 {
64   bool bReturn(true);
65
66   if (m_iGenreType != EPG_SEARCH_UNSET)
67   {
68     bool bIsUnknownGenre(tag.GenreType() > EPG_EVENT_CONTENTMASK_USERDEFINED ||
69         tag.GenreType() < EPG_EVENT_CONTENTMASK_MOVIEDRAMA);
70     bReturn = ((m_bIncludeUnknownGenres && bIsUnknownGenre) || tag.GenreType() == m_iGenreType);
71   }
72
73   return bReturn;
74 }
75
76 bool EpgSearchFilter::MatchDuration(const CEpgInfoTag &tag) const
77 {
78   bool bReturn(true);
79
80   if (m_iMinimumDuration != EPG_SEARCH_UNSET)
81     bReturn = (tag.GetDuration() > m_iMinimumDuration * 60);
82
83   if (bReturn && m_iMaximumDuration != EPG_SEARCH_UNSET)
84     bReturn = (tag.GetDuration() < m_iMaximumDuration * 60);
85
86   return bReturn;
87 }
88
89 bool EpgSearchFilter::MatchStartAndEndTimes(const CEpgInfoTag &tag) const
90 {
91   return (tag.StartAsLocalTime() >= m_startDateTime && tag.EndAsLocalTime() <= m_endDateTime);
92 }
93
94 bool EpgSearchFilter::MatchSearchTerm(const CEpgInfoTag &tag) const
95 {
96   bool bReturn(true);
97
98   if (!m_strSearchTerm.empty())
99   {
100     CTextSearch search(m_strSearchTerm, m_bIsCaseSensitive, SEARCH_DEFAULT_OR);
101     bReturn = search.Search(tag.Title()) ||
102         search.Search(tag.PlotOutline());
103   }
104
105   return bReturn;
106 }
107
108 bool EpgSearchFilter::MatchBroadcastId(const CEpgInfoTag &tag) const
109 {
110   if (m_iUniqueBroadcastId != EPG_SEARCH_UNSET)
111     return (tag.UniqueBroadcastID() == m_iUniqueBroadcastId);
112
113   return true;
114 }
115
116 bool EpgSearchFilter::FilterEntry(const CEpgInfoTag &tag) const
117 {
118   return (MatchGenre(tag) &&
119       MatchBroadcastId(tag) &&
120       MatchDuration(tag) &&
121       MatchStartAndEndTimes(tag) &&
122       MatchSearchTerm(tag)) &&
123       (!tag.HasPVRChannel() ||
124        (MatchChannelNumber(tag) &&
125         MatchChannelGroup(tag) &&
126         (!m_bFTAOnly || !tag.ChannelTag()->IsEncrypted())));
127 }
128
129 int EpgSearchFilter::RemoveDuplicates(CFileItemList &results)
130 {
131   unsigned int iSize = results.Size();
132
133   for (unsigned int iResultPtr = 0; iResultPtr < iSize; iResultPtr++)
134   {
135     const CEpgInfoTag *epgentry_1 = results.Get(iResultPtr)->GetEPGInfoTag();
136     for (unsigned int iTagPtr = 0; iTagPtr < iSize; iTagPtr++)
137     {
138       const CEpgInfoTag *epgentry_2 = results.Get(iTagPtr)->GetEPGInfoTag();
139       if (iResultPtr == iTagPtr)
140         continue;
141
142       if (epgentry_1->Title()       != epgentry_2->Title() ||
143           epgentry_1->Plot()        != epgentry_2->Plot() ||
144           epgentry_1->PlotOutline() != epgentry_2->PlotOutline())
145         continue;
146
147       results.Remove(iTagPtr);
148       iResultPtr--;
149       iTagPtr--;
150       iSize--;
151     }
152   }
153
154   return iSize;
155 }
156
157
158 bool EpgSearchFilter::MatchChannelNumber(const CEpgInfoTag &tag) const
159 {
160   bool bReturn(true);
161
162   if (m_iChannelNumber != EPG_SEARCH_UNSET && g_PVRManager.IsStarted())
163   {
164     CPVRChannelGroupPtr group = (m_iChannelGroup != EPG_SEARCH_UNSET) ? g_PVRChannelGroups->GetByIdFromAll(m_iChannelGroup) : g_PVRChannelGroups->GetGroupAllTV();
165     if (!group)
166       group = CPVRManager::Get().ChannelGroups()->GetGroupAllTV();
167
168     bReturn = (m_iChannelNumber == (int) group->GetChannelNumber(*tag.ChannelTag()));
169   }
170
171   return bReturn;
172 }
173
174 bool EpgSearchFilter::MatchChannelGroup(const CEpgInfoTag &tag) const
175 {
176   bool bReturn(true);
177
178   if (m_iChannelGroup != EPG_SEARCH_UNSET && g_PVRManager.IsStarted())
179   {
180     CPVRChannelGroupPtr group = g_PVRChannelGroups->GetByIdFromAll(m_iChannelGroup);
181     bReturn = (group && group->IsGroupMember(*tag.ChannelTag()));
182   }
183
184   return bReturn;
185 }
186
187 int EpgSearchFilter::FilterRecordings(CFileItemList &results)
188 {
189   int iRemoved(0);
190   if (!g_PVRManager.IsStarted())
191     return iRemoved;
192
193   CFileItemList recordings;
194   g_PVRRecordings->GetAll(recordings);
195
196   // TODO inefficient!
197   for (int iRecordingPtr = 0; iRecordingPtr < recordings.Size(); iRecordingPtr++)
198   {
199     CPVRRecording *recording = recordings.Get(iRecordingPtr)->GetPVRRecordingInfoTag();
200     if (!recording)
201       continue;
202
203     for (int iResultPtr = 0; iResultPtr < results.Size(); iResultPtr++)
204     {
205       const CEpgInfoTag *epgentry  = results.Get(iResultPtr)->GetEPGInfoTag();
206
207       /* no match */
208       if (!epgentry ||
209           epgentry->Title() != recording->m_strTitle ||
210           epgentry->Plot()  != recording->m_strPlot)
211         continue;
212
213       results.Remove(iResultPtr);
214       iResultPtr--;
215       ++iRemoved;
216     }
217   }
218
219   return iRemoved;
220 }
221
222 int EpgSearchFilter::FilterTimers(CFileItemList &results)
223 {
224   int iRemoved(0);
225   if (!g_PVRManager.IsStarted())
226     return iRemoved;
227
228   vector<CFileItemPtr> timers = g_PVRTimers->GetActiveTimers();
229   // TODO inefficient!
230   for (unsigned int iTimerPtr = 0; iTimerPtr < timers.size(); iTimerPtr++)
231   {
232     CFileItemPtr fileItem = timers.at(iTimerPtr);
233     if (!fileItem || !fileItem->HasPVRTimerInfoTag())
234       continue;
235
236     CPVRTimerInfoTag *timer = fileItem->GetPVRTimerInfoTag();
237     if (!timer)
238       continue;
239
240     for (int iResultPtr = 0; iResultPtr < results.Size(); iResultPtr++)
241     {
242       const CEpgInfoTag *epgentry = results.Get(iResultPtr)->GetEPGInfoTag();
243       if (!epgentry ||
244           *epgentry->ChannelTag() != *timer->ChannelTag() ||
245           epgentry->StartAsUTC()   <  timer->StartAsUTC() ||
246           epgentry->EndAsUTC()     >  timer->EndAsUTC())
247         continue;
248
249       results.Remove(iResultPtr);
250       iResultPtr--;
251       ++iRemoved;
252     }
253   }
254
255   return iRemoved;
256 }