Skip to content

Commit 30ac942

Browse files
committed
support for Epgsearch_searchresults_v1_0
1 parent 25f4230 commit 30ac942

File tree

5 files changed

+318
-4
lines changed

5 files changed

+318
-4
lines changed

epgsearch/services.h

+195
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
Copyright (C) 2004-2008 Christian Wieninger
3+
4+
This program is free software; you can redistribute it and/or
5+
modify it under the terms of the GNU General Public License
6+
as published by the Free Software Foundation; either version 2
7+
of the License, or (at your option) any later version.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+
Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18+
19+
The author can be reached at [email protected]
20+
21+
The project's page is at http://winni.vdr-developer.org/epgsearch
22+
*/
23+
24+
#ifndef EPGSEARCHSERVICES_INC
25+
#define EPGSEARCHSERVICES_INC
26+
27+
#include <string>
28+
#include <list>
29+
#include <memory>
30+
#include <set>
31+
#include <vdr/osdbase.h>
32+
33+
// Data structure for service "Epgsearch-search-v1.0"
34+
struct Epgsearch_search_v1_0
35+
{
36+
// in
37+
char* query; // search term
38+
int mode; // search mode (0=phrase, 1=and, 2=or, 3=regular expression)
39+
int channelNr; // channel number to search in (0=any)
40+
bool useTitle; // search in title
41+
bool useSubTitle; // search in subtitle
42+
bool useDescription; // search in description
43+
// out
44+
cOsdMenu* pResultMenu; // pointer to the menu of results
45+
};
46+
47+
// Data structure for service "Epgsearch-exttimeredit-v1.0"
48+
struct Epgsearch_exttimeredit_v1_0
49+
{
50+
// in
51+
cTimer* timer; // pointer to the timer to edit
52+
bool bNew; // flag that indicates, if this is a new timer or an existing one
53+
const cEvent* event; // pointer to the event corresponding to this timer (may be NULL)
54+
// out
55+
cOsdMenu* pTimerMenu; // pointer to the menu of results
56+
};
57+
58+
// Data structure for service "Epgsearch-updatesearchtimers-v1.0"
59+
struct Epgsearch_updatesearchtimers_v1_0
60+
{
61+
// in
62+
bool showMessage; // inform via osd when finished?
63+
};
64+
65+
// Data structure for service "Epgsearch-osdmessage-v1.0"
66+
struct Epgsearch_osdmessage_v1_0
67+
{
68+
// in
69+
char* message; // the message to display
70+
eMessageType type;
71+
};
72+
73+
// Data structure for service "EpgsearchMenu-v1.0"
74+
struct EpgSearchMenu_v1_0
75+
{
76+
// in
77+
// out
78+
cOsdMenu* Menu; // pointer to the menu
79+
};
80+
81+
// Data structure for service "Epgsearch-lastconflictinfo-v1.0"
82+
struct Epgsearch_lastconflictinfo_v1_0
83+
{
84+
// in
85+
// out
86+
time_t nextConflict; // next conflict date, 0 if none
87+
int relevantConflicts; // number of relevant conflicts
88+
int totalConflicts; // total number of conflicts
89+
};
90+
91+
// Data structure for service "Epgsearch-searchresults-v1.0"
92+
struct Epgsearch_searchresults_v1_0
93+
{
94+
// in
95+
char* query; // search term
96+
int mode; // search mode (0=phrase, 1=and, 2=or, 3=regular expression)
97+
int channelNr; // channel number to search in (0=any)
98+
bool useTitle; // search in title
99+
bool useSubTitle; // search in subtitle
100+
bool useDescription; // search in description
101+
// out
102+
103+
class cServiceSearchResult : public cListObject
104+
{
105+
public:
106+
const cEvent* event;
107+
cServiceSearchResult(const cEvent* Event) : event(Event) {}
108+
};
109+
110+
cList<cServiceSearchResult>* pResultList; // pointer to the results
111+
};
112+
113+
// Data structure for service "Epgsearch-switchtimer-v1.0"
114+
struct Epgsearch_switchtimer_v1_0
115+
{
116+
// in
117+
const cEvent* event;
118+
int mode; // mode (0=query existance, 1=add/modify, 2=delete)
119+
// in/out
120+
int switchMinsBefore;
121+
int announceOnly;
122+
// out
123+
bool success; // result
124+
};
125+
126+
// Data structures for service "Epgsearch-services-v1.0"
127+
class cServiceHandler
128+
{
129+
public:
130+
virtual std::list<std::string> SearchTimerList() = 0;
131+
// returns a list of search timer entries in the same format as used in epgsearch.conf
132+
virtual int AddSearchTimer(const std::string&) = 0;
133+
// adds a new search timer and returns its ID (-1 on error)
134+
virtual bool ModSearchTimer(const std::string&) = 0;
135+
// edits an existing search timer and returns success
136+
virtual bool DelSearchTimer(int) = 0;
137+
// deletes search timer with given ID and returns success
138+
virtual std::list<std::string> QuerySearchTimer(int) = 0;
139+
// returns the search result of the searchtimer with given ID in the same format as used in SVDRP command 'QRYS' (->MANUAL)
140+
virtual std::list<std::string> QuerySearch(std::string) = 0;
141+
// returns the search result of the searchtimer with given settings in the same format as used in SVDRP command 'QRYS' (->MANUAL)
142+
virtual std::list<std::string> ExtEPGInfoList() = 0;
143+
// returns a list of extended EPG categories in the same format as used in epgsearchcats.conf
144+
virtual std::list<std::string> ChanGrpList() = 0;
145+
// returns a list of channel groups maintained by epgsearch
146+
virtual std::list<std::string> BlackList() = 0;
147+
// returns a list of blacklists in the same format as used in epgsearchblacklists.conf
148+
virtual std::set<std::string> DirectoryList() = 0;
149+
// List of all recording directories used in recordings, timers, search timers or in epgsearchdirs.conf
150+
virtual ~cServiceHandler() {}
151+
// Read a setup value
152+
virtual std::string ReadSetupValue(const std::string& entry) = 0;
153+
// Write a setup value
154+
virtual bool WriteSetupValue(const std::string& entry, const std::string& value) = 0;
155+
};
156+
157+
struct Epgsearch_services_v1_0
158+
{
159+
// in/out
160+
std::auto_ptr<cServiceHandler> handler;
161+
};
162+
163+
// Data structures for service "Epgsearch-services-v1.1"
164+
class cServiceHandler_v1_1 : public cServiceHandler
165+
{
166+
public:
167+
// Get timer conflicts
168+
virtual std::list<std::string> TimerConflictList(bool relOnly=false) = 0;
169+
// Check if a conflict check is advised
170+
virtual bool IsConflictCheckAdvised() = 0;
171+
};
172+
173+
struct Epgsearch_services_v1_1
174+
{
175+
// in/out
176+
std::auto_ptr<cServiceHandler_v1_1> handler;
177+
};
178+
179+
// Data structures for service "Epgsearch-services-v1.2"
180+
class cServiceHandler_v1_2 : public cServiceHandler_v1_1
181+
{
182+
public:
183+
// List of all recording directories used in recordings, timers (and optionally search timers or in epgsearchdirs.conf)
184+
virtual std::set<std::string> ShortDirectoryList() = 0;
185+
// Evaluate an expression against an event
186+
virtual std::string Evaluate(const std::string& expr, const cEvent* event) = 0;
187+
};
188+
189+
struct Epgsearch_services_v1_2
190+
{
191+
// in/out
192+
std::auto_ptr<cServiceHandler_v1_2> handler;
193+
};
194+
195+
#endif

events.cpp

+89
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ void EventsResponder::reply(std::ostream& out, cxxtools::http::Request& request,
99

1010
if ( (int)request.url().find("/events/image/") == 0 ) {
1111
replyImage(out, request, reply);
12+
} else if ( (int)request.url().find("/events/search") == 0 ){
13+
replySearchResult(out, request, reply);
1214
} else {
1315
replyEvents(out, request, reply);
1416
}
@@ -119,6 +121,93 @@ void EventsResponder::replyImage(std::ostream& out, cxxtools::http::Request& req
119121
}
120122
}
121123

124+
void EventsResponder::replySearchResult(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply)
125+
{
126+
StreamExtension se(&out);
127+
QueryHandler q("/events/search", request);
128+
129+
std::string query = q.getBodyAsString("query");
130+
int mode = q.getBodyAsInt("mode");// search mode (0=phrase, 1=and, 2=or, 3=regular expression)
131+
int channel = q.getBodyAsInt("channel");
132+
bool use_title = q.getBodyAsBool("use_title");
133+
bool use_subtitle = q.getBodyAsBool("use_subtitle");
134+
bool use_description = q.getBodyAsBool("use_description");
135+
136+
if ( query.length() == 0 ) {
137+
reply.httpReturn(402, "Query required");
138+
return;
139+
}
140+
141+
EventList* eventList;
142+
143+
if ( q.isFormat(".json") ) {
144+
reply.addHeader("Content-Type", "application/json; charset=utf-8");
145+
eventList = (EventList*)new JsonEventList(&out);
146+
} else if ( q.isFormat(".html") ) {
147+
reply.addHeader("Content-Type", "text/html; charset=utf-8");
148+
eventList = (EventList*)new HtmlEventList(&out);
149+
} else if ( q.isFormat(".xml") ) {
150+
reply.addHeader("Content-Type", "text/xml; charset=utf-8");
151+
eventList = (EventList*)new XmlEventList(&out);
152+
} else {
153+
reply.httpReturn(403, "Resources are not available for the selected format. (Use: .json or .html)");
154+
return;
155+
}
156+
eventList->init();
157+
158+
if (!use_title && !use_subtitle && !use_description)
159+
use_title = true;
160+
if (mode < 0 || mode > 3)
161+
mode = 0;
162+
if (channel < 0 || channel > Channels.Count())
163+
channel = 0;
164+
if (query.length() > 100)
165+
query = query.substr(0,100); //don't allow more than 100 characters, NOTE: maybe I should add a limitation to the Responderclass?
166+
167+
struct Epgsearch_searchresults_v1_0* epgquery = new struct Epgsearch_searchresults_v1_0;
168+
epgquery->query = (char*)query.c_str();
169+
epgquery->mode = mode;
170+
epgquery->channelNr = channel;
171+
epgquery->useTitle = use_title;
172+
epgquery->useSubTitle = use_subtitle;
173+
epgquery->useDescription = use_description;
174+
175+
int start_filter = q.getOptionAsInt("start");
176+
int limit_filter = q.getOptionAsInt("limit");
177+
if ( start_filter >= 0 && limit_filter >= 1 ) {
178+
eventList->activateLimit(start_filter, limit_filter);
179+
}
180+
181+
int total = 0;
182+
183+
cPlugin *Plugin = cPluginManager::GetPlugin("epgsearch");
184+
if (Plugin) {
185+
if (Plugin->Service("Epgsearch-searchresults-v1.0", NULL)) {
186+
if (Plugin->Service("Epgsearch-searchresults-v1.0", epgquery)) {
187+
cList< Epgsearch_searchresults_v1_0::cServiceSearchResult>* result = epgquery->pResultList;
188+
Epgsearch_searchresults_v1_0::cServiceSearchResult* item = NULL;
189+
if (result != NULL) {
190+
for(int i=0;i<result->Count();i++) {
191+
item = result->Get(i);
192+
eventList->addEvent(((cEvent*)item->event));
193+
total++;
194+
}
195+
}
196+
} else {
197+
reply.httpReturn(406, "Internal (epgsearch) error, check parameters.");
198+
}
199+
} else {
200+
reply.httpReturn(405, "Plugin-service not available.");
201+
}
202+
} else {
203+
reply.httpReturn(404, "Plugin not installed!");
204+
}
205+
eventList->setTotal(total);
206+
eventList->finish();
207+
delete eventList;
208+
delete epgquery;
209+
}
210+
122211
void operator<<= (cxxtools::SerializationInfo& si, const SerEvent& e)
123212
{
124213
si.addMember("id") <<= e.Id;

events.h

+3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
#include <cxxtools/serializationinfo.h>
77
#include <cxxtools/utf8codec.h>
88
#include "tools.h"
9+
#include "epgsearch/services.h"
910

1011
#include <vdr/epg.h>
12+
#include <vdr/plugin.h>
1113

1214
class EventsResponder : public cxxtools::http::Responder
1315
{
@@ -18,6 +20,7 @@ class EventsResponder : public cxxtools::http::Responder
1820
virtual void reply(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply);
1921
void replyEvents(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply);
2022
void replyImage(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply);
23+
void replySearchResult(std::ostream& out, cxxtools::http::Request& request, cxxtools::http::Reply& reply);
2124
};
2225

2326
typedef cxxtools::http::CachedService<EventsResponder> EventsService;

tools.cpp

+27-2
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ QueryHandler::QueryHandler(std::string service, cxxtools::http::Request& request
624624
//workaround for current cxxtools which always appends ascii character #012 at the end? AFAIK!
625625
std::string body = request.bodyStr().substr(0,request.bodyStr().length()-1);
626626
bool found_json = false;
627-
627+
628628
int i = 0;
629629
while(!found_json) {
630630
if (body[i] == '{') {
@@ -711,6 +711,19 @@ int QueryHandler::getJsonInt(std::string name)
711711
return -LOWINT;
712712
}
713713

714+
bool QueryHandler::getJsonBool(std::string name)
715+
{
716+
if (jsonObject == NULL) return false;
717+
JsonValue* jsonValue = jsonObject->GetItem(name);
718+
if (jsonValue == NULL) return false;
719+
JsonBase* jsonBase = jsonValue->Value();
720+
if (jsonBase == NULL || !jsonBase->IsBasicValue()) return false;
721+
JsonBasicValue* jsonBasicValue = (JsonBasicValue*)jsonBase;
722+
if (jsonBasicValue->IsBool()) return jsonBasicValue->ValueAsBool();
723+
if (jsonBasicValue->IsDouble()) return jsonBasicValue->ValueAsDouble() != 0 ? true : false;
724+
return false;
725+
}
726+
714727
std::string QueryHandler::getParamAsString(int level)
715728
{
716729
if ( level >= (int)_params.size() )
@@ -755,7 +768,19 @@ int QueryHandler::getBodyAsInt(std::string name)
755768
if (jsonObject != NULL) {
756769
return getJsonInt(name);
757770
}
758-
return StringExtension::strtoi(getOptionAsString(name));
771+
return StringExtension::strtoi(getBodyAsString(name));
772+
}
773+
774+
bool QueryHandler::getBodyAsBool(std::string name)
775+
{
776+
if (jsonObject != NULL) {
777+
return getJsonBool(name);
778+
}
779+
std::string result = getBodyAsString(name);
780+
if (result == "true") return true;
781+
if (result == "false") return false;
782+
if (result == "1") return true;
783+
return false;
759784
}
760785

761786
bool QueryHandler::isFormat(std::string format)

tools.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -161,17 +161,19 @@ class QueryHandler
161161
JsonObject* jsonObject;
162162
void parseRestParams(std::string params);
163163
std::string getJsonString(std::string name);
164-
int getJsonInt(std::string name);
164+
int getJsonInt(std::string name);
165+
bool getJsonBool(std::string name);
165166
std::string _format;
166167
public:
167168
QueryHandler(std::string service, cxxtools::http::Request& request);
168169
~QueryHandler();
169170
std::string getParamAsString(int level); //Parameters are part of the url (the rest after you cut away the service path)
170171
std::string getOptionAsString(std::string name); //Options are the normal url query parameters after the question mark
171-
std::string getBodyAsString(std::string name); //Are variables in the body of the http-request -> for now only html is supported!!!
172+
std::string getBodyAsString(std::string name); //Are variables in the body of the http-request -> for now only html/json are supported, xml is not implemented (!)
172173
int getParamAsInt(int level);
173174
int getOptionAsInt(std::string name);
174175
int getBodyAsInt(std::string name);
176+
bool getBodyAsBool(std::string name);
175177
bool isFormat(std::string format);
176178
std::string getFormat() { return _format; }
177179
};

0 commit comments

Comments
 (0)