add search function to epgcache to do similar broadcasting searches and text searches...
authorAndreas Monzner <andreas.monzner@multimedia-labs.de>
Tue, 21 Mar 2006 13:53:19 +0000 (13:53 +0000)
committerAndreas Monzner <andreas.monzner@multimedia-labs.de>
Tue, 21 Mar 2006 13:53:19 +0000 (13:53 +0000)
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

lib/dvb/db.cpp
lib/dvb/db.h
lib/dvb/epgcache.cpp
lib/dvb/epgcache.h
lib/python/Screens/EventView.py

index 193394705c06ee1a34c2fb9d047a3f20c84a017f..63e163eb28ffc2918da47589bd9e7bf4e7d45869 100644 (file)
@@ -760,6 +760,22 @@ RESULT eDVBDB::startQuery(ePtr<iDVBChannelListQuery> &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<eServiceReferenceDVB, ePtr<eDVBService> >::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)
index bf39df18c2b755af8e140e77145b783c61a447aa..8ddf2232a671522c39a777fd2b6ecc95b1a5e23c 100644 (file)
@@ -50,6 +50,7 @@ public:
 //////
        void saveServicelist();
        void loadBouquet(const char *path);
+       eServiceReference searchReference(int tsid, int onid, int sid);
        eDVBDB();
        virtual ~eDVBDB();
 #endif
index b5f519e94488ec93d1cfa26095e58294563ece29..d400dd27765355923e9da0fc5ada3d94e4ced11f 100644 (file)
@@ -9,6 +9,7 @@
 // #include <libmd5sum.h>
 #include <lib/base/eerror.h>
 #include <lib/dvb/pmt.h>
+#include <lib/dvb/db.h>
 #include <Python.h>
 
 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<eServiceEvent> &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<eServiceEvent> ptr;
+                                               if (needServiceEvent)
+                                               {
+                                                       lookupEventId(ref, evit->first, ptr);
+                                                       if (!ptr)
+                                                               eDebug("event not found !!!!!!!!!!!");
+                                               }
+                                       // create service name
+                                               if (!service_name && strchr(argstring,'N'))
+                                               {
+                                                       ePtr<iStaticServiceInformation> 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("<n/a>");
+                                               }
+                                       // 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 <dvbsi++/descriptor_tag.h>
 #include <dvbsi++/unknown_descriptor.h>
index 9f94d5caaee61c390e8d9abd26311d59b5a7f2b7..69eec7d750785ba633a2f161f35c75f0b3bbd486 100644 (file)
@@ -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 )
index ef3786c5e5604d814eeb22d7f847eacc1905da1b..bb45836de1eb5276144569a237a5ff63cac29f35 100644 (file)
@@ -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())