From 56ef7aaa40b5aff3bce5ace21215acb0be5ab92f Mon Sep 17 00:00:00 2001 From: thlo Date: Sat, 23 Feb 2013 10:31:30 +0100 Subject: Support for multiple interfaces. Improved Channel Group Separator handling. Updated Web GUI to use the enclosure RSS element. Bugfixes. --- vdr-smarttvweb/httpresource.c | 102 +++++++++++------ vdr-smarttvweb/httpresource.h | 7 +- vdr-smarttvweb/smarttvfactory.c | 40 ++++--- vdr-smarttvweb/smarttvfactory.h | 5 +- vdr-smarttvweb/smarttvweb.conf | 15 ++- vdr-smarttvweb/stvw_cfg.c | 38 ++++++- vdr-smarttvweb/stvw_cfg.h | 24 ++-- vdr-smarttvweb/web/Data.js | 129 ++++++++++++++------- vdr-smarttvweb/web/Server.js | 244 +++++++++++++++++++++++++--------------- 9 files changed, 400 insertions(+), 204 deletions(-) mode change 100644 => 100755 vdr-smarttvweb/smarttvfactory.c (limited to 'vdr-smarttvweb') diff --git a/vdr-smarttvweb/httpresource.c b/vdr-smarttvweb/httpresource.c index 47fce70..84e6b06 100755 --- a/vdr-smarttvweb/httpresource.c +++ b/vdr-smarttvweb/httpresource.c @@ -116,14 +116,14 @@ struct tIndexTs { }; - +/* union tIndexRead { struct tIndexTs in; char buf[8]; }; +*/ - -cHttpResource::cHttpResource(int f, int id,string addr, int port, SmartTvServer* factory): mFactory(factory), mLog(), mServerAddr(addr), +cHttpResource::cHttpResource(int f, int id, int port, SmartTvServer* factory): mFactory(factory), mLog(), mServerPort(port), mFd(f), mReqId(id), mConnTime(0), mHandleReadCount(0), mConnected(true), mConnState(WAITING), mContentType(NYD), mReadBuffer(), mMethod(), mResponseMessagePos(0), mBlkData(NULL), mBlkPos(0), mBlkLen(0), @@ -138,19 +138,19 @@ cHttpResource::cHttpResource(int f, int id,string addr, int port, SmartTvServer* setNonBlocking(); mBlkData = new char[MAXLEN]; -#ifndef DEBUG + //#ifndef DEBUG *(mLog->log())<< DEBUGPREFIX << " cHttpResource created" << endl; -#endif + //#endif } cHttpResource::~cHttpResource() { -#ifndef DEBUG + //#ifndef DEBUG *(mLog->log())<< DEBUGPREFIX << " Destructor of cHttpResource called" << endl; -#endif + //#endif delete[] mBlkData; if (mFile != NULL) { *(mLog->log())<< DEBUGPREFIX @@ -769,6 +769,9 @@ int cHttpResource::handlePost() { if (mPath.compare("/log") == 0) { *(mLog->log())<< mPayload << endl; + + sendHeaders(200, "OK", NULL, NULL, -1, -1); + return OKAY; } if (mPath.compare("/getResume.xml") == 0) { @@ -932,7 +935,7 @@ int cHttpResource::sendDir(struct stat *statbuf) { } -int cHttpResource::writeXmlItem(string name, string link, string programme, string desc, string guid, time_t start, int dur, double fps, int is_pes, int is_new) { +int cHttpResource::writeXmlItem(string name, string link, string programme, string desc, string guid, int no, time_t start, int dur, double fps, int is_pes, int is_new) { string hdr = ""; char f[400]; @@ -944,6 +947,11 @@ int cHttpResource::writeXmlItem(string name, string link, string programme, stri hdr += "" + guid + "\n"; + snprintf(f, sizeof(f), "%d", no); + hdr += ""; + hdr += f; + hdr += "\n"; + hdr += "" + programme +"\n"; hdr += "" + desc + "\n"; @@ -1446,6 +1454,9 @@ int cHttpResource::sendMediaXml (struct stat *statbuf) { *(mLog->log()) << DEBUGPREFIX << " sendMedia " << endl; #endif + string own_ip = getOwnIp(mFd); + *(mLog->log()) << " OwnIP= " << own_ip << endl; + vector entries; if (parseFiles(&entries, "", media_folder, "", statbuf) == ERROR) { @@ -1464,10 +1475,11 @@ int cHttpResource::sendMediaXml (struct stat *statbuf) { for (uint i=0; i < entries.size(); i++) { - snprintf(pathbuf, sizeof(pathbuf), "http://%s:%d%s", mServerAddr.c_str(), mServerPort, + // snprintf(pathbuf, sizeof(pathbuf), "http://%s:%d%s", mServerAddr.c_str(), mServerPort, + snprintf(pathbuf, sizeof(pathbuf), "http://%s:%d%s", own_ip.c_str(), mServerPort, cUrlEncode::doUrlSaveEncode(entries[i].sPath).c_str()); if (writeXmlItem(cUrlEncode::doXmlSaveEncode(entries[i].sName), pathbuf, "NA", "NA", "-", - entries[i].sStart, -1, -1, -1, -1) == ERROR) + -1, entries[i].sStart, -1, -1, -1, -1) == ERROR) return ERROR; } @@ -1702,6 +1714,8 @@ int cHttpResource::sendChannelsXml (struct stat *statbuf) { << " generating /channels.xml" << DEBUGHDR << endl; #endif + string own_ip = getOwnIp(mFd); + *(mLog->log()) << " OwnIP= " << own_ip << endl; vector avps; parseQueryLine(&avps); @@ -1711,7 +1725,7 @@ int cHttpResource::sendChannelsXml (struct stat *statbuf) { string no_channels_str = ""; int no_channels = -1; string group_sep = ""; - + if (getQueryAttributeValue(&avps, "mode", mode) == OKAY){ if (mode == "nodesc") { add_desc = false; @@ -1748,27 +1762,21 @@ int cHttpResource::sendChannelsXml (struct stat *statbuf) { for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) { if (channel->GroupSep()) { - group_sep = cUrlEncode::doXmlSaveEncode(channel->Name()); - /* *(mLog->log())<< DEBUGPREFIX - << " group= " << group_sep - << " group_sep[0]= " << group_sep[0] << endl; - if (group_sep[0] == '@') { - size_t pos = group_sep.find(' ', 1); - if (pos != string::npos) - group_sep = group_sep.substr( pos +1); - else - group_sep = ""; - *(mLog->log()) << DEBUGPREFIX - << " group_sep= " << group_sep << endl; + if (mFactory->getConfig()->getGroupSep() != IGNORE) { + // if emtpyFolderDown, always. + // otherwise, only when not empty + if (!((strcmp(channel->Name(), "") == 0) && (mFactory->getConfig()->getGroupSep() == EMPTYIGNORE))) + group_sep = cUrlEncode::doXmlSaveEncode(channel->Name()); + } -*/ continue; } if (--count == 0) { break; } - snprintf(f, sizeof(f), "http://%s:3000/%s.ts", mServerAddr.c_str(), *(channel->GetChannelID()).ToString()); + // snprintf(f, sizeof(f), "http://%s:3000/%s.ts", mServerAddr.c_str(), *(channel->GetChannelID()).ToString()); + snprintf(f, sizeof(f), "http://%s:3000/%s.ts", own_ip.c_str(), *(channel->GetChannelID()).ToString()); string link = f; const cSchedule *schedule = schedules->GetSchedule(channel->GetChannelID()); @@ -1805,7 +1813,7 @@ int cHttpResource::sendChannelsXml (struct stat *statbuf) { string c_name = (group_sep != "") ? (group_sep + "~" + cUrlEncode::doXmlSaveEncode(channel->Name())) : cUrlEncode::doXmlSaveEncode(channel->Name()); // if (writeXmlItem(channel->Name(), link, title, desc, *(channel->GetChannelID()).ToString(), start_time, duration) == ERROR) - if (writeXmlItem(c_name, link, title, desc, *(channel->GetChannelID()).ToString(), start_time, duration, -1, -1, -1) == ERROR) + if (writeXmlItem(c_name, link, title, desc, *(channel->GetChannelID()).ToString(), channel->Number(), start_time, duration, -1, -1, -1) == ERROR) return ERROR; } @@ -1950,7 +1958,7 @@ int cHttpResource::deleteRecording() { if (getQueryAttributeValue(&avps, "id", id) == ERROR){ *(mLog->log())<< DEBUGPREFIX - << " ERROR: id not found" + << " ERROR: id not found in query." << DEBUGHDR << endl; sendError(400, "Bad Request", NULL, "no id in query line"); return OKAY; @@ -1959,6 +1967,9 @@ int cHttpResource::deleteRecording() { cRecording* rec = Recordings.GetByName(mPath.c_str()); if (rec == NULL) { + *(mLog->log())<< DEBUGPREFIX + << " ERROR: Recording not found. Deletion failed: mPath= " << mPath + << endl; sendError(404, "Not Found.", NULL, "Recording not found. Deletion failed!"); return OKAY; } @@ -1967,10 +1978,16 @@ int cHttpResource::deleteRecording() { // Recordings.DelByName(mPath.c_str()); } else { + *(mLog->log())<< DEBUGPREFIX + << " ERROR: rec->Delete() returns false. mPath= " << mPath + << endl; sendError(500, "Internal Server Error", NULL, "deletion failed!"); return OKAY; } + *(mLog->log())<< DEBUGPREFIX + << " Deleted." + << endl; sendHeaders(200, "OK", NULL, NULL, -1, -1); return OKAY; } @@ -1986,6 +2003,9 @@ int cHttpResource::sendRecordingsXml(struct stat *statbuf) { mConnState = SERVING; + string own_ip = getOwnIp(mFd); + *(mLog->log()) << " OwnIP= " << own_ip << endl; + vector avps; parseQueryLine(&avps); string model = ""; @@ -2098,12 +2118,14 @@ int cHttpResource::sendRecordingsXml(struct stat *statbuf) { << endl; */ if (ti->HasFlags(tfRecording) ) { + /* if (ti->Event() == NULL) { *(mLog->log()) << DEBUGPREFIX << " WARNING: Active recording for " << ti->File() << " is skipped (No Event()" << endl; continue; } + */ /* *(mLog->log()) << DEBUGPREFIX << " Active Timer: " << ti->File() << " Start= " << ti->Event()->StartTime() @@ -2132,10 +2154,12 @@ int cHttpResource::sendRecordingsXml(struct stat *statbuf) { hdr = ""; if (recording->IsPesRecording() or ((recording->FramesPerSecond() > 30.0) and !has_4_hd )) - snprintf(f, sizeof(f), "http://%s:%d%s", mServerAddr.c_str(), mServerPort, + // snprintf(f, sizeof(f), "http://%s:%d%s", mServerAddr.c_str(), mServerPort, + snprintf(f, sizeof(f), "http://%s:%d%s", own_ip.c_str(), mServerPort, cUrlEncode::doUrlSaveEncode(recording->FileName()).c_str()); else - snprintf(f, sizeof(f), "http://%s:%d%s%s", mServerAddr.c_str(), mServerPort, + // snprintf(f, sizeof(f), "http://%s:%d%s%s", mServerAddr.c_str(), mServerPort, + snprintf(f, sizeof(f), "http://%s:%d%s%s", own_ip.c_str(), mServerPort, cUrlEncode::doUrlSaveEncode(recording->FileName()).c_str(), link_ext.c_str()); string link = f; @@ -2164,7 +2188,8 @@ int cHttpResource::sendRecordingsXml(struct stat *statbuf) { } if (writeXmlItem(cUrlEncode::doXmlSaveEncode(recording->Name()), link, "NA", desc, - cUrlEncode::doXmlSaveEncode(recording->FileName()).c_str(), + cUrlEncode::doXmlSaveEncode(recording->FileName()).c_str(), + -1, recording->Start(), rec_dur, recording->FramesPerSecond(), (recording->IsPesRecording() ? 0: 1), (recording->IsNew() ? 0: 1)) == ERROR) // Better Internal Server Error @@ -2705,6 +2730,19 @@ string cHttpResource::getConnStateName() { return state_string; } + +string cHttpResource::getOwnIp(int fd) { + struct sockaddr_in sock; + socklen_t len_inet = sizeof(sock); + int ret = getsockname(fd, (struct sockaddr *)&sock, &len_inet); + if ( ret == -1 ) { + *(mLog->log()) << "Error: Cannot obtain own ip address" << endl; + return string("0.0.0.0"); + // exit(1); /* Failed */ + } + return string (inet_ntoa(sock.sin_addr)); +} + int cHttpResource::parseHttpRequestLine(string line) { mMethod = line.substr(0, line.find_first_of(" ")); mRequest = line.substr(line.find_first_of(" ") +1, (line.find_last_of(" ") - line.find_first_of(" ") -1)); @@ -2753,10 +2791,10 @@ int cHttpResource::parseHttpHeaderLine (string line) { } if (hdr_name.compare("Content-Length") == 0) { mReqContentLength = atoll(hdr_val.c_str()); -#ifndef DEBUG + //#ifndef DEBUG *(mLog->log())<< " Content-Length: " << mReqContentLength << endl; -#endif + //#endif } return 0; } diff --git a/vdr-smarttvweb/httpresource.h b/vdr-smarttvweb/httpresource.h index 81ecb34..8185026 100755 --- a/vdr-smarttvweb/httpresource.h +++ b/vdr-smarttvweb/httpresource.h @@ -74,7 +74,7 @@ class cResumeEntry; class cHttpResource { public: - cHttpResource(int, int, string, int, SmartTvServer*); + cHttpResource(int, int, int, SmartTvServer*); virtual ~cHttpResource(); int handleRead(); @@ -90,7 +90,6 @@ class cHttpResource { SmartTvServer* mFactory; Log* mLog; - string mServerAddr; int mServerPort; int mFd; int mReqId; @@ -147,7 +146,6 @@ class cHttpResource { int sendChannelsXml (struct stat *statbuf); int sendResumeXml (); int sendVdrStatusXml (struct stat *statbuf); - // int sendResumeXml (struct stat *statbuf); int sendEpgXml (struct stat *statbuf); int sendMediaXml (struct stat *statbuf); @@ -170,6 +168,7 @@ class cHttpResource { // Helper Functions const char *getMimeType(const char *name); string getConnStateName(); + string getOwnIp(int fd); void checkRecording(); bool isTimeRequest(struct stat *statbuf); int parseRangeHeaderValue(string); @@ -182,6 +181,6 @@ class cHttpResource { int getQueryAttributeValue(vector *avps, string id, string &val); int openFile(const char *name); - int writeXmlItem(string title, string link, string programme, string desc, string guid, time_t start, int dur, double fps, int is_pes, int is_new); + int writeXmlItem(string title, string link, string programme, string desc, string guid, int no, time_t start, int dur, double fps, int is_pes, int is_new); }; #endif diff --git a/vdr-smarttvweb/smarttvfactory.c b/vdr-smarttvweb/smarttvfactory.c old mode 100644 new mode 100755 index b806021..d0196c9 --- a/vdr-smarttvweb/smarttvfactory.c +++ b/vdr-smarttvweb/smarttvfactory.c @@ -143,13 +143,6 @@ void SmartTvServer::loop() { FD_SET(mServerFd, &mReadState); maxfd = mServerFd; - struct ifreq ifr; - - ifr.ifr_addr.sa_family = AF_INET; - strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1); - ioctl(mServerFd, SIOCGIFADDR, &ifr); - string own_ip = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr); - *(mLog.log()) << "mServerFd= " << mServerFd << endl; int handeled_fds = 0; @@ -231,9 +224,10 @@ void SmartTvServer::loop() { if (clientList.size() < (rfd+1)) { clientList.resize(rfd+1, NULL); // Check. } - clientList[rfd] = new cHttpResource(rfd, req_id, own_ip, serverPort, this); + clientList[rfd] = new cHttpResource(rfd, req_id, serverPort, this); + // clientList[rfd] = new cHttpResource(rfd, req_id, mOwnIp, serverPort, this); mActiveSessions ++; - + *(mLog.log()) << " + mActiveSessions= " << mActiveSessions << endl; } else{ *(mLog.log()) << "Error accepting " << errno << endl; @@ -241,8 +235,6 @@ void SmartTvServer::loop() { } // Check for data on already accepted connections - // for (rfd = mServerFd + 1; rfd <= maxfd; ++rfd) { - // for (rfd = 0; rfd <= maxfd; ++rfd) { for (rfd = 0; rfd < clientList.size(); rfd++) { if (clientList[rfd] == NULL) continue; @@ -264,6 +256,7 @@ void SmartTvServer::loop() { delete clientList[rfd]; clientList[rfd] = NULL; mActiveSessions--; + *(mLog.log()) << " - Check Read: mActiveSessions= " << mActiveSessions << endl; FD_CLR(rfd, &mReadState); /* dead client */ FD_CLR(rfd, &mWriteState); } @@ -271,8 +264,6 @@ void SmartTvServer::loop() { } // Check for write - // for (rfd = mServerFd + 1; rfd <= maxfd; ++rfd) { - // for (rfd = 0; rfd <= maxfd; ++rfd) { for (rfd = 0; rfd < clientList.size(); rfd++) { if (clientList[rfd] == NULL) continue; @@ -293,6 +284,7 @@ void SmartTvServer::loop() { delete clientList[rfd]; clientList[rfd] = NULL; mActiveSessions--; + *(mLog.log()) << " - Check Write: mActiveSessions= " << mActiveSessions << endl; FD_CLR(rfd, &mReadState); FD_CLR(rfd, &mWriteState); } @@ -344,7 +336,6 @@ void SmartTvServer::initServer(string dir) { #ifndef STANDALONE mConfig = new cSmartTvConfig(dir); mLog.init(mConfig->getLogFile()); - // mLog.init("/multimedia/video/smartvvweblog.txt"); esyslog("SmartTvWeb: Logfile created"); *(mLog.log()) << mConfig->getLogFile() << endl; @@ -352,11 +343,12 @@ void SmartTvServer::initServer(string dir) { #else mConfig = new cSmartTvConfig("."); mLog.init(mConfig->getLogFile()); - // mLog.init("/tmp/smartvvweblog-standalone.txt"); cout << "SmartTvWeb: Logfile created" << endl; cout << "SmartTvWeb: Listening on port= " << PORT << endl; #endif + + // mConfig->printConfig(); mSegmentDuration= mConfig->getSegmentDuration(); mHasMinBufferTime= mConfig->getHasMinBufferTime(); @@ -379,7 +371,13 @@ void SmartTvServer::initServer(string dir) { memset((char *) &sock, 0, sizeof(sock)); sock.sin_family = AF_INET; - sock.sin_addr.s_addr = htonl(INADDR_ANY); + + if (mConfig->getServerAddress() == "") + sock.sin_addr.s_addr = htonl(INADDR_ANY); + else { + *(mLog.log()) << "Binding Server to " << mConfig->getServerAddress() << endl; + sock.sin_addr.s_addr = inet_addr(mConfig->getServerAddress().c_str()); + } sock.sin_port = htons(serverPort); ret = bind(mServerFd, (struct sockaddr *) &sock, sizeof(sock)); @@ -387,6 +385,16 @@ void SmartTvServer::initServer(string dir) { *(mLog.log()) << "Error: Cannot bind serving socket, exit" << endl; exit(1); } + + /* + struct ifreq ifr; + + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1); + ioctl(mServerFd, SIOCGIFADDR, &ifr); + string own_ip = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr); + *(mLog.log()) << " own if ip= " << own_ip << endl; +*/ ret = listen(mServerFd, 5); if (ret <0) { diff --git a/vdr-smarttvweb/smarttvfactory.h b/vdr-smarttvweb/smarttvfactory.h index 7fc7bbd..171b1b8 100644 --- a/vdr-smarttvweb/smarttvfactory.h +++ b/vdr-smarttvweb/smarttvfactory.h @@ -38,8 +38,8 @@ using namespace std; -#define PLG_VERSION "0.9.4" -#define SERVER "SmartTvWeb/0.9.4" +#define PLG_VERSION "0.9.5" +#define SERVER "SmartTvWeb/0.9.5" class SmartTvServer { public: @@ -72,7 +72,6 @@ class SmartTvServer { int mLiveChannels; vector clientList; - // listmFdList; int mActiveSessions; string mConfigDir; cSmartTvConfig *mConfig; diff --git a/vdr-smarttvweb/smarttvweb.conf b/vdr-smarttvweb/smarttvweb.conf index 382f5bb..c9f52ed 100644 --- a/vdr-smarttvweb/smarttvweb.conf +++ b/vdr-smarttvweb/smarttvweb.conf @@ -4,12 +4,25 @@ LogFile /tmp/smarttvweb.txt MediaFolder /multimedia/video +# Media Segment Duration for HLS/ DASH SegmentDuration 10 +# minBufferTime value for the DASH MPD HasMinBufferTime 30 +# Bitrate parameter in the DASH MPD HasBitrate 60000000 +# Default number of Live Channel entries included in the channels.xml, when not requested specifically. LiveChannels 30 -UseHasForHd false +# Influence behavior, when you channels.conf contain group separators +# Valid Values (case sensitive): +# - Ignore : Ignore group separators) +# - EmptyIgnore : Ignore empty group separators (which might be set to assign channel numbers) +# - EmptyFolderDown : Interpretes an empty group channel as "cd ..", so that subsequent channels are not part of the group. +GroupSeparators Ignore + +# Bind the web server to a specific IP address. Otherwise, the Web Server is listening on ALL interfaces. +#ServerAddress 127.0.0.1 + diff --git a/vdr-smarttvweb/stvw_cfg.c b/vdr-smarttvweb/stvw_cfg.c index b624040..e323856 100755 --- a/vdr-smarttvweb/stvw_cfg.c +++ b/vdr-smarttvweb/stvw_cfg.c @@ -1,7 +1,7 @@ /* * stvw_cfg.h: VDR on Smart TV plugin * - * Copyright (C) 2012 T. Lohmar + * Copyright (C) 2012, 2013 T. Lohmar * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -33,7 +33,7 @@ cSmartTvConfig::cSmartTvConfig(string d): mConfigDir(d), mLog(NULL), mCfgFile(NULL), mLogFile(), mMediaFolder(), mSegmentDuration(), mHasMinBufferTime(), mHasBitrate(), - mLiveChannels() { + mLiveChannels(), mGroupSep(IGNORE), mServerAddress("") { #ifndef STANDALONE mLogFile= ""; @@ -47,7 +47,6 @@ cSmartTvConfig::cSmartTvConfig(string d): mConfigDir(d), mLog(NULL), mCfgFile(NU mHasMinBufferTime = 40; mHasBitrate = 6000000; mLiveChannels = 30; - mLog = Log::getInstance(); readConfig(); } @@ -55,6 +54,23 @@ cSmartTvConfig::cSmartTvConfig(string d): mConfigDir(d), mLog(NULL), mCfgFile(NU cSmartTvConfig::~cSmartTvConfig() { } +void cSmartTvConfig::printConfig() { + mLog = Log::getInstance(); + + + *(mLog->log()) << "printConfig: " << endl; + *(mLog->log()) << " ConfigDir: " << mConfigDir << endl; + *(mLog->log()) << " LogFile: " << mLogFile << endl; + *(mLog->log()) << " MediaFolder:" << mMediaFolder << endl; + *(mLog->log()) << " SegmentDuration: " << mSegmentDuration << endl; + *(mLog->log()) << " HasMinBufferTime: " << mHasMinBufferTime << endl; + *(mLog->log()) << " HasBitrate: " << mHasBitrate << endl; + *(mLog->log()) << " LiveChannels: " << mLiveChannels << endl; + *(mLog->log()) << " GroupSeparators: " << ((mGroupSep==IGNORE)? "Ignore" : ((mGroupSep==EMPTYIGNORE)? "EmptyIgnore": "EmptyFolderDown")) << endl; + *(mLog->log()) << " ServerAddress: " << mServerAddress << endl; +} + + void cSmartTvConfig::readConfig() { string line; char attr[200]; @@ -112,6 +128,22 @@ void cSmartTvConfig::readConfig() { continue; } + if (strcmp(attr, "GroupSeparators") == 0) { + if (strcmp (value, "EmptyIgnore") == 0) { + mGroupSep = EMPTYIGNORE; + } + else if ( strcmp(value, "EmptyFolderDown") == 0) { + mGroupSep = EMPTYFOLDERDOWN; + } + continue; + } + + if (strcmp(attr, "ServerAddress") == 0) { + mServerAddress = value; + // cout << " Found mLiveChannels= " < mResumes; - - string mDevice; +enum eGroupSep { + IGNORE, + EMPTYIGNORE, + EMPTYFOLDERDOWN }; -*/ + class cSmartTvConfig { private: string mConfigDir; @@ -56,13 +52,15 @@ class cSmartTvConfig { unsigned int mHasBitrate; int mLiveChannels; + eGroupSep mGroupSep; + string mServerAddress; + public: cSmartTvConfig(string dir); ~cSmartTvConfig(); void readConfig(); - - // cResumes* readConfig(string); + void printConfig(); string getLogFile() { return mLogFile; }; string getMediaFolder() { return mMediaFolder; }; @@ -70,6 +68,8 @@ class cSmartTvConfig { int getHasMinBufferTime() { return mHasMinBufferTime; }; unsigned int getHasBitrate() {return mHasBitrate; }; int getLiveChannels() {return mLiveChannels; }; + eGroupSep getGroupSep() { return mGroupSep; }; + string getServerAddress() { return mServerAddress; }; }; #endif diff --git a/vdr-smarttvweb/web/Data.js b/vdr-smarttvweb/web/Data.js index 5e480d2..49e9026 100755 --- a/vdr-smarttvweb/web/Data.js +++ b/vdr-smarttvweb/web/Data.js @@ -1,16 +1,27 @@ +//Diff: +// getNumString +// createJQMDomTree + var Data = { assets : new Item, folderList : [], }; +Array.prototype.remove = function(from, to) { + var rest = this.slice((to || from) + 1 || this.length); + this.length = from < 0 ? this.length + from : from; + return this.push.apply(this, rest); +}; + Data.reset = function() { this.assets = null; this.assets = new Item; this.folderList = []; - this.folderList.push({item : this.assets, id: 0}); +// this.folderList.push({item : this.assets, id: 0}); +// Main.log("Data.reset: folderList.push. this.folderList.length= " + this.folderList.length); }; Data.completed= function(sort) { @@ -18,26 +29,31 @@ Data.completed= function(sort) { this.assets.sortPayload(); this.folderList.push({item : this.assets, id: 0}); - console.log ("Data.completed()= " +this.folderList.length); +// Main.log("Data.completed: folderList.push. this.folderList.length= " + this.folderList.length); +// Main.log ("Data.completed()= " +this.folderList.length); }; -Data.selectFolder = function (idx) { - this.folderList.push({item : this.getCurrentItem().childs[idx], id: idx}); +Data.selectFolder = function (idx, first_idx) { + this.folderList.push({item : this.getCurrentItem().childs[idx], id: idx, first:first_idx}); +// Main.log("Data.selectFolder: folderList.push. this.folderList.length= " + this.folderList.length); +}; + +Data.folderUp = function () { + itm = this.folderList.pop(); +// Main.log("Data.folderUp: folderList.pop. this.folderList.length= " + this.folderList.length); + return itm; +// return itm.id; }; Data.isRootFolder = function() { +// Main.log("Data.isRootFolder: this.folderList.length= " + this.folderList.length); if (this.folderList.length == 1) return true; else return false; }; -Data.folderUp = function () { - itm = this.folderList.pop(); - return itm.id; -}; - Data.addItem = function(t_list, pyld) { this.assets.addChild(t_list, pyld, 0); }; @@ -48,21 +64,24 @@ Data.dumpFolderStruct = function(){ Main.log("---------- dumpFolderStruct Done -------"); }; -Data.createDomTree = function () { - - return this.assets.createDomTree(0); -}; - Data.createJQMDomTree = function () { return this.assets.createJQMDomTree(0); }; +Data.findEpgUpdateTime = function() { + return this.assets.findEpgUpdateTime(Display.GetEpochTime() + 10000, "", 0); + // min, guid, level +}; + +Data.updateEpg = function (guid, entry) { + this.assets.updateEpgEntry(guid, entry, 0); +}; + Data.getCurrentItem = function () { return this.folderList[this.folderList.length-1].item; }; -Data.getVideoCount = function() -{ +Data.getVideoCount = function() { return this.folderList[this.folderList.length-1].item.childs.length; }; @@ -84,7 +103,9 @@ Data.getNumString =function(num, fmt) { return res; }; - +Data.deleteElm = function (pos) { + Data.getCurrentItem().childs.remove(pos); +}; //----------------------------------------- function Item() { this.title = "root"; @@ -150,43 +171,71 @@ Item.prototype.addChild = function (key, pyld, level) { } }; -Item.prototype.print = function(level) { +Item.prototype.findEpgUpdateTime = function (min, guid, level) { var prefix= ""; for (var i = 0; i < level; i++) - prefix += " "; - + prefix += "-"; + for (var i = 0; i < this.childs.length; i++) { - Main.log(prefix + this.childs[i].title); if (this.childs[i].isFolder == true) { - Main.log(prefix+"Childs:"); - this.childs[i].print(level +1); + var res = this.childs[i].findEpgUpdateTime(min, guid, level+1); + min = res.min; + guid = res.guid; } - } + else { + var digi =new Date(this.childs[i].payload['start'] * 1000); + var str = digi.getHours() + ":" + digi.getMinutes(); + +// Main.log(prefix + "min= " + min+ " start= " + this.childs[i].payload['start'] + " (" + str+ ") title= " + this.childs[i].title); + + if ((this.childs[i].payload['start'] != 0) && ((this.childs[i].payload['start'] + this.childs[i].payload['dur']) < min)) { + min = this.childs[i].payload['start'] + this.childs[i].payload['dur']; + guid = this.childs[i].payload['guid'] ; +// Main.log(prefix + "New Min= " + min + " new id= " + guid + " title= " + this.childs[i].title); +// Main.logToServer(prefix + "New Min= " + min + " new id= " + guid + " title= " + this.childs[i].title); + } + } + } + + return { "min": min, "guid" : guid}; }; -Item.prototype.createDomTree = function(level) { +Item.prototype.updateEpgEntry = function (guid, entry, level) { var prefix= ""; for (var i = 0; i < level; i++) prefix += "-"; -// var mydiv = $('
' +prefix+this.title+ '
'); - var mydiv = $('