diff options
author | Denis Loh <denis.loh@gmail.com> | 2009-10-25 22:44:37 +0100 |
---|---|---|
committer | Denis Loh <denis.loh@gmail.com> | 2009-10-25 22:44:37 +0100 |
commit | c672d0018e24161434e63400f7dc23999d3f9c8a (patch) | |
tree | a16cea90b3f7dc45f47adc61568d854f79fe1513 /database | |
parent | bde12e9e1467f185068b0ae139b2380377a47eb4 (diff) | |
download | vdr-plugin-upnp-c672d0018e24161434e63400f7dc23999d3f9c8a.tar.gz vdr-plugin-upnp-c672d0018e24161434e63400f7dc23999d3f9c8a.tar.bz2 |
Solved some issues with database filling and loading
Diffstat (limited to 'database')
-rw-r--r-- | database/database.cpp | 3 | ||||
-rw-r--r-- | database/database.h | 26 | ||||
-rw-r--r-- | database/metadata.cpp | 142 | ||||
-rw-r--r-- | database/metadata.h | 2 | ||||
-rw-r--r-- | database/object.cpp | 15 | ||||
-rw-r--r-- | database/object.h | 23 |
6 files changed, 176 insertions, 35 deletions
diff --git a/database/database.cpp b/database/database.cpp index 22c41cd..9c08c00 100644 --- a/database/database.cpp +++ b/database/database.cpp @@ -169,6 +169,7 @@ void cSQLiteDatabase::startTransaction(){ } } this->execStatement("BEGIN TRANSACTION"); + MESSAGE("Start new transaction"); this->mActiveTransaction = true; } @@ -185,6 +186,7 @@ void cSQLiteDatabase::rollbackTransaction(){ int cSQLiteDatabase::initializeTables(){ int ret = 0; this->startTransaction(); + if(this->execStatement(SQLITE_CREATE_TABLE_ITEMFINDER)==-1) ret = -1; if(this->execStatement(SQLITE_CREATE_TABLE_SYSTEM)==-1) ret = -1; if(this->execStatement(SQLITE_CREATE_TABLE_PRIMARY_KEYS)==-1) ret = -1; if(this->execStatement(SQLITE_CREATE_TABLE_ALBUMS)==-1) ret = -1; @@ -213,6 +215,7 @@ int cSQLiteDatabase::initializeTables(){ int cSQLiteDatabase::initializeTriggers(){ int ret = 0; this->startTransaction(); + if(this->execStatement(SQLITE_TRIGGER_D_OBJECTS_ITEMFINDER)==-1) ret = -1; if(this->execStatement(SQLITE_TRIGGER_UPDATE_SYSTEM)==-1) ret = -1; if(this->execStatement(SQLITE_TRIGGER_UPDATE_OBJECTID)==-1) ret = -1; if(this->execStatement(SQLITE_TRIGGER_D_AUDIOITEMS_AUDIOBROADCASTS)==-1) ret = -1; diff --git a/database/database.h b/database/database.h index 9df2c71..49c208d 100644 --- a/database/database.h +++ b/database/database.h @@ -12,8 +12,8 @@ #include <vdr/tools.h> #include "../common.h" -//#define SQLITE_PRINT_STATEMENTS -//#define SQLITE_PRINT_FETCHES +#define SQLITE_PRINT_STATEMENTS +#define SQLITE_PRINT_FETCHES #define SQLITE_CASCADE_DELETES #define PK_OBJECTS TOSTRING(1) @@ -40,6 +40,7 @@ #define SQLITE_TABLE_SEARCHCLASS "SearchClass" #define SQLITE_TABLE_PRIMARY_KEYS "PrimaryKeys" #define SQLITE_TABLE_SYSTEM "System" +#define SQLITE_TABLE_ITEMFINDER "ItemFinder" #define SQLITE_TYPE_TEXT "TEXT" #define SQLITE_TYPE_INTEGER "INTEGER" @@ -110,6 +111,7 @@ #define SQLITE_COL_ARTIST "Artist" #define SQLITE_COL_DLNA_CONTAINERTYPE "DLNAContainer" #define SQLITE_COL_CHILDCOUNT "ChildCount" +#define SQLITE_COL_ITEMFINDER "ItemFastID" #define SQLITE_UPNP_OBJECTID SQLITE_COL_OBJECTID " " SQLITE_TYPE_INTEGER " " SQLITE_NOT_NULL " " SQLITE_CONFLICT_CLAUSE " "\ SQLITE_UNIQUE " " SQLITE_CONFLICT_CLAUSE @@ -294,6 +296,22 @@ /**********************************************\ * * + * Fast item finder * + * * + \**********************************************/ + +#define SQLITE_CREATE_TABLE_ITEMFINDER "CREATE TABLE IF NOT EXISTS "\ + SQLITE_TABLE_ITEMFINDER " "\ + "("\ + SQLITE_UPNP_OBJECTID ","\ + SQLITE_COL_ITEMFINDER " " SQLITE_TYPE_TEXT " " SQLITE_NOT_NULL " " SQLITE_UNIQUE \ + ");" + +#define SQLITE_TRIGGER_D_OBJECTS_ITEMFINDER SQLITE_DELETE_TRIGGER(SQLITE_TABLE_OBJECTS,\ + SQLITE_TABLE_ITEMFINDER) + + /**********************************************\ + * * * Objects * * * \**********************************************/ @@ -325,7 +343,7 @@ "((SELECT " SQLITE_COL_PARENTID " FROM " SQLITE_TABLE_OBJECTS " "\ "WHERE " SQLITE_COL_PARENTID "=-1) IS NOT NULL) "\ "AND "\ - "(NEW." SQLITE_COL_PARENTID "=-1) "\ + "(NEW." SQLITE_COL_PARENTID "=-1)"\ ") THEN "\ "RAISE(" SQLITE_TRANSACTION_TYPE ","\ "'INSERT on table " SQLITE_TABLE_OBJECTS " violates constraint. "\ @@ -344,7 +362,7 @@ "WHERE " SQLITE_COL_PARENTID "=-1 "\ "AND " SQLITE_COL_OBJECTID "!=NEW." SQLITE_COL_OBJECTID " ) IS NOT NULL) "\ "AND "\ - "(NEW." SQLITE_COL_PARENTID "=-1) "\ + "(NEW." SQLITE_COL_PARENTID "=-1) AND (OLD." SQLITE_COL_PARENTID "!=-1) "\ ") THEN "\ "RAISE(" SQLITE_TRANSACTION_TYPE ","\ "'UPDATE on table " SQLITE_TABLE_OBJECTS " violates constraint. "\ diff --git a/database/metadata.cpp b/database/metadata.cpp index 75adf98..438d002 100644 --- a/database/metadata.cpp +++ b/database/metadata.cpp @@ -16,6 +16,7 @@ #include <vdr/channels.h> #include <vdr/epg.h> #include <upnp/upnp.h> +#include <vdr/device.h> #define KEY_SYSTEM_UPDATE_ID "SystemUpdateID" @@ -51,6 +52,10 @@ bool cMediaDatabase::init(){ ERROR("Loading channels failed"); return false; } +// if(this->loadRecordings()){ +// ERROR("Loading records failed"); +// return false; +// } return true; } @@ -101,18 +106,65 @@ cUPnPObjectID cMediaDatabase::getNextObjectID(){ } cRows* Rows = this->mDatabase->getResultRows(); cRow* Row; + int ret = 0; if(!Rows->fetchRow(&Row)){ ERROR("No rows found"); + ret = 0; + } + else { + while(Row->fetchColumn(&Column, &Value)){ + if(!strcasecmp(Column, "Key")){ + this->mLastInsertObjectID = atoi(Value); + ret = this->mLastInsertObjectID; + } + } + } + delete Rows; + return ret; +} + +int cMediaDatabase::addFastFind(cUPnPClassObject* Object, const char* FastFind){ + if(!Object || !FastFind){ + MESSAGE("Invalid fast find parameters"); + return -1; + } + cString Statement = cString::sprintf("INSERT OR REPLACE INTO %s (%s, %s) VALUES ('%s', '%s')", + SQLITE_TABLE_ITEMFINDER, + SQLITE_COL_OBJECTID, + SQLITE_COL_ITEMFINDER, + *Object->getID(), + FastFind + ); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); + return -1; + } + return 0; +} + +cUPnPClassObject* cMediaDatabase::getObjectByFastFind(const char* FastFind){ + if(!FastFind) return NULL; + MESSAGE("Try to find Object with identifier %s", FastFind); + cString Statement, Column, Value; + const char* Format = "SELECT %s FROM %s WHERE %s='%s'"; + Statement = cString::sprintf(Format, SQLITE_COL_OBJECTID, SQLITE_TABLE_ITEMFINDER, SQLITE_COL_ITEMFINDER, FastFind); + if(this->mDatabase->execStatement(Statement)){ + ERROR("Error while executing statement"); return 0; } + cRows* Rows = this->mDatabase->getResultRows(); + cRow* Row; + if(!Rows->fetchRow(&Row)){ + ERROR("No rows found"); + return NULL; + } while(Row->fetchColumn(&Column, &Value)){ - if(!strcasecmp(Column, "Key")){ - this->mLastInsertObjectID = atoi(Value); - return this->mLastInsertObjectID; + if(!strcasecmp(Column, SQLITE_COL_OBJECTID)){ + return this->getObjectByID(atoi(Value)); } } delete Rows; - return 0; + return NULL; } cUPnPClassObject* cMediaDatabase::getObjectByID(cUPnPObjectID ID){ @@ -201,25 +253,38 @@ int cMediaDatabase::loadChannels(){ MESSAGE("Loading channels"); cUPnPClassContainer* TV = (cUPnPClassContainer*)this->getObjectByID(3); if(TV){ - // Iterating channels - cList<cUPnPClassObject>* List = TV->getObjectList(); bool noResource = false; // TODO: Add to setup // if an error occured while loading resources, add the channel anyway bool addWithoutResources = false; - for(cChannel* Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)){ + cChannel* Channel = NULL; + for(int Index = 0; (Channel = Channels.Get(Index)); Index = Channels.GetNextNormal(Index)){ + // Iterating the channels +// for(Channel = Channels.First(); Channel; Channel = Channels.(Channel)){ bool inList = false; - for(cUPnPClassVideoBroadcast* Child = (cUPnPClassVideoBroadcast*)List->First(); - Child; - Child = (cUPnPClassVideoBroadcast*)List->Next(Child)){ - if(!strcasecmp(Child->getChannelName(),Channel->Name())){ inList = true; break; } - } + + tChannelID ChannelID = Channel->GetChannelID(); + MESSAGE("Determine if the channel %s is already listed", *ChannelID.ToString()); + cUPnPClassVideoBroadcast* ChannelItem = NULL; + + ChannelItem = (cUPnPClassVideoBroadcast*)this->getObjectByFastFind(ChannelID.ToString()); + + inList = (ChannelItem && TV->getObject(ChannelItem->getID())) ? true : false; + if(!inList){ - if(!Channel->GroupSep()){ + if(Channel->GroupSep()){ + MESSAGE("Skipping group '%s'", Channel->Name()); + // Skip channel groups + // Channel groups may be supported theoretically. However, DLNA states that a tuner needs + // a consecutive list of channels. A simple work-around may be a virtual tuner for each group. + } + else if(Channel->Vpid()==0){ + // TODO: add radio support + MESSAGE("Skipping radio '%s'", Channel->Name()); + } + else { noResource = false; - tChannelID ChannelID = Channel->GetChannelID(); MESSAGE("Adding channel '%s' ID:%s", Channel->Name(), *ChannelID.ToString()); - cUPnPClassVideoBroadcast* ChannelItem; ChannelItem = (cUPnPClassVideoBroadcast*)this->mFactory->createObject(UPNP_CLASS_VIDEOBC, Channel->Name()); ChannelItem->setChannelName(Channel->Name()); ChannelItem->setChannelNr(Channel->Number()); @@ -231,17 +296,16 @@ int cMediaDatabase::loadChannels(){ ERROR("Unable to get resources for this channel"); noResource = true; } - if(noResource && addWithoutResources) { + if(!noResource || addWithoutResources) { TV->addObject(ChannelItem); - if(this->mFactory->saveObject(ChannelItem)) return -1; + if(this->mFactory->saveObject(ChannelItem) || + this->addFastFind(ChannelItem, ChannelID.ToString())){ + this->mFactory->deleteObject(ChannelItem); + return -1; + } + MESSAGE("Successfuly added channel"); } } - else { - MESSAGE("Skipping group '%s'", Channel->Name()); - // Skip channel groups - // Channel groups may be supported theoretically. However, DLNA states that a tuner needs - // a consecutive list of channels. A simple work-around may be a virtual tuner for each group. - } } else { MESSAGE("Skipping %s, already in database", Channel->Name()); @@ -255,12 +319,38 @@ int cMediaDatabase::loadChannels(){ // MESSAGE("Loading recordings"); // cUPnPClassContainer* Records = (cUPnPClassContainer*)this->getObjectByID(4); // if(Records){ -// // Iterating channels -// cList<cUPnPClassObject>* List = Records->getObjectList(); -// for(cRecording* Record = Recordings.First(); Record; Record = Recordings.Next(Record)){ +// cRecording* Recording = NULL; +// for(Recording = Recordings.First(); Recording; Recording = Recordings.Next(Recording)){ +// // Iterating the records +// bool inList = false; +// +// MESSAGE("Determine if the channel %s is already listed", Recording->FileName()); +// const cRecordingInfo* RecInfo = Recording->Info(); +// +// MESSAGE("%s", *RecInfo->Components()->Component(0)->ToString()); +// cUPnPClassMovie *MovieItem = NULL; +// +// MovieItem = (cUPnPClassMovie*)this->getObjectByFastFind(Recording->FileName()); +// +// inList = (MovieItem && Records->getObject(MovieItem->getID())) ? true : false; +// +// if(inList){ +// +// MESSAGE("Adding movie '%s' File name:%s", RecInfo->Title(), Recording->FileName()); +// +// MovieItem = (cUPnPClassMovie*)this->mFactory->createObject(UPNP_CLASS_MOVIE, RecInfo->Title()); +// MovieItem->setDescription(RecInfo->ShortText()); +// MovieItem->setLongDescription(RecInfo->Description()); +// MovieItem->setStorageMedium(UPNP_STORAGE_HDD); +// // +// } +// else { +// MESSAGE("Skipping %s, already in Database", Recording->FileName()); +// } // } // } +// return 0; //} void cMediaDatabase::Action(){ diff --git a/database/metadata.h b/database/metadata.h index 32d663e..6e3732c 100644 --- a/database/metadata.h +++ b/database/metadata.h @@ -51,6 +51,8 @@ public: const char* getContainerUpdateIDs(); cMediaDatabase(); virtual ~cMediaDatabase(); + int addFastFind(cUPnPClassObject* Object, const char* FastFind); + cUPnPClassObject* getObjectByFastFind(const char* FastFind); cUPnPClassObject* getObjectByID(cUPnPObjectID ID); int browse(OUT cUPnPResultSet** Results, IN const char* ID, IN bool BrowseMetadata, IN const char* Filter = "*", IN unsigned int Offset = 0, IN unsigned int Count = 0, IN const char* SortCriteria = ""); int search(OUT cUPnPResultSet** Results, IN const char* ID, IN const char* Search, IN const char* Filter = "*", IN unsigned int Offset = 0, IN unsigned int Count = 0, IN const char* SortCriteria = ""); diff --git a/database/object.cpp b/database/object.cpp index 748078d..e533fbc 100644 --- a/database/object.cpp +++ b/database/object.cpp @@ -36,7 +36,7 @@ cUPnPResource::cUPnPResource(){ } off64_t cUPnPResource::getFileSize() const { - return (this->mSize) ? this->mSize : -1; + return (this->mSize) ? this->mSize : (off64_t)-1; } time_t cUPnPResource::getLastModification() const { @@ -105,6 +105,7 @@ void cUPnPObjects::SortBy(const char* Property, bool Descending){ cUPnPClassObject::cUPnPClassObject(){ this->mID = -1; + this->mLastID = -1; this->mResources = new cList<cUPnPResource>; this->mResourcesID = new cHash<cUPnPResource>; this->mParent = NULL; @@ -154,6 +155,7 @@ int cUPnPClassObject::setID(cUPnPObjectID ID){ ERROR("Invalid object ID '%s'",*ID); return -1; } + this->mLastID = (this->mID==-1) ? ID : this->mID; this->mID = ID; return 0; } @@ -520,16 +522,16 @@ bool cUPnPClassContainer::getProperty(const char* Property, char** Value) const void cUPnPClassContainer::addObject(cUPnPClassObject* Object){ MESSAGE("Adding object (ID:%s) to container (ID:%s)", *Object->getID(), *this->getID()); + Object->setParent(this); this->mChildren->Add(Object); this->mChildrenID->Add(Object, (unsigned int)Object->getID()); - Object->setParent(this); } void cUPnPClassContainer::removeObject(cUPnPClassObject* Object){ - MESSAGE("Removing object (ID:%s) from container (ID:%s)", *Object->getID(), *this->getID()); this->mChildrenID->Del(Object, (unsigned int)Object->getID()); this->mChildren->Del(Object, false); Object->mParent = NULL; + MESSAGE("Removed object (ID:%s) from container (ID:%s)", *Object->getID(), *this->getID()); } cUPnPClassObject* cUPnPClassContainer::getObject(cUPnPObjectID ID) const { @@ -1104,6 +1106,7 @@ cUPnPClassObject* cUPnPObjectMediator::getObject(cUPnPObjectID){ WARNING("Gettin cUPnPClassObject* cUPnPObjectMediator::createObject(const char*, bool){ WARNING("Getting instance of class 'Object' forbidden"); return NULL; } int cUPnPObjectMediator::objectToDatabase(cUPnPClassObject* Object){ + MESSAGE("Updating object #%s", *Object->getID()); cString Format = "UPDATE %s SET %s WHERE %s='%s'"; //cString Format = "INSERT OR REPLACE INTO %s (%s) VALUES (%s);"; cString Statement=NULL; @@ -1128,16 +1131,19 @@ int cUPnPObjectMediator::objectToDatabase(cUPnPClassObject* Object){ } char *escapedValue; escapeSQLite(Value, &escapedValue); + MESSAGE("Set %s to %s", *(*Property), escapedValue); //Values = cString::sprintf("%s%s'%s'", *Values?*Values:"", *Values?",":"", Value?Value:"NULL"); Set = cString::sprintf("%s%s%s='%s'", *Set?*Set:"", *Set?",":"", *(*Property), escapedValue?escapedValue:"NULL"); } - Statement = cString::sprintf(Format, SQLITE_TABLE_OBJECTS, *Set, SQLITE_COL_OBJECTID, *Object->getID()); + Statement = cString::sprintf(Format, SQLITE_TABLE_OBJECTS, *Set, SQLITE_COL_OBJECTID, *Object->mLastID); //Statement = cString::sprintf(Format, SQLITE_TABLE_OBJECTS, *Columns, *Values); if(this->mDatabase->execStatement(Statement)){ ERROR("Error while executing statement"); return -1; } + // The update was successful --> the current ID is now also the LastID + Object->mLastID = Object->mID; return 0; } @@ -1146,7 +1152,6 @@ int cUPnPObjectMediator::databaseToObject(cUPnPClassObject* Object, cUPnPObjectI cString Statement = NULL, Column = NULL, Value = NULL; cRows* Rows; cRow* Row; Statement = cString::sprintf(Format, SQLITE_TABLE_OBJECTS, SQLITE_COL_OBJECTID, *ID); -// MESSAGE("Fehler hier"); if(this->mDatabase->execStatement(Statement)){ ERROR("Error while executing statement"); return -1; diff --git a/database/object.h b/database/object.h index 9b62c54..9da62db 100644 --- a/database/object.h +++ b/database/object.h @@ -104,6 +104,7 @@ class cUPnPClassObject : public cListObject { friend class cUPnPObjectMediator; friend class cUPnPClassContainer; private: + cUPnPObjectID mLastID; bool mDeleted; // is this Objected marked as deleted protected: time_t mLastModified; @@ -271,6 +272,28 @@ public: const char* getRating() const { return this->mRating; } }; +class cUPnPClassMovie : public cUPnPClassVideoItem { + friend class cMediaDatabase; + friend class cUPnPObjectMediator; + friend class cUPnPMovieMediator; +protected: + int mDVDRegionCode; + cString mStorageMedium; + cUPnPClassMovie(); +public: + virtual ~cUPnPClassMovie(); + //virtual cString createDIDLFragment(cStringList* Filter); + virtual cStringList* getPropertyList(); + virtual bool setProperty(const char* Property, const char* Value); + virtual bool getProperty(const char* Property, char** Value) const; + /******** Setter ********/ + int setDVDRegionCode(int RegionCode); + int setStorageMedium(const char* StorageMedium); + /******** Getter ********/ + int getDVDRegionCode() const { return this->mDVDRegionCode; } + const char* getStorageMedium() const { return this->mStorageMedium; } +}; + class cUPnPClassVideoBroadcast : public cUPnPClassVideoItem { friend class cMediaDatabase; friend class cUPnPObjectMediator; |