From: Andreas Monzner Date: Tue, 21 Mar 2006 13:53:19 +0000 (+0000) Subject: add search function to epgcache to do similar broadcasting searches and text searches... X-Git-Tag: 2.6.0~3791 X-Git-Url: https://git.cweiske.de/enigma2.git/commitdiff_plain/a5275b224cc48c49d249501ba029ea932d2c95c2 add search function to epgcache to do similar broadcasting searches and text searches in event titles for more infos about how to use look at epgcache.cpp, search eEPGCache::search method and read the comment above the funcion the similar broadcastings search is used from python in Eventview.py --- diff --git a/lib/dvb/db.cpp b/lib/dvb/db.cpp index 19339470..63e163eb 100644 --- a/lib/dvb/db.cpp +++ b/lib/dvb/db.cpp @@ -760,6 +760,22 @@ RESULT eDVBDB::startQuery(ePtr &query, eDVBChannelQuery *q return 0; } +eServiceReference eDVBDB::searchReference(int tsid, int onid, int sid) +{ + eServiceID Sid(sid); + eTransportStreamID Tsid(tsid); + eOriginalNetworkID Onid(onid); + for (std::map >::iterator sit(m_services.begin()); + sit != m_services.end(); ++sit) + { + if (sit->first.getTransportStreamID() == Tsid && + sit->first.getOriginalNetworkID() == Onid && + sit->first.getServiceID() == Sid) + return sit->first; + } + return eServiceReference(); +} + DEFINE_REF(eDVBDBQueryBase); eDVBDBQueryBase::eDVBDBQueryBase(eDVBDB *db, const eServiceReference &source, eDVBChannelQuery *query) diff --git a/lib/dvb/db.h b/lib/dvb/db.h index bf39df18..8ddf2232 100644 --- a/lib/dvb/db.h +++ b/lib/dvb/db.h @@ -50,6 +50,7 @@ public: ////// void saveServicelist(); void loadBouquet(const char *path); + eServiceReference searchReference(int tsid, int onid, int sid); eDVBDB(); virtual ~eDVBDB(); #endif diff --git a/lib/dvb/epgcache.cpp b/lib/dvb/epgcache.cpp index b5f519e9..d400dd27 100644 --- a/lib/dvb/epgcache.cpp +++ b/lib/dvb/epgcache.cpp @@ -9,6 +9,7 @@ // #include #include #include +#include #include int eventData::CacheSize=0; @@ -65,7 +66,6 @@ const eit_event_struct* eventData::get() const { int pos = 12; int tmp = ByteSize-12; - memcpy(data, EITdata, 12); __u32 *p = (__u32*)(EITdata+12); while(tmp>0) @@ -1641,6 +1641,389 @@ skip_entry: return dest_list; } +void fillTuple2(PyObject *tuple, const char *argstring, int argcount, eventData *evData, ePtr &ptr, PyObject *service_name, PyObject *service_reference) +{ + PyObject *tmp=NULL; + int pos=0; + while(pos < argcount) + { + bool inc_refcount=false; + switch(argstring[pos]) + { + case '0': // PyLong 0 + tmp = PyLong_FromLong(0); + break; + case 'I': // Event Id + tmp = PyLong_FromLong(evData->getEventID()); + break; + case 'B': // Event Begin Time + if (ptr) + tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : NULL; + else + tmp = PyLong_FromLong(evData->getStartTime()); + break; + case 'D': // Event Duration + if (ptr) + tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : NULL; + else + tmp = PyLong_FromLong(evData->getDuration()); + break; + case 'T': // Event Title + tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : NULL; + break; + case 'S': // Event Short Description + tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : NULL; + break; + case 'E': // Event Extended Description + tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : NULL; + break; + case 'R': // service reference string + tmp = service_reference; + inc_refcount = true; + break; + case 'N': // service name + tmp = service_name; + inc_refcount = true; + break; + } + if (!tmp) + { + tmp = Py_None; + inc_refcount = true; + } + if (inc_refcount) + Py_INCREF(tmp); + PyTuple_SET_ITEM(tuple, pos++, tmp); + } +} + +// here we get a python tuple +// the first entry in the tuple is a python string to specify the format of the returned tuples (in a list) +// I = Event Id +// B = Event Begin Time +// D = Event Duration +// T = Event Title +// S = Event Short Description +// E = Event Extended Description +// R = Service Reference +// N = Service Name +// the second tuple entry is the MAX matches value +// the third tuple entry is the type of query +// 0 = search for similar broadcastings (SIMILAR_BROADCASTINGS_SEARCH) +// 1 = search events with exactly title name (EXAKT_TITLE_SEARCH) +// 2 = search events with text in title name (PARTIAL_TITLE_SEARCH) +// when type is 0 (SIMILAR_BROADCASTINGS_SEARCH) +// the fourth is the servicereference tring +// the fifth is the eventid +// when type is 1 or 2 (EXAKT_TITLE_SEARCH or PARTIAL_TITLE_SEARCH) +// the fourth is the search text +// the fifth is +// 0 = case sensitive (CASE_CHECK) +// 1 = case insensitive (NO_CASECHECK) + +PyObject *eEPGCache::search(PyObject *arg) +{ + PyObject *ret = 0; + int descridx = -1; + __u32 descr[512]; + int eventid = -1; + const char *argstring=0; + int argcount=0; + int querytype=-1; + bool needServiceEvent=false; + int maxmatches=0; + + if (PyTuple_Check(arg)) + { + int tuplesize=PyTuple_Size(arg); + if (tuplesize > 0) + { + PyObject *obj = PyTuple_GET_ITEM(arg,0); + if (PyString_Check(obj)) + { + argcount = PyString_GET_SIZE(obj); + argstring = PyString_AS_STRING(obj); + for (int i=0; i < argcount; ++i) + switch(argstring[i]) + { + case 'S': + case 'E': + case 'T': + needServiceEvent=true; + default: + break; + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("tuple arg 0 is not a string"); + return NULL; + } + } + if (tuplesize > 1) + maxmatches = PyLong_AsLong(PyTuple_GET_ITEM(arg, 1)); + if (tuplesize > 2) + { + querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2)); + if (tuplesize > 4 && querytype == 0) + { + PyObject *obj = PyTuple_GET_ITEM(arg, 3); + if (PyString_Check(obj)) + { + const char *refstr = PyString_AS_STRING(obj); + eServiceReferenceDVB ref(refstr); + if (ref.valid()) + { + eventid = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4)); + singleLock s(cache_lock); + const eventData *evData = 0; + lookupEventId(ref, eventid, evData); + if (evData) + { + __u8 *data = evData->EITdata; + int tmp = evData->ByteSize-12; + __u32 *p = (__u32*)(data+12); + // search short and extended event descriptors + while(tmp>0) + { + __u32 crc = *p++; + descriptorMap::iterator it = + eventData::descriptors.find(crc); + if (it != eventData::descriptors.end()) + { + __u8 *descr_data = it->second.second; + switch(descr_data[0]) + { + case 0x4D ... 0x4E: + descr[++descridx]=crc; + default: + break; + } + } + tmp-=4; + } + } + if (descridx<0) + eDebug("event not found"); + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("tuple arg 4 is not a valid service reference string"); + return NULL; + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("tuple arg 4 is not a string"); + return NULL; + } + } + else if (tuplesize > 4 && (querytype == 1 || querytype == 2) ) + { + PyObject *obj = PyTuple_GET_ITEM(arg, 3); + if (PyString_Check(obj)) + { + int casetype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4)); + const char *str = PyString_AS_STRING(obj); + int textlen = PyString_GET_SIZE(obj); + if (querytype == 1) + eDebug("lookup for events with '%s' as title(%s)", str, casetype?"ignore case":"case sensitive"); + else + eDebug("lookup for events with '%s' in title(%s)", str, casetype?"ignore case":"case sensitive"); + singleLock s(cache_lock); + for (descriptorMap::iterator it(eventData::descriptors.begin()); + it != eventData::descriptors.end() && descridx < 511; ++it) + { + __u8 *data = it->second.second; + if ( data[0] == 0x4D ) // short event descriptor + { + int title_len = data[5]; + if ( querytype == 1 ) + { + if (title_len > textlen) + continue; + else if (title_len < textlen) + continue; + if ( casetype ) + { + if ( !strncasecmp((const char*)data+6, str, title_len) ) + { +// std::string s((const char*)data+6, title_len); +// eDebug("match1 %s %s", str, s.c_str() ); + descr[++descridx] = it->first; + } + } + else if ( !strncmp((const char*)data+6, str, title_len) ) + { +// std::string s((const char*)data+6, title_len); +// eDebug("match2 %s %s", str, s.c_str() ); + descr[++descridx] = it->first; + } + } + else + { + int idx=0; + while((title_len-idx) >= textlen) + { + if (casetype) + { + if (!strncasecmp((const char*)data+6+idx, str, textlen) ) + { + descr[++descridx] = it->first; +// std::string s((const char*)data+6, title_len); +// eDebug("match 3 %s %s", str, s.c_str() ); + break; + } + else if (!strncmp((const char*)data+6+idx, str, textlen) ) + { + descr[++descridx] = it->first; +// std::string s((const char*)data+6, title_len); +// eDebug("match 4 %s %s", str, s.c_str() ); + break; + } + } + ++idx; + } + } + } + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("tuple arg 4 is not a string"); + return NULL; + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("tuple arg 3(%d) is not a known querytype(0, 1, 2)", querytype); + return NULL; + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("not enough args in tuple"); + return NULL; + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("arg 0 is not a tuple"); + return NULL; + } + + if (descridx > -1) + { + int maxcount=maxmatches; + singleLock s(cache_lock); + // check all services + for( eventCache::iterator cit(eventDB.begin()); cit != eventDB.end() && maxcount; ++cit) + { + PyObject *service_name=0; + PyObject *service_reference=0; + eventMap &evmap = cit->second.first; + // check all events + for (eventMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit) + { + __u8 *data = evit->second->EITdata; + int tmp = evit->second->ByteSize-12; + __u32 *p = (__u32*)(data+12); + // check if any of our descriptor used by this event +// if (evit->first == eventid ) +// continue; + int cnt=-1; + while(tmp>0) + { + __u32 crc32 = *p++; + for ( int i=0; i <= descridx; ++i) + { + if (descr[i] == crc32) // found... + ++cnt; + } + tmp-=4; + } + if ( (querytype == 0 && cnt == descridx) || + ((querytype == 1 || querytype == 2) && cnt != -1) ) + { + const uniqueEPGKey &service = cit->first; + eServiceReference ref = + eDVBDB::getInstance()->searchReference(service.tsid, service.onid, service.sid); + if (ref.valid()) + { + // create servive event + ePtr ptr; + if (needServiceEvent) + { + lookupEventId(ref, evit->first, ptr); + if (!ptr) + eDebug("event not found !!!!!!!!!!!"); + } + // create service name + if (!service_name && strchr(argstring,'N')) + { + ePtr sptr; + eServiceCenterPtr service_center; + eServiceCenter::getPrivInstance(service_center); + if (service_center) + { + service_center->info(ref, sptr); + if (sptr) + { + std::string name; + sptr->getName(ref, name); + if (name.length()) + service_name = PyString_FromString(name.c_str()); + } + } + if (!service_name) + service_name = PyString_FromString(""); + } + // create servicereference string + if (!service_reference && strchr(argstring,'R')) + service_reference = PyString_FromString(ref.toString().c_str()); + // create list + if (!ret) + ret = PyList_New(0); + // create tuple + PyObject *tuple = PyTuple_New(argcount); + // fill tuple + fillTuple2(tuple, argstring, argcount, evit->second, ptr, service_name, service_reference); + PyList_Append(ret, tuple); + Py_DECREF(tuple); + --maxcount; + } + } + } + if (service_name) + Py_DECREF(service_name); + if (service_reference) + Py_DECREF(service_reference); + } + } + + if (!ret) + { + Py_INCREF(Py_None); + ret=Py_None; + } + + return ret; +} + #ifdef ENABLE_PRIVATE_EPG #include #include diff --git a/lib/dvb/epgcache.h b/lib/dvb/epgcache.h index 9f94d5ca..69eec7d7 100644 --- a/lib/dvb/epgcache.h +++ b/lib/dvb/epgcache.h @@ -139,7 +139,7 @@ public: int getDuration() { return fromBCD(EITdata[7])*3600+fromBCD(EITdata[8])*60+fromBCD(EITdata[9]); - } + } }; #endif @@ -296,7 +296,17 @@ public: RESULT lookupEventTime(const eServiceReference &service, time_t, Event* &, int direction=0); RESULT getNextTimeEntry(Event *&); #endif + enum { + SIMILAR_BROADCASTINGS_SEARCH, + EXAKT_TITLE_SEARCH, + PARTIAL_TITLE_SEARCH + }; + enum { + CASE_CHECK, + NO_CASE_CHECK + }; PyObject *lookupEvent(PyObject *list, PyObject *convertFunc=NULL); + PyObject *search(PyObject *); // eServiceEvent are parsed epg events.. it's safe to use them after cache unlock // for use from python ( members: m_start_time, m_duration, m_short_description, m_extended_description ) diff --git a/lib/python/Screens/EventView.py b/lib/python/Screens/EventView.py index ef3786c5..bb45836d 100644 --- a/lib/python/Screens/EventView.py +++ b/lib/python/Screens/EventView.py @@ -3,10 +3,11 @@ from Components.ActionMap import ActionMap from Components.Button import Button from Components.Label import Label from Components.ScrollLabel import ScrollLabel -from enigma import eServiceEventPtr +from enigma import eServiceEventPtr, eEPGCachePtr, eEPGCache from ServiceReference import ServiceReference from RecordTimer import RecordTimerEntry, parseEvent from TimerEntry import TimerEntry +from time import localtime, asctime class EventViewBase: def __init__(self, Event, Ref, callback=None): @@ -71,8 +72,20 @@ class EventViewBase: else: self["channel"].setText(_("unknown service")) + def sort_func(self,x,y): + if x[1] < y[1]: + return -1 + elif x[1] == y[1]: + return 0 + else: + return 1 + def setEvent(self, event): self.event = event + id = event.getEventId() + + refstr = str(self.currentService) + epgcache = eEPGCache.getInstance() text = event.getEventName() short = event.getShortDescription() ext = event.getExtendedDescription() @@ -82,6 +95,16 @@ class EventViewBase: if len(text) > 0: text = text + '\n\n' text = text + ext + + # search similar broadcastings + ret = epgcache.search(('NB', 100, eEPGCache.SIMILAR_BROADCASTINGS_SEARCH, refstr, id)) + if ret is not None: + text += '\n\n' + _('Similar broadcastings:') + ret.sort(self.sort_func) + for x in ret: + t = localtime(x[1]) + text += '\n%d.%d.%d, %02d:%02d - %s'%(t[2], t[1], t[0], t[3], t[4], x[0]) + self.setTitle(event.getEventName()) self["epg_description"].setText(text) self["datetime"].setText(event.getBeginTimeString())