diff options
Diffstat (limited to 'smarttvfactory.c')
-rwxr-xr-x | smarttvfactory.c | 357 |
1 files changed, 353 insertions, 4 deletions
diff --git a/smarttvfactory.c b/smarttvfactory.c index d106917..27c0b2a 100755 --- a/smarttvfactory.c +++ b/smarttvfactory.c @@ -1,4 +1,4 @@ -/* + /* * smarttvfactory.c: VDR on Smart TV plugin * * Copyright (C) 2012 - 2014 T. Lohmar @@ -110,18 +110,270 @@ void cCmd::trim(string &t) { } +void cRecEntryBase::print(string pref) { + *(mLog->log()) << pref + << ": l= " << mLevel + << " B= " << mName + << endl; +}; + +void cRecEntry::print(string pref) { + *(mLog->log()) << pref + << ": l= " << mLevel + << " sfs= " << mSubfolders.size() + << " E= " << mTitle + << endl; +}; + +void cRecFolder::print(string pref) { + *(mLog->log()) << pref + << ": l= " << mLevel + << " es= " << mEntries.size() + << " F= " << mName + << endl; + for (list<cRecEntryBase*>::iterator iter = mEntries.begin(); iter != mEntries.end(); ++iter) + (*iter)->print(pref + "+" + mName); + +}; + +cRecEntry::cRecEntry(string n, int l, Log* lg, cRecording* r) : cRecEntryBase(n, l, false, lg), mRec(r), mSubfolders(), + mError(false), mTitle(n) { + + size_t pos = 0; + size_t l_pos = 0; + for (int i = 0; i <= l; i++) { + if (l_pos == string::npos) { + *(mLog->log()) << mLog->getTimeString() + << " ERROR: " + << " Name= " << n + << endl; + mError = true; + break; + } + pos = n.find('~', l_pos); + string dir = n.substr(l_pos, (pos -l_pos)); + + /* + *(mLog->log()) << " (p= " << pos + << " l= " << l_pos + << " d= " << dir + << ")"; +*/ + mSubfolders.push_back(dir); + + l_pos = pos +1; + } + // *(mLog->log()) << endl; + + *(mLog->log()) << mLog->getTimeString() + << " L= " << mLevel << " " << l + << " SFs= " << mSubfolders.size() + << " FName= " << mName + << endl; + + int idx = mSubfolders.size() -1; + if (idx != l) { + *(mLog->log()) << mLog->getTimeString() + << " ERROR: mName= " << mName + << " Level (" << l + << ") missmatches subfolders (" << mSubfolders.size() + << ")" + << endl; + } + else + mName = mSubfolders[idx]; +} + +int cRecEntry::writeXmlItem(string * msg, string own_ip, int own_port) { + string hdr = ""; + char f[400]; + + hdr += "<item>\n"; + hdr += "<title>" + mTitle +"</title>\n"; + hdr += "<isfolder>false</isfolder>\n"; + // mRec->IsPesRecording(); + + snprintf(f, sizeof(f), "http://%s:%d%s", own_ip.c_str(), own_port, + cUrlEncode::doUrlSaveEncode(mRec->FileName()).c_str()); + + string mime = "video/mpeg"; + string programme = "NA"; + string desc = "NA"; + int no = -1; + + hdr += "<enclosure url=\""; + hdr += f; + hdr += "\" type=\""+mime+"\" />\n"; + + hdr += "<guid>" + cUrlEncode::doUrlSaveEncode(mRec->FileName()) + "</guid>\n"; + + snprintf(f, sizeof(f), "%d", no); + hdr += "<number>"; + hdr += f; + hdr += "</number>\n"; + hdr += "<programme>" + programme +"</programme>\n"; + hdr += "<description>" + desc + "</description>\n"; + + snprintf(f, sizeof(f), "%ld", mRec->Start()); + hdr += "<start>"; + hdr += f; + hdr += "</start>\n"; + + snprintf(f, sizeof(f), "%d", mRec->LengthInSeconds()); + hdr += "<duration>"; + + hdr += f; + hdr += "</duration>\n"; + + snprintf(f, sizeof(f), "<fps>%.2f</fps>\n", mRec->FramesPerSecond()); + hdr += f; + + if (mRec->IsPesRecording()) + hdr += "<ispes>true</ispes>\n"; + else + hdr += "<ispes>false</ispes>\n"; + + if (mRec->IsNew()) + hdr += "<isnew>true</isnew>\n"; + else + hdr += "<isnew>false</isnew>\n"; + + hdr += "</item>\n"; + + *msg += hdr; + return 0; +} + +int cRecFolder::writeXmlItem(string * msg, string own_ip, int own_port) { + string hdr = ""; + + hdr += "<item>\n"; + hdr += "<title>" + mName +"</title>\n"; + hdr += "<guid>" + cUrlEncode::doUrlSaveEncode(mPath) + "</guid>\n"; + + hdr += "<isfolder>true</isfolder>\n"; + hdr += "</item>\n"; + + *msg += hdr; + return 0; +} + +int cRecFolder::writeXmlFolder(string* msg, string own_ip, int own_port) { + string hdr = ""; + hdr += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + hdr += "<rss version=\"2.0\">\n"; + hdr+= "<channel>\n"; + hdr+= "<title>VDR Recordings List</title>\n"; + + *msg += hdr; + + //iter over all items + for (list<cRecEntryBase*>::iterator iter = mEntries.begin(); iter != mEntries.end(); ++iter) { + (*iter)->writeXmlItem(msg, own_ip, own_port); + } + + hdr = "</channel>\n"; + hdr += "</rss>\n"; + + *msg += hdr; + + // *(mLog->log())<< DEBUGPREFIX << " Recording Count= " <<item_count<< endl; + + return OKAY; + +} + +void cRecFolder::appendEntry(cRecFolder* entry) { + *(mLog->log()) << mLog->getTimeString() << " appendEntry " + << " mName= " << mName + << " ol= " << mLevel + << " Folder" + << " l= " << entry->mLevel + << " Name= " << entry->mName + << endl; + mEntries.push_back(entry); +} + + +void cRecFolder::appendEntry(cRecEntry* entry) { + + // root: append to mEntries + if (entry->mLevel == mLevel) { + *(mLog->log()) << mLog->getTimeString() << " appendEntry " + << " mName= " << mName + << " ol= " << mLevel + << " Entry" + << " l= " << entry->mLevel + << " Name= " << entry->mName + << endl; + + mEntries.push_back(entry); + return; + } + + *(mLog->log()) << mLog->getTimeString() << " - appendEntry " + << " mName= " << mName + << " ol= " << mLevel + << " Entry" + << " l= " << entry->mLevel + << " sf= " << (entry->mSubfolders).size() + << " f= " << entry->mSubfolders[mLevel] + << " Name= " << entry->mName + << endl; + + // find needed subfolder + bool found = false; + for (list<cRecEntryBase*>::iterator iter= mEntries.begin(); iter != mEntries.end(); ++iter) { + if (((*iter)->mName == entry->mSubfolders[mLevel]) && ((*iter)->mIsFolder)) { + ((cRecFolder*)(*iter))->appendEntry(entry); + found = true; + break; + } + } + if (!found) { + string p = ((mPath == "") ? entry->mSubfolders[mLevel] : mPath + "~" + entry->mSubfolders[mLevel]); + cRecFolder* folder = new cRecFolder(entry->mSubfolders[mLevel], p, mLevel +1, mLog); + appendEntry(folder); + folder->appendEntry(entry); + } + // check, if a subfolder is needed +} + +cRecFolder* cRecFolder::GetFolder(list<string> *folder_list) { + string name = folder_list->front(); + cRecFolder* dir = NULL; + *(mLog->log()) << mLog->getTimeString() + << " GetFolder name= " << name << endl; + for (list<cRecEntryBase*>::iterator iter= mEntries.begin(); iter != mEntries.end(); ++iter) { + if (((*iter)->mName == name) && ((*iter)->mIsFolder)) { + dir = (cRecFolder*)(*iter); + break; + } + } + if (dir != NULL) { + folder_list->pop_front(); + if (folder_list->size() != 0) + return dir->GetFolder(folder_list); + else + return dir; + } + return NULL; +} SmartTvServer::SmartTvServer(): cStatus(), mRequestCount(0), isInited(false), serverPort(PORT), mServerFd(-1), mSegmentDuration(10), mHasMinBufferTime(40), mLiveChannels(20), clientList(), mConTvClients(), mRecCmds(), mCmdCmds(), mRecMsg(), mCmdMsg(), mActiveSessions(0), mHttpClientId(0), mConfig(NULL), mMaxFd(0), - mManagedUrls(NULL) { + mManagedUrls(NULL), mActRecordings(), mRecordings(NULL), mRecState(0) { + } SmartTvServer::~SmartTvServer() { + delete mRecordings; + if (mConfig != NULL) delete mConfig; @@ -165,6 +417,15 @@ void SmartTvServer::Recording(const cDevice *Device, const char *Name, const cha name = Name; string method = (On) ? "RECSTART" : "RECSTOP"; + + // keep track of active recordings + if (FileName != NULL) { + if (On) + AddActRecording(name, FileName); + else + DelActRecording(name, FileName); + } + string guid = (FileName == NULL) ? "" : cUrlEncode::doUrlSaveEncode(FileName); msg << "{\"type\":\""+method+"\",\"name\":\"" << name << "\",\"guid\":\""+guid+"\"}"; @@ -187,6 +448,46 @@ void SmartTvServer::Recording(const cDevice *Device, const char *Name, const cha } }; + //TODO: Store active recordings in a Database + // The database should contain only active recordings + // database for active recordings: entry is FileName (i.e. guid) + // store only, when FileName is not NULL + +void SmartTvServer::AddActRecording(string n, string fn) { + mActRecordings.push_back(new cActiveRecording(n, fn)); + *(mLog.log()) << mLog.getTimeString() + << " AddActRecording fn= " << fn + << " CurListSize= " << mActRecordings.size() + << endl; +} + +void SmartTvServer::DelActRecording(string n, string fn) { + int del_count =0; + for (list<cActiveRecording*>::iterator itr = mActRecordings.begin(); itr != mActRecordings.end(); /*nothing*/) { + if ((*itr)->mFilename == fn) { + itr = mActRecordings.erase(itr); + del_count ++; + } + else + ++itr; + } + + *(mLog.log()) << mLog.getTimeString() + << " DelActRecording Deleted " << n + << " Occurances= " << del_count + << " CurListSize= " << mActRecordings.size() + << endl; +} + +bool SmartTvServer::IsActRecording(string fn) { + for (list<cActiveRecording*>::iterator itr = mActRecordings.begin(); itr != mActRecordings.end(); ++itr) { + if ((*itr)->mFilename == fn) { + return true; + } + } + return false; +} + //thlo: Try to clean up void SmartTvServer::pushToClients(cHttpResourceBase* resource) { for (uint i = 0; i < mConTvClients.size(); i ++) { @@ -534,6 +835,53 @@ void SmartTvServer::acceptHttpResource(int &req_id) { } + +cRecFolder* SmartTvServer::GetRecDb() { + bool changed = Recordings.StateChanged(mRecState); + *(mLog.log()) << mLog.getTimeString() + << " GetRecDb Changed= " << ((changed) ? "Yes" : "No") + << endl; + if (changed) { + + delete mRecordings; + mRecordings = new cRecFolder(".", "", 0, &mLog); + CreateRecDb(); + } + return mRecordings; +} + +void SmartTvServer::CreateRecDb() { + cRecording *recording = Recordings.First(); + *(mLog.log()) << mLog.getTimeString() << ": CreateRecDb " + << " NewState= " << mRecState + << endl; + + while (recording != NULL) { + string name = recording->Name(); + + // (mRecordings->mEntries).push_back(new cRecEntry(recording->Name(), recording->HierarchyLevels())); + cRecEntry* entry = new cRecEntry(recording->Name(), recording->HierarchyLevels(), &mLog, recording); + mRecordings->appendEntry(entry); + // (mRecordings->mEntries).appendEntry(entry, 0); + + /* + *(mLog.log()) << mLog.getTimeString() + << " L= " << recording->HierarchyLevels() + << " FName= " << recording->Name() + << endl; +*/ + recording = Recordings.Next(recording); + } + + + *(mLog.log()) << " Summary " << endl; + mRecordings->print(""); + + + *(mLog.log()) << " Summary -done " << endl; + +} + void SmartTvServer::loop() { int req_id = 0; int ret = 0; @@ -737,9 +1085,10 @@ void SmartTvServer::initServer(string dir) { cout << "SmartTvWeb: Listening on port= " << PORT << endl; #endif - - mConfig->printConfig(); + mRecordings = new cRecFolder(".", "", 0, &mLog); + + mConfig->printConfig(); mSegmentDuration= mConfig->getSegmentDuration(); mHasMinBufferTime= mConfig->getHasMinBufferTime(); |