diff options
author | thlo <smarttv640@gmail.com> | 2013-03-17 09:41:35 +0100 |
---|---|---|
committer | thlo <t.lohmar@gmx.de> | 2013-03-17 09:41:35 +0100 |
commit | b183afb04050143a3f9faccf6ff52219e60c34d6 (patch) | |
tree | 7c32b63c7f5c175005186e68ff55edafc1ac36e3 /vdr-smarttvweb | |
parent | d48d64273d5da9bf596b239bb0aec622086655f0 (diff) | |
download | vdr-plugin-smarttvweb-b183afb04050143a3f9faccf6ff52219e60c34d6.tar.gz vdr-plugin-smarttvweb-b183afb04050143a3f9faccf6ff52219e60c34d6.tar.bz2 |
First step of repo restructuring
Diffstat (limited to 'vdr-smarttvweb')
-rw-r--r-- | vdr-smarttvweb/Makefile | 109 | ||||
-rwxr-xr-x | vdr-smarttvweb/httpresource.c | 2905 | ||||
-rwxr-xr-x | vdr-smarttvweb/httpresource.h | 187 | ||||
-rw-r--r-- | vdr-smarttvweb/log.c | 85 | ||||
-rw-r--r-- | vdr-smarttvweb/log.h | 50 | ||||
-rwxr-xr-x | vdr-smarttvweb/smarttvfactory.c | 408 | ||||
-rw-r--r-- | vdr-smarttvweb/smarttvfactory.h | 84 | ||||
-rw-r--r-- | vdr-smarttvweb/smarttvweb.c | 152 | ||||
-rw-r--r-- | vdr-smarttvweb/smarttvweb.conf | 28 | ||||
-rwxr-xr-x | vdr-smarttvweb/stvw_cfg.c | 196 | ||||
-rwxr-xr-x | vdr-smarttvweb/stvw_cfg.h | 75 | ||||
-rw-r--r-- | vdr-smarttvweb/url.c | 340 | ||||
-rw-r--r-- | vdr-smarttvweb/url.h | 50 | ||||
-rwxr-xr-x | vdr-smarttvweb/web/Data.js | 296 | ||||
-rwxr-xr-x | vdr-smarttvweb/web/Server.js | 180 | ||||
-rwxr-xr-x | vdr-smarttvweb/web/favicon.ico | bin | 1502 -> 0 bytes | |||
-rwxr-xr-x | vdr-smarttvweb/web/index.html | 104 | ||||
-rw-r--r-- | vdr-smarttvweb/widget.conf | 11 |
18 files changed, 0 insertions, 5260 deletions
diff --git a/vdr-smarttvweb/Makefile b/vdr-smarttvweb/Makefile deleted file mode 100644 index b04d143..0000000 --- a/vdr-smarttvweb/Makefile +++ /dev/null @@ -1,109 +0,0 @@ -# -# Makefile for a Video Disk Recorder plugin -# -# -# The official name of this plugin. -# This name will be used in the '-P...' option of VDR to load the plugin. -# By default the main source file also carries this name. -# -PLUGIN = smarttvweb - -### The version number of this plugin (taken from the main source file): - -VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') - -### The C++ compiler and options: - - -CXX ?= g++ -ifdef DEBUG -CXXFLAGS ?= -g -O0 -fPIC -Wall -Woverloaded-virtual #-Werror -else -CXXFLAGS ?= -fPIC -Wall -Woverloaded-virtual #-Werror -#CXXFLAGS ?= -O2 -fPIC -Wall -Woverloaded-virtual #-Werror -endif - -### The directory environment: - -#VDRDIR = ../../.. -VDRDIR = /usr/include/vdr -LIBDIR = . -#LIBDIR = ../../lib -TMPDIR = /tmp - -### Allow user defined options to overwrite defaults: - -#-include $(VDRDIR)/Make.config - -### read standlone settings if there --include .standalone - -### The version number of VDR (taken from VDR's "config.h"): - -VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') -APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) - -### The name of the distribution archive: - -ARCHIVE = $(PLUGIN)-$(VERSION) -PACKAGE = vdr-$(ARCHIVE) - -### Includes and Defines (add further entries here): - -INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include - -DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE - -### The object files (add further files here): - -OBJS = $(PLUGIN).o smarttvfactory.o httpresource.o log.o url.o stvw_cfg.o - -OBJS2 = - -### Implicit rules: - -%.o: %.c - $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< - -# Dependencies: - -MAKEDEP = g++ -MM -MG -DEPFILE = .dependencies -$(DEPFILE): Makefile - @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ - --include $(DEPFILE) - -### Targets: - -all: allbase libvdr-$(PLUGIN).so -standalone: standalonebase smarttvweb-standalone - -objectsstandalone: $(OBJS) -objects: $(OBJS) $(OBJS2) - -allbase: - ( if [ -f .standalone ] ; then ( rm -f .standalone; make clean ; make objects ) ; else exit 0 ;fi ) -standalonebase: - ( if [ ! -f .standalone ] ; then ( make clean; echo "DEFINES+=-DSTANDALONE" > .standalone; echo "DEFINES+=-D_FILE_OFFSET_BITS=64" >> .standalone; make objectsstandalone ) ; else exit 0 ;fi ) - -libvdr-$(PLUGIN).so: objects - $(CXX) $(CXXFLAGS) -shared $(OBJS) $(OBJS2) -o $@ - @cp $@ $(LIBDIR)/$@.$(APIVERSION) - -smarttvweb-standalone: objectsstandalone - $(CXX) $(CXXFLAGS) $(OBJS) -lpthread -o $@ - chmod u+x $@ - -dist: clean - @-rm -rf $(TMPDIR)/$(ARCHIVE) - @mkdir $(TMPDIR)/$(ARCHIVE) - @cp -a * $(TMPDIR)/$(ARCHIVE) - @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) - @-rm -rf $(TMPDIR)/$(ARCHIVE) - @echo Distribution package created as $(PACKAGE).tgz - -clean: - rm -f $(OBJS) $(OBJS2) $(DEPFILE) libvdr*.so.* *.tgz core* *~ .standalone smarttvweb-standalone - diff --git a/vdr-smarttvweb/httpresource.c b/vdr-smarttvweb/httpresource.c deleted file mode 100755 index 79d39bc..0000000 --- a/vdr-smarttvweb/httpresource.c +++ /dev/null @@ -1,2905 +0,0 @@ -/* - * httpresource.c: VDR on Smart TV plugin - * - * 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 - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <time.h> -#include <sys/socket.h> -#include <netdb.h> -#include <sys/stat.h> -#include <sys/select.h> -#include <fcntl.h> -#include <errno.h> -#include <dirent.h> - -#include <string> -#include <cstring> -#include <iostream> -#include <vector> -#include "httpresource.h" -#include "smarttvfactory.h" -#include "stvw_cfg.h" - -#include "url.h" - -#ifndef STANDALONE -#include <vdr/recording.h> -#include <vdr/channels.h> -#include <vdr/timers.h> -#include <vdr/videodir.h> -#include <vdr/epg.h> - -#endif - -#define PROTOCOL "HTTP/1.1" -#define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT" - -#define MAXLEN 4096 -#define OKAY 0 -#define ERROR (-1) -#define DEBUG_REGHEADERS -#define DEBUGPREFIX "mReqId= " << mReqId << " fd= " << mFd -#define DEBUGHDR " " << __PRETTY_FUNCTION__ << " (" << __LINE__ << ") " - -#define DEBUG - -#define SEGMENT_DURATION 10 - -using namespace std; - -class cResumeEntry { - public: - string mFilename; - float mResume; - - friend ostream& operator<<(ostream& out, const cResumeEntry& o) { - out << "mFilename= " << o.mFilename << " mResume= " << o.mResume << endl; - return out; - }; - cResumeEntry():mFilename(), mResume(-1.0) {}; -}; - - -struct sVdrFileEntry { - uint64_t sSize; - uint64_t sFirstOffset; - int sIdx; - - sVdrFileEntry () {}; - sVdrFileEntry (uint64_t s, uint64_t t, int i) - : sSize(s), sFirstOffset(t), sIdx(i) {}; -}; - - -struct sTimerEntry { - string name; - time_t startTime; - int duration; -sTimerEntry(string t, time_t s, int d) : name(t), startTime(s), duration(d) {}; -}; - -// 8 Byte Per Entry -struct tIndexPes { - uint32_t offset; - uchar type; - uchar number; - uint16_t reserved; - }; - - -// 8 Byte per entry -struct tIndexTs { - uint64_t offset:40; // up to 1TB per file (not using long long int here - must definitely be exactly 64 bit!) - int reserved:7; // reserved for future use - int independent:1; // marks frames that can be displayed by themselves (for trick modes) - uint16_t number:16; // up to 64K files per recording - }; - - -/* -union tIndexRead { - struct tIndexTs in; - char buf[8]; -}; -*/ - -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), - mPath(), mVersion(), protocol(), mReqContentLength(0), - mPayload(), mUserAgent(), - mAcceptRanges(true), rangeHdr(), mFileSize(-1), mStreamToEnd(false), mRemLength(0), mFile(NULL), mVdrIdx(1), mFileStructure(), - mIsRecording(false), mRecProgress(0.0) { - - mLog = Log::getInstance(); - mPath = ""; - mConnTime = time(NULL); - setNonBlocking(); - mBlkData = new char[MAXLEN]; - - //#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " cHttpResource created" << endl; - //#endif -} - - -cHttpResource::~cHttpResource() { - //#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " Destructor of cHttpResource called" - << endl; - //#endif - delete[] mBlkData; - if (mFile != NULL) { - *(mLog->log())<< DEBUGPREFIX - << " ERROR: mFile still open. Closing now..." << endl; - fclose(mFile); - mFile = NULL; - } - -} - -int cHttpResource::checkStatus() { - time_t now = time(NULL); - - switch (mConnState) { - case WAITING: - case READHDR: - case READPAYLOAD: - if (now - mConnTime > 2) { - *(mLog->log()) << DEBUGPREFIX - << " checkStatus: no activity for 2sec " - << "mmConnState= " << getConnStateName() - << endl; - return ERROR; - } - break; - case TOCLOSE: - return ERROR; - break; - case SERVING: - break; - } - - // check for how much time the - return OKAY; -} - -void cHttpResource::setNonBlocking() { - int oldflags = fcntl(mFd, F_GETFL, 0); - oldflags |= O_NONBLOCK; - fcntl(mFd, F_SETFL, oldflags); -} - - -int cHttpResource::handleRead() { - mHandleReadCount ++; - if (mConnState == SERVING) { - *(mLog->log())<< DEBUGPREFIX - << " handleRead() in wrong state= " << getConnStateName() - << endl; - return OKAY; - } - if (mConnState == TOCLOSE) { - *(mLog->log())<< DEBUGPREFIX - << " handleRead() in wrong state= " << getConnStateName() - << endl; - return ERROR; - } - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " handleRead() state= " << getConnStateName() - << endl; -#endif - - char buf[MAXLEN]; - int buflen = sizeof(buf); - - int line_count = 0; - // bool is_req = true; - string rem_hdr = ""; - - buflen = read(mFd, buf, sizeof(buf)); - - if (buflen == -1) { - *(mLog->log())<< " Some Error, no data received" << endl; - return ERROR; // Nothing to read - } - - // if (( mConnState == WAITING) and ((time(NULL) - mConnTime) > 1)) { - if (( mConnState == WAITING) and (mHandleReadCount > 1000)) { - *(mLog->log()) << DEBUGPREFIX << " hmm, handleRead() no data since 1sec -> closing. mHandleReadCount= " << mHandleReadCount << endl; - return ERROR; // Nothing to read - } - - if ( ((mConnState == READHDR) or (mConnState == READPAYLOAD)) and (mHandleReadCount > 5000)) { - *(mLog->log()) << DEBUGPREFIX << " ERROR Still not finished after mHandleReadCount= " << mHandleReadCount << endl; - return ERROR; // Nothing to read - } - - if (buflen == 0) { - return OKAY; // Nothing to read - } - - if (mConnState == READPAYLOAD) { - mPayload += string(buf, buflen); - if (mPayload.size() == mReqContentLength) { - //Done - mConnState = SERVING; - return processRequest(); - } - } - - if (mConnState == WAITING) { - mConnState = READHDR; - } - - string req_line = mReadBuffer + string(buf, buflen); - buflen += rem_hdr.size(); - - size_t last_pos = 0; - // Parse http header lines - while (true) { - line_count ++; - size_t pos = req_line.find ("\r\n", last_pos); - - if ((pos > buflen) or (pos == string::npos)) { - mReadBuffer = req_line.substr(last_pos, buflen - last_pos); -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX << " No HdrEnd Found, read more data. rem_hdr= " << mReadBuffer.size() - << " buflen= " << buflen - << DEBUGHDR << endl; - *(mLog->log())<< cUrlEncode::hexDump(mReadBuffer) << endl; -#endif - return OKAY; - } - - if ((last_pos - pos) == 0) { - // Header End -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX << " ---- Header End Found" << DEBUGHDR << endl; -#endif - - if (mReqContentLength != 0) { - mConnState = READPAYLOAD; - mPayload = req_line.substr(pos +2, buflen - (pos +2)); - if (mPayload.size() != mReqContentLength) - return OKAY; - else { - mConnState = SERVING; - return processRequest(); - } - } // if(content_length != 0) - else { - mConnState = SERVING; - return processRequest(); - } - } // if (header end) - - string line = req_line.substr(last_pos, (pos-last_pos)); -#ifdef DEBUG_REQHEADERS - *(mLog->log())<< " Line= " << line << endl; -#endif - last_pos = pos +2; - if (mPath.size() == 0) { -#ifndef DEBUG - *(mLog->log())<< " parsing Request Line= " << line << endl; -#endif - // is_req = false; - // Parse the request line - if (parseHttpRequestLine(line) != OKAY) { - return ERROR; - }; - } - else { - parseHttpHeaderLine (line); - } - } - return OKAY; -} - -int cHttpResource::processRequest() { - // do stuff based on the request and the query -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX << " processRequest for mPath= " << mPath << DEBUGHDR << endl; -#endif - struct stat statbuf; - bool ok_to_serve = false; - - if (mMethod.compare("POST")==0) { - return handlePost(); - } - - if (!((strcasecmp(mMethod.c_str(), "GET") == 0) or (strcasecmp(mMethod.c_str(), "HEAD") == 0))) { - sendError(501, "Not supported", NULL, "Method is not supported."); - return OKAY; - } - -#ifndef STANDALONE - if (mPath.compare("/recordings.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - sendRecordingsXml( &statbuf); - return OKAY; - } - - if (mPath.compare("/channels.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - sendChannelsXml( &statbuf); - return OKAY; - } - - if (mPath.compare("/epg.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - sendEpgXml( &statbuf); - return OKAY; - } - - if (mPath.compare("/setResume.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - receiveResume(); - return OKAY; - } - - if (mPath.compare("/getResume.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - sendResumeXml(); - return OKAY; - } - - if (mPath.compare("/vdrstatus.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - sendVdrStatusXml( &statbuf); - return OKAY; - } - - -#endif - - if (mPath.compare("/media.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - sendMediaXml( &statbuf); - return OKAY; - } - - if (mPath.compare("/widget.conf") == 0) { - mPath = mFactory->getConfigDir() + "/widget.conf"; - - if (stat(mPath.c_str(), &statbuf) < 0) { - sendError(404, "Not Found", NULL, "File not found."); - return OKAY; - } - if (handleHeadRequest() != 0) - return OKAY; - - mFileSize = statbuf.st_size; - mContentType = SINGLEFILE; - return sendFile(&statbuf); - } - - if (mPath.compare("/favicon.ico") == 0) { - mPath = mFactory->getConfigDir() + "/web/favicon.ico"; - - if (stat(mPath.c_str(), &statbuf) < 0) { - sendError(404, "Not Found", NULL, "File not found."); - return OKAY; - } - if (handleHeadRequest() != 0) - return OKAY; - - mFileSize = statbuf.st_size; - mContentType = SINGLEFILE; - return sendFile(&statbuf); - } - - - if (mPath.size() > 8) { - if (mPath.compare(mPath.size() -8, 8, "-seg.mpd") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - sendManifest( &statbuf, false); - return OKAY; - } - } - - if (mPath.size() > 9) { - if (mPath.compare(mPath.size() -9, 9, "-seg.m3u8") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - sendManifest( &statbuf, true); - return OKAY; - } - } - - if (mPath.size() > 7) { - if (mPath.compare(mPath.size() -7, 7, "-seg.ts") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - sendMediaSegment( &statbuf); - return OKAY; - } - } - - if (mPath.find("/web/") == 0) { - mPath = mFactory->getConfigDir() + mPath; - *(mLog->log())<< DEBUGPREFIX - << " Found web request. serving " << mPath << endl; - ok_to_serve = true; - } - - - if (stat(mPath.c_str(), &statbuf) < 0) { - // checking, whether the file or directory exists - *(mLog->log())<< DEBUGPREFIX - << " File Not found " << mPath << endl; - sendError(404, "Not Found", NULL, "File not found."); - - return OKAY; - } - - if (S_ISDIR(statbuf.st_mode)) { - // Do Folder specific checkings -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " processRequest: isDir - mPath: " << mPath.c_str() << endl; -#endif - - if (mPath.size() >4) { - if (mPath.compare(mPath.size() - 4, 4, ".rec") == 0) { - // Handle any recording directory specifically - if (handleHeadRequest() != 0) - return OKAY; - - mContentType = VDRDIR; - return sendVdrDir( &statbuf); - } - } - - if (!((ok_to_serve) or (mPath.compare(0, (mFactory->getConfig()->getMediaFolder()).size(), mFactory->getConfig()->getMediaFolder()) == 0))) { - // No directory access outside of MediaFolder (and also VDRCONG/web) - sendError(404, "Not Found", NULL, "File not found."); - return OKAY; - } - if (handleHeadRequest() != 0) - return OKAY; - - mContentType = MEMBLOCK; - sendDir( &statbuf); - return OKAY; - } - else { - // mPath is not a folder, thus it is a file -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " processRequest: file send\n"; -#endif - - // Check, if requested file is in Media Directory - if (!((ok_to_serve) or (mPath.compare(0, (mFactory->getConfig()->getMediaFolder()).size(), mFactory->getConfig()->getMediaFolder()) == 0))) { - sendError(404, "Not Found", NULL, "File not found."); - return OKAY; - } - if (handleHeadRequest() != 0) - return OKAY; - mFileSize = statbuf.st_size; - mContentType = SINGLEFILE; - return sendFile(&statbuf); - } - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " processRequest: Not Handled SHOULD not be here\n"; -#endif - return ERROR; -} - - -int cHttpResource::handleWrite() { - - if (mConnState == TOCLOSE) { - *(mLog->log())<< DEBUGPREFIX - << " handleWrite() in wrong state= " << getConnStateName() - << endl; - return ERROR; - } - - if (mConnState != SERVING) { - return OKAY; - } - - if (mBlkLen == mBlkPos) { - // note the mBlk may be filled with header info first. - if (fillDataBlk() != OKAY) { - return ERROR; - } - } - - int this_write = write(mFd, &mBlkData[mBlkPos], mBlkLen - mBlkPos); - if (this_write <=0) { - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " ERROR after write: Stopped (Client terminated Connection)" - << " mBlkPos= " << mBlkPos << " mBlkLen= " << mBlkLen - << DEBUGHDR << endl; -#endif - mConnState = TOCLOSE; - mConnected = false; - return ERROR; - } - mBlkPos += this_write; - - return OKAY; -} - - -int cHttpResource::fillDataBlk() { - char pathbuf[4096]; - - mBlkPos = 0; - int to_read = 0; - - switch(mContentType) { - case NYD: - - break; - case VDRDIR: - // Range requests are assumed to be all open - if (mFile == NULL) { - *(mLog->log()) << DEBUGPREFIX << " no open file anymore " - << "--> Done " << endl; - return ERROR; - } - if ((mRemLength == 0) && !mStreamToEnd){ -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX << " mRemLength is zero " - << "--> Done " << endl; -#endif - fclose(mFile); - mFile = NULL; - return ERROR; - } - if (!mStreamToEnd) - to_read = ((mRemLength > MAXLEN) ? MAXLEN : mRemLength); - else - to_read = MAXLEN; - - mBlkLen = fread(mBlkData, 1, to_read, mFile); - if (!mStreamToEnd) - mRemLength -= mBlkLen; - - if ((mRemLength == 0) && (!mStreamToEnd)) { -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX << " last Block read " - << "--> Almost Done " << endl; -#endif - return OKAY; - } - - // if (mBlkLen != MAXLEN) { // thlo verify - if (mBlkLen != to_read) { - fclose(mFile); - mFile = NULL; - mVdrIdx ++; - - snprintf(pathbuf, sizeof(pathbuf), mFileStructure.c_str(), mDir.c_str(), mVdrIdx); - mPath = pathbuf; - - if (openFile(pathbuf) != OKAY) { - *(mLog->log())<< DEBUGPREFIX << " Failed to open file= " << pathbuf << " mRemLength= " << mRemLength<< endl; - mFile = NULL; - if (mBlkLen == 0) { - *(mLog->log()) << DEBUGPREFIX << " mBlkLen is zero --> Done " << endl; - return ERROR; - } - else - *(mLog->log()) << DEBUGPREFIX << " Still data to send mBlkLen= " << mBlkLen <<" --> continue " << endl; - return OKAY; - } // Error: Open next file failed - - if (mBlkLen == 0) { - if (!mStreamToEnd) - to_read = ((mRemLength > MAXLEN) ? MAXLEN : mRemLength); - else - to_read = MAXLEN; - mBlkLen = fread(mBlkData, 1, to_read, mFile); - if (!mStreamToEnd) - mRemLength -= mBlkLen ; - } - } - break; - case SINGLEFILE: - - to_read = ((mRemLength > MAXLEN) ? MAXLEN : mRemLength); - mBlkLen = fread(mBlkData, 1, to_read, mFile); - mRemLength -= mBlkLen; - if (mBlkLen == 0) { - - // read until EOF - fclose(mFile); - mFile = NULL; - return ERROR; - } - break; - case MEMBLOCK: - int rem_len = mResponseMessage->size() - mResponseMessagePos; - if (rem_len == 0) { - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX << " fillDataBlock: MEMBLOCK done" << endl; -#endif - delete mResponseMessage; - mResponseMessagePos = 0; - mConnState = TOCLOSE; - return ERROR; - } - if (rem_len > MAXLEN) - rem_len = MAXLEN; - - string sub_msg = mResponseMessage->substr(mResponseMessagePos, rem_len); - mResponseMessagePos += rem_len; - mBlkLen = sub_msg.size(); - memcpy(mBlkData, sub_msg.c_str(), rem_len); - break; - } - - return OKAY; -} - - -int cHttpResource::parseResume(cResumeEntry &entry, string &id) { - bool done = false; - size_t cur_pos = 0; - - // The asset_id should the the filename, which is provided by the link element in the xml - // the link is url-safe encoded. - - // bool have_devid = false; - bool have_filename = false; - bool have_resume = false; - - while (!done) { - size_t pos = mPayload.find('\n', cur_pos); - if (pos == string::npos) { - done = true; - continue; - } - size_t pos_col = mPayload.find(':', cur_pos); - string attr= mPayload.substr(cur_pos, (pos_col- cur_pos)); - string val = mPayload.substr(pos_col +1, (pos - pos_col-1)); - - /* if (attr== "devid") { - have_devid = true; - id = val; - } - else */ - if (attr == "filename") { - have_filename = true; - entry.mFilename = cUrlEncode::doXmlSaveDecode(val); - *(mLog->log())<< DEBUGPREFIX - << " filename= " << entry.mFilename - << endl; - } - else if (attr == "resume") { - have_resume = true; - entry.mResume = atof(val.c_str()); - *(mLog->log())<< DEBUGPREFIX - << " mResume= " << entry.mResume - << endl; - } - else { - *(mLog->log())<< DEBUGPREFIX - << " parseResume: ERROR: Unknown attr= " << attr - << " with val= " << val - << endl; - } - cur_pos = pos +1; - if (cur_pos >= mPayload.size()) - done= true; - } - if (have_resume && have_filename ) - return OKAY; - else - return ERROR; -} - -int cHttpResource::handleHeadRequest() { - if (mMethod.compare("HEAD") != 0) { - return 0; - } - *(mLog->log())<< DEBUGPREFIX - << " Handle HEAD Request for Url " << mPath << endl; - mConnState = SERVING; - mContentType = MEMBLOCK; - - // sent an empty response message with just the OK header - mResponseMessage = new string(); - *mResponseMessage = ""; - mResponseMessagePos = 0; - - sendHeaders(200, "OK", NULL, NULL, -1, -1); - return 1; -} - -int cHttpResource::handlePost() { - mConnState = SERVING; - mContentType = MEMBLOCK; - - // sent an empty response message with just the OK header - mResponseMessage = new string(); - *mResponseMessage = ""; - mResponseMessagePos = 0; - - if (mPath.compare("/log") == 0) { - *(mLog->log())<< mPayload - << endl; - - sendHeaders(200, "OK", NULL, NULL, -1, -1); - return OKAY; - } - - if (mPath.compare("/getResume.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - // sendResumeXml( &statbuf); - sendResumeXml( ); - return OKAY; - } - - if (mPath.compare("/setResume.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - receiveResume(); - return OKAY; - } - - if (mPath.compare("/deleteRecording.xml") == 0) { - if (handleHeadRequest() != 0) - return OKAY; - - deleteRecording(); - return OKAY; - } - - // Should not reach the end of the function - return ERROR; -} - - -void cHttpResource::sendError(int status, const char *title, const char *extra, const char *text) { - char f[400]; - - mConnState = SERVING; - mContentType = MEMBLOCK; - mResponseMessage = new string(); - *mResponseMessage = ""; - mResponseMessagePos = 0; - - string hdr = ""; - // sendHeaders(status, title, extra, "text/html", -1, -1); - sendHeaders(status, title, extra, "text/plain", -1, -1); - - /* snprintf(f, sizeof(f), "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title); - hdr += f; - snprintf(f, sizeof(f), "<BODY><H4>%d %s</H4>\r\n", status, title); - hdr += f; -*/ - snprintf(f, sizeof(f), "%s\r\n", text); - hdr += f; - /* snprintf(f, sizeof(f), "</BODY></HTML>\r\n"); - hdr += f; -*/ - - strcpy(&(mBlkData[mBlkLen]), hdr.c_str()); - mBlkLen += hdr.size(); - -} - - -int cHttpResource::sendDir(struct stat *statbuf) { - char pathbuf[4096]; - char f[400]; - int len; - - mConnState = SERVING; - -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX << " sendDir: mPath= " << mPath << endl; -#endif - len = mPath.length(); - // int ret = OKAY; - - if (len == 0 || mPath[len - 1] != '/') { - snprintf(pathbuf, sizeof(pathbuf), "Location: %s/", mPath.c_str()); - sendError(302, "Found", pathbuf, "Directories must end with a slash."); - return OKAY; - } - - snprintf(pathbuf, sizeof(pathbuf), "%sindex.html", mPath.c_str()); - if (stat(pathbuf, statbuf) >= 0) { - mPath = pathbuf; - mFileSize = statbuf->st_size; - mContentType = SINGLEFILE; - return sendFile(statbuf); - } - -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX << " sendDir: create index.html " << endl; -#endif - DIR *dir; - struct dirent *de; - - mResponseMessage = new string(); - mResponseMessagePos = 0; - *mResponseMessage = ""; - - string hdr = ""; - snprintf(f, sizeof(f), "<HTML><HEAD><TITLE>Index of %s</TITLE></HEAD>\r\n<BODY>", mPath.c_str()); - hdr += f; - snprintf(f, sizeof(f), "<H4>Index of %s</H4>\r\n<PRE>\n", mPath.c_str()); - hdr += f; - snprintf(f, sizeof(f), "Name Last Modified Size\r\n"); - hdr += f; - snprintf(f, sizeof(f), "<HR>\r\n"); - hdr += f; - - *mResponseMessage += hdr; - hdr = ""; - - if (len > 1) { - snprintf(f, sizeof(f), "<A HREF=\"..\">..</A>\r\n"); - hdr += f; - } - *mResponseMessage += hdr; - - dir = opendir(mPath.c_str()); - while ((de = readdir(dir)) != NULL) { - char timebuf[32]; - struct tm *tm; - strcpy(pathbuf, mPath.c_str()); - // printf (" -Entry: %s\n", de->d_name); - strcat(pathbuf, de->d_name); - - stat(pathbuf, statbuf); - tm = gmtime(&(statbuf->st_mtime)); - strftime(timebuf, sizeof(timebuf), "%d-%b-%Y %H:%M:%S", tm); - - hdr = ""; - snprintf(f, sizeof(f), "<A HREF=\"%s%s\">", de->d_name, S_ISDIR(statbuf->st_mode) ? "/" : ""); - hdr += f; - - snprintf(f, sizeof(f), "%s%s", de->d_name, S_ISDIR(statbuf->st_mode) ? "/</A>" : "</A> "); - hdr += f; - - if (strlen(de->d_name) < 32) { - snprintf(f, sizeof(f), "%*s", 32 - strlen(de->d_name), ""); - hdr += f; - } - if (S_ISDIR(statbuf->st_mode)) { - snprintf(f, sizeof(f), "%s\r\n", timebuf); - hdr += f; - } - else { - snprintf(f, sizeof(f), "%s\r\n", timebuf); - hdr += f; - } - - *mResponseMessage += hdr; - } - closedir(dir); - snprintf(f, sizeof(f), "</PRE>\r\n<HR>\r\n<ADDRESS>%s</ADDRESS>\r\n</BODY></HTML>\r\n", SERVER); - *mResponseMessage += f; - - sendHeaders(200, "OK", NULL, "text/html", mResponseMessage->size(), statbuf->st_mtime); - - mRemLength = 0; - return OKAY; -} - - -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]; - - hdr += "<item>\n"; - // snprintf(f, sizeof(f), "%s - %s", ); - hdr += "<title>" + name +"</title>\n"; - hdr += "<link>" +link + "</link>\n"; - hdr += "<enclosure url=\"" +link + "\" type=\"video/mpeg\" />\n"; - - hdr += "<guid>" + guid + "</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", start); - hdr += "<start>"; - hdr += f; - hdr += "</start>\n"; - - snprintf(f, sizeof(f), "%d", dur); - hdr += "<duration>"; - hdr += f; - hdr += "</duration>\n"; - - if (fps != -1) - snprintf(f, sizeof(f), "<fps>%.2f</fps>\n", fps); - else - snprintf(f, sizeof(f), "<fps>unknown</fps>\n"); - hdr += f; - - switch (is_pes){ - case -1: - // unknown - hdr += "<ispes>unknown</ispes>\n"; - break; - case 0: - // true - hdr += "<ispes>true</ispes>\n"; - break; - case 1: - // false - hdr += "<ispes>false</ispes>\n"; - break; - default: - break; - } - - switch (is_new){ - case -1: - // unknown - hdr += "<isnew>unknown</isnew>\n"; - break; - case 0: - // true - hdr += "<isnew>true</isnew>\n"; - break; - case 1: - // false - hdr += "<isnew>false</isnew>\n"; - break; - default: - break; - } - - hdr += "</item>\n"; - - *mResponseMessage += hdr; - - - - - // return writeToClient(hdr.c_str(), hdr.size()); - return OKAY; -} - -int cHttpResource::parseQueryLine (vector<sQueryAVP> *avps) { - bool done = false; - size_t cur_pos = 0; - while (!done) { - size_t end_pos = mQuery.find('&', cur_pos); - size_t pos_eq = mQuery.find('=', cur_pos); - - if (pos_eq != cur_pos) { - avps->push_back(sQueryAVP(mQuery.substr(cur_pos, (pos_eq -cur_pos)), mQuery.substr(pos_eq+1, (end_pos -pos_eq-1)) )); - } - if (end_pos == string::npos) - done = true; - else - cur_pos = end_pos +1; - } - - return OKAY; -} - -int cHttpResource::getQueryAttributeValue(vector<sQueryAVP> *avps, string attr, string &val) { - int found = ERROR; - for (uint i = 0; i < avps->size(); i++) { - if ((*avps)[i].attribute == attr) { - val = (*avps)[i].value; - found = OKAY; - } -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " a= " - << (*avps)[i].attribute - << " v= " << (*avps)[i].value - << endl; -#endif - } - return found; -} - -int cHttpResource::parseFiles(vector<sFileEntry> *entries, string prefix, string dir_base, string dir_name, struct stat *statbuf) { - char pathbuf[4096]; - string link; - DIR *dir; - struct dirent *de; - string dir_comp; - dir_comp = dir_base + dir_name + "/"; - -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX - << " parseFiles: Prefix= " << prefix - << " base= " << dir_base - << " dir= " << dir_name - << " comp= " << dir_comp - << endl; -#endif - - dir = opendir(dir_comp.c_str()); - if (stat(dir_comp.c_str(), statbuf) < 0) - return ERROR; - - while ((de = readdir(dir)) != NULL) { - if ((strcmp(de->d_name, ".") == 0) or (strcmp(de->d_name, "..") == 0)) { - continue; - } - - strcpy(pathbuf, dir_comp.c_str()); - strcat(pathbuf, de->d_name); - - stat(pathbuf, statbuf); - - if (S_ISDIR(statbuf->st_mode)) { - if (strcmp(&(pathbuf[strlen(pathbuf)-4]), ".rec") == 0) { - // vdr folder - time_t now = time(NULL); - struct tm tm_r; - struct tm t = *localtime_r(&now, &tm_r); - t.tm_isdst = -1; - // char [20] rest; - int start = -1; - sscanf(de->d_name, "%4d-%02d-%02d.%02d.%02d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min); - - // sscanf(de->d_name, "%4d-%02d-%02d.%02d%.%02d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min); - t.tm_year -= 1900; - t.tm_mon--; - t.tm_sec = 0; - start = mktime(&t); - -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX - << " Vdr Folder Found: " << pathbuf << " start= " << start << endl; -#endif - - entries->push_back(sFileEntry(dir_name, pathbuf, start)); - } - else { - // regular file - parseFiles(entries, prefix + de->d_name + "~", dir_comp, de->d_name, statbuf); - } - } - else { - if ((de->d_name)[0] != '.' ) - entries->push_back(sFileEntry(prefix+de->d_name, pathbuf, 1)); - } - } - closedir(dir); - return OKAY; -} - -int cHttpResource::sendManifest (struct stat *statbuf, bool is_hls) { -#ifndef STANDALONE - - size_t pos = mPath.find_last_of ("/"); - - mDir = mPath.substr(0, pos); - string mpd_name = mPath.substr(pos+1); - - float seg_dur = mFactory->getConfig()->getSegmentDuration() *1.0; - - cRecordings* recordings = &Recordings; - cRecording* rec = recordings->GetByName(mDir.c_str()); - double duration = rec->NumFrames() / rec->FramesPerSecond(); - - int bitrate = (int)((getVdrFileSize() *8.0 * mFactory->getConfig()->getHasBitrateCorrection()/ duration) +0.5); - - time_t now = time(NULL); - - if (rec->Info() != NULL){ - if (rec->Info()->GetEvent() != NULL) { - if (rec->Info()->GetEvent()->EndTime() > now) { - - float corr = (now - rec->Info()->GetEvent()->StartTime()) - duration; - duration = rec->Info()->GetEvent()->Duration() -int(corr); - *(mLog->log()) << DEBUGPREFIX - << " is Recording: Duration= " << duration << " sec" - << " correction: " << int(corr) - << endl; - } - } - else - *(mLog->log()) << DEBUGPREFIX << " WARNING: rec-Info()->GetEvent() is NULL " << endl; - } - else - *(mLog->log()) << DEBUGPREFIX << " WARNING: rec-Info() is NULL " << endl; - - // duration is now either the actual duration of the asset or the target duration of the asset - int end_seg = int (duration / seg_dur) +1; - - *(mLog->log()) << DEBUGPREFIX - << " Manifest for mDir= " << mDir - << " duration= " << duration - << " seg_dur= " << seg_dur - << " end_seg= " << end_seg - << endl; - - - - if (is_hls) { - writeM3U8(duration, bitrate, seg_dur, end_seg); - } - else { - writeMPD(duration, bitrate, seg_dur, end_seg); - } - -#endif - return OKAY; -} - -void cHttpResource::writeM3U8(double duration, int bitrate, float seg_dur, int end_seg) { - mResponseMessage = new string(); - mResponseMessagePos = 0; - *mResponseMessage = ""; - mContentType = MEMBLOCK; - - mConnState = SERVING; - char buf[30]; - - string hdr = ""; - - - *mResponseMessage += "#EXTM3U\n"; - // snprintf(buf, sizeof(buf), "#EXT-X-TARGETDURATION:%d\n", (seg_dur-1)); - snprintf(buf, sizeof(buf), "#EXT-X-TARGETDURATION:%d\n", int(seg_dur)); - hdr = buf; - *mResponseMessage += hdr; - - *mResponseMessage += "#EXT-X-MEDIA-SEQUENCE:1\n"; - *mResponseMessage += "#EXT-X-KEY:METHOD=NONE\n"; - - for (int i = 1; i < end_seg; i++){ - // snprintf(buf, sizeof(buf), "#EXTINF:%.1f,\n", (seg_dur-0.5)); - snprintf(buf, sizeof(buf), "#EXTINF:%.2f,\n", seg_dur); - hdr = buf; - *mResponseMessage += hdr; - - snprintf(buf, sizeof(buf), "%d-seg.ts\n", i); - hdr = buf; - *mResponseMessage += hdr; - } - *mResponseMessage += "#EXT-X-ENDLIST\n"; - - sendHeaders(200, "OK", NULL, "application/x-mpegURL", mResponseMessage->size(), -1); -} - - -void cHttpResource::writeMPD(double duration, int bitrate, float seg_dur, int end_seg) { - mResponseMessage = new string(); - mResponseMessagePos = 0; - *mResponseMessage = ""; - mContentType = MEMBLOCK; - - mConnState = SERVING; - char buf[30]; - char line[400]; - - string hdr = ""; - - *mResponseMessage += "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"; - - snprintf(line, sizeof(line), "<MPD type=\"OnDemand\" minBufferTime=\"PT%dS\" mediaPresentationDuration=\"PT%.1fS\"", - mFactory->getConfig()->getHasMinBufferTime(), duration); - *mResponseMessage = *mResponseMessage + line; - - *mResponseMessage += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"urn:mpeg:mpegB:schema:DASH:MPD:DIS2011\" "; - *mResponseMessage += "xsi:schemaLocation=\"urn:mpeg:mpegB:schema:DASH:MPD:DIS2011\">\n"; - *mResponseMessage += "<ProgramInformation>\n"; - *mResponseMessage += "<ChapterDataURL/>\n"; - *mResponseMessage += "</ProgramInformation>\n"; - *mResponseMessage += "<Period start=\"PT0S\" segmentAlignmentFlag=\"True\">\n"; - // SD: 720x 576 - // HD: 1280x 720 - // snprintf(line, sizeof(line), "<Representation id=\"0\" mimeType=\"video/mpeg\" bandwidth=\"%d\" startWithRAP=\"True\" width=\"1280\" height=\"720\" group=\"0\">\n", mFactory->getConfig()->getHasBitrate()); - snprintf(line, sizeof(line), "<Representation id=\"0\" mimeType=\"video/mpeg\" bandwidth=\"%d\" startWithRAP=\"True\" %s group=\"0\">\n", - bitrate, ((bitrate < 10000000)? "width=\"720\" height=\"576\"" : "width=\"1280\" height=\"720\"")); - *mResponseMessage = *mResponseMessage + line; - - hdr = "<SegmentInfo duration="; - snprintf(buf, sizeof(buf), "\"PT%.1fS\"", (seg_dur*1.0)); - hdr = hdr + buf + " >\n"; - *mResponseMessage += hdr; - - snprintf(buf, sizeof(buf), "\"%d\"", end_seg); - *mResponseMessage += "<UrlTemplate sourceURL=\"$Index$-seg.ts\" startIndex=\"1\" endIndex="; - hdr = buf ; - *mResponseMessage += hdr + " />\n"; - - *mResponseMessage += "</SegmentInfo>\n"; - *mResponseMessage += "</Representation>\n"; - *mResponseMessage += "</Period>\n"; - *mResponseMessage += "</MPD>"; - - sendHeaders(200, "OK", NULL, "application/x-mpegURL", mResponseMessage->size(), -1); -} - -int cHttpResource::sendMediaSegment (struct stat *statbuf) { -#ifndef STANDALONE - - *(mLog->log()) << DEBUGPREFIX << " sendMediaSegment " << mPath << endl; - size_t pos = mPath.find_last_of ("/"); - - mDir = mPath.substr(0, pos); - string seg_name = mPath.substr(pos+1); - int seg_number; - - int seg_dur = mFactory->getConfig()->getSegmentDuration(); - int frames_per_seg = 0; - - sscanf(seg_name.c_str(), "%d-seg.ts", &seg_number); - - //FIXME: Do some consistency checks on the seg_number - //* Does the segment exist - - cRecordings* recordings = &Recordings; - cRecording* rec = recordings->GetByName(mDir.c_str()); - if (rec != NULL) { - frames_per_seg = seg_dur * rec->FramesPerSecond(); - } - else { - *(mLog->log()) << DEBUGPREFIX << " ERROR: Ooops, rec is NULL, assuming 25 fps " << endl; - frames_per_seg = seg_dur * 25; - } - //FIXME: HD Fix - // frames_per_seg = seg_dur * 25; - - *(mLog->log()) << DEBUGPREFIX - << " mDir= " << mDir - << " seg_name= " << seg_name - << " seg_number= "<< seg_number - << " fps= " << rec->FramesPerSecond() - << " frames_per_seg= " << frames_per_seg - << endl; - int start_frame_count = (seg_number -1) * frames_per_seg; - - FILE* idx_file = fopen((mDir +"/index").c_str(), "r"); - if (idx_file == NULL){ - *(mLog->log()) << DEBUGPREFIX - << " failed to open idx file = "<< (mDir +"/index").c_str() - << endl; - sendError(404, "Not Found", NULL, "Failed to open Index file"); - return OKAY; - } - - char *index_buf = new char[(frames_per_seg +3) *8]; - - // fseek to start_frame_count * sizeof(in_read) - fseek(idx_file, start_frame_count * 8, SEEK_SET); - - // read to (seg_number * frames_per_seg +1) * sizeof(in_read) - // buffersize is frames_per_seg * seg_number * sizeof(in_read) - int buffered_indexes = fread(index_buf, 8, (frames_per_seg +2), idx_file); - - fclose(idx_file); - - if(buffered_indexes <= 0 ) { - *(mLog->log())<<DEBUGPREFIX - << " issue while reading" << endl; - delete[] index_buf; - sendError(404, "Not Found", NULL, "Failed to read Index file"); - return OKAY; - } - - // Reading the segment - mFileStructure = "%s/%05d.ts"; - int start_offset = -1; - int start_idx = -1; - - tIndexTs in_read_ts; - memcpy (&in_read_ts, &(index_buf[0]), 8); - - start_offset = in_read_ts.offset; - start_idx = in_read_ts.number; - - char seg_fn[200]; - mVdrIdx = start_idx; - - snprintf(seg_fn, sizeof(seg_fn), mFileStructure.c_str(), mDir.c_str(), mVdrIdx); - mPath = seg_fn; - - /* - * Now we determine the end of the segment - */ - memcpy (&in_read_ts, &(index_buf[(frames_per_seg)*8]), 8); - - int end_idx = in_read_ts.number; - int end_offset = in_read_ts.offset; - - /*#ifndef DEBUG*/ - *(mLog->log()) << DEBUGPREFIX - << " GenSegment: start (no/idx)= " << start_idx << " / " << start_offset - << " to (no/idx)= " << end_idx << " / " << end_offset - << endl; - /*#endif*/ - - delete[] index_buf; - - int rem_len = 0; - bool error = false; - if (start_idx == end_idx){ - mRemLength = (end_offset - start_offset); - -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX - << " start_idx == end_idx: mRemLength= " <<mRemLength - << endl; -#endif - } - else { -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX - << " start_idx < end_idx " - << endl; -#endif - snprintf(seg_fn, sizeof(seg_fn), mFileStructure.c_str(), mDir.c_str(), mVdrIdx); - if (stat(seg_fn, statbuf) < 0) { - *(mLog->log()) << DEBUGPREFIX - << " file= " <<seg_fn << " does not exist" - << endl; - error= true; - // issue: - } - rem_len = statbuf->st_size - start_offset; // remaining length of the first segment - - // loop over all idx files between start_idx and end_idx - for (int idx = (start_idx+1); idx < end_idx; idx ++) { - snprintf(seg_fn, sizeof(seg_fn), mFileStructure.c_str(), mDir.c_str(), idx); - if (stat(seg_fn, statbuf) < 0) { - *(mLog->log()) << DEBUGPREFIX - << " for loop file= " <<seg_fn << " does not exist" - << endl; - error = true; - break; - // issue: - } - rem_len += statbuf->st_size; // remaining length of the first segment - } - rem_len += end_offset; // - mRemLength = rem_len; - snprintf(seg_fn, sizeof(seg_fn), mFileStructure.c_str(), mDir.c_str(), mVdrIdx); - -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX - << " start_idx= " << start_idx << " != end_idx= "<< end_idx <<": mRemLength= " <<mRemLength - << endl; -#endif - } - - if (error){ - sendError(404, "Not Found", NULL, "Not all inputs exists"); - return OKAY; - } - - mContentType = VDRDIR; - - if (openFile(seg_fn) != OKAY) { - *(mLog->log())<< DEBUGPREFIX << " Failed to open file= " << seg_fn - << " mRemLength= " << mRemLength<< endl; - sendError(404, "Not Found", NULL, "File not found."); - return OKAY; - } - fseek(mFile, start_offset, SEEK_SET); - - sendHeaders(200, "OK", NULL, "video/mpeg", mRemLength, -1); - -#endif - return OKAY; -} - -int cHttpResource::sendMediaXml (struct stat *statbuf) { - char pathbuf[4096]; - string link; - string media_folder = mFactory->getConfig()->getMediaFolder(); - - mResponseMessage = new string(); - mResponseMessagePos = 0; - *mResponseMessage = ""; - mContentType = MEMBLOCK; - - mConnState = SERVING; - -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX << " sendMedia " << endl; -#endif - - string own_ip = getOwnIp(mFd); - *(mLog->log()) << " OwnIP= " << own_ip << endl; - - vector<sFileEntry> entries; - - if (parseFiles(&entries, "", media_folder, "", statbuf) == ERROR) { - sendError(404, "Not Found", NULL, "Media Folder likely not configured."); - return OKAY; - } - - string hdr = ""; - hdr += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - hdr += "<rss version=\"2.0\">\n"; - hdr+= "<channel>\n"; - - *mResponseMessage += hdr; - - hdr = ""; - - 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", own_ip.c_str(), mServerPort, - cUrlEncode::doUrlSaveEncode(entries[i].sPath).c_str()); - if (writeXmlItem(cUrlEncode::doXmlSaveEncode(entries[i].sName), pathbuf, "NA", "NA", "-", - -1, entries[i].sStart, -1, -1, -1, -1) == ERROR) - return ERROR; - - } - - hdr = "</channel>\n"; - hdr += "</rss>\n"; - *mResponseMessage += hdr; - sendHeaders(200, "OK", NULL, "application/xml", mResponseMessage->size(), statbuf->st_mtime); - - return OKAY; -} - -int cHttpResource::sendVdrStatusXml (struct stat *statbuf) { - -#ifndef STANDALONE - - char f[400]; - mResponseMessage = new string(); - *mResponseMessage = ""; - mResponseMessagePos = 0; - mContentType = MEMBLOCK; - - mConnState = SERVING; - - int free; - int used; - int percent; - - percent = VideoDiskSpace(&free, &used); - - *mResponseMessage += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - *mResponseMessage += "<vdrstatus>\n"; - - *mResponseMessage += "<diskspace>\n"; - snprintf(f, sizeof(f), "<free>%d</free>", free); - *mResponseMessage += f; - - snprintf(f, sizeof(f), "<used>%d</used>", used); - *mResponseMessage += f; - snprintf(f, sizeof(f), "<percent>%d</percent>", percent); - *mResponseMessage += f; - *mResponseMessage += "</diskspace>\n"; - - *mResponseMessage += "</vdrstatus>\n"; - - sendHeaders(200, "OK", NULL, "application/xml", mResponseMessage->size(), -1); - -#endif - return OKAY; -} - -int cHttpResource::sendEpgXml (struct stat *statbuf) { -#ifndef STANDALONE - - char f[400]; - mResponseMessage = new string(); - *mResponseMessage = ""; - mResponseMessagePos = 0; - mContentType = MEMBLOCK; - - mConnState = SERVING; - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " generating /epg.xml" - << DEBUGHDR << endl; -#endif - vector<sQueryAVP> avps; - parseQueryLine(&avps); - string id = "S19.2E-1-1107-17500"; - string mode = ""; - bool add_desc = true; - - if (getQueryAttributeValue(&avps, "id", id) == ERROR){ - *(mLog->log())<< DEBUGPREFIX - << " ERROR: id not found" - << DEBUGHDR << endl; - delete mResponseMessage; - sendError(400, "Bad Request", NULL, "no id in query line"); - return OKAY; - } - - if (getQueryAttributeValue(&avps, "mode", mode) == OKAY){ - if (mode == "nodesc") { - add_desc = false; - *(mLog->log())<< DEBUGPREFIX - << " **** Mode: No Description ****" - << endl; - } - } - - /* for (int i = 0; i < avps.size(); i++) { - if (avps[i].attribute == "id") - id = avps[i].value; - *(mLog->log())<< DEBUGPREFIX - << " a= " - << avps[i].attribute - << " v= " << avps[i].value - << endl; - }*/ - tChannelID chan_id = tChannelID::FromString (id.c_str()); - if ( chan_id == tChannelID::InvalidID) { - *(mLog->log())<< DEBUGPREFIX - << " ERROR: Not possible to get the ChannelId from the string" - << DEBUGHDR << endl; - delete mResponseMessage; - sendError(400, "Bad Request", NULL, "Invalid Channel ID."); - return OKAY; - } - - cSchedulesLock * lock = new cSchedulesLock(false, 500); - const cSchedules *schedules = cSchedules::Schedules(*lock); - - const cSchedule *schedule = schedules->GetSchedule(chan_id); - if (schedule == NULL) { - *(mLog->log())<< DEBUGPREFIX - << "ERROR: Schedule is zero for guid= " << id - << endl; - delete mResponseMessage; - sendError(500, "Internal Server Error", NULL, "Schedule is zero."); - return OKAY; - } - - time_t now = time(NULL); - const cEvent *ev = NULL; - for(cEvent* e = schedule->Events()->First(); e; e = schedule->Events()->Next(e)) { - if ( (e->StartTime() <= now) && (e->EndTime() > now)) { - ev = e; - - } else if (e->StartTime() > now + 3600) { - break; - } - } - - // const cEvent * ev = schedule->GetPresentEvent(); - - if (ev == NULL) { - *(mLog->log())<< DEBUGPREFIX - << "ERROR: Event is zero for guid= " << id - << endl; - delete mResponseMessage; - sendError(500, "Internal Server Error", NULL, "Event is zero."); - return OKAY; - } - - string hdr = ""; - hdr += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - hdr += "<tv version=\"2.0\">\n"; - hdr+= "<programme>\n"; - - *mResponseMessage += hdr; - // Payload here - - hdr = ""; - if (ev->Title() != NULL) { - string title = cUrlEncode::doXmlSaveEncode(ev->Title()); - hdr += "<title>" + title +"</title>\n"; - } - else { - *(mLog->log())<< DEBUGPREFIX - << " ERROR: title is zero for guid= " << id << endl; - hdr += "<title>Empty</title>\n"; - - delete mResponseMessage; - sendError(500, "Internal Server Error", NULL, "Title is zero."); - return OKAY; - } - - hdr += "<guid>" + id + "</guid>\n"; - - *(mLog->log())<< DEBUGPREFIX - << " guid= " << id - << " title= " << ev->Title() - << " start= " << ev->StartTime() - << " end= " << ev->EndTime() - << " now= " << now - << endl; - if (add_desc) { - hdr += "<desc>"; - if (ev->Description() != NULL) { - hdr += cUrlEncode::doXmlSaveEncode(ev->Description()); - } - else { - *(mLog->log())<< DEBUGPREFIX - << " ERROR: description is zero for guid= " << id << endl; - - delete mResponseMessage; - sendError(500, "Internal Server Error", NULL, "Description is zero."); - return OKAY; - } - hdr += "</desc>\n"; - } - else { - hdr += "<desc>No Description Available</desc>\n"; - } - snprintf(f, sizeof(f), "<start>%ld</start>\n", ev->StartTime()); - hdr += f ; - - snprintf(f, sizeof(f), "<end>%ld</end>\n", ev->EndTime()); - hdr += f; - - snprintf(f, sizeof(f), "<duration>%d</duration>\n", ev->Duration()); - hdr += f; - *mResponseMessage += hdr; - - hdr = "</programme>\n"; - hdr += "</tv>\n"; - - *mResponseMessage += hdr; - - delete lock; - - sendHeaders(200, "OK", NULL, "application/xml", mResponseMessage->size(), -1); - -#endif - return OKAY; -} - -int cHttpResource::sendChannelsXml (struct stat *statbuf) { -#ifndef STANDALONE - - char f[400]; - mResponseMessage = new string(); - *mResponseMessage = ""; - mResponseMessagePos = 0; - mContentType = MEMBLOCK; - - mConnState = SERVING; - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " generating /channels.xml" - << DEBUGHDR << endl; -#endif - string own_ip = getOwnIp(mFd); - *(mLog->log()) << " OwnIP= " << own_ip << endl; - - vector<sQueryAVP> avps; - parseQueryLine(&avps); - string mode = ""; - bool add_desc = true; - - string no_channels_str = ""; - int no_channels = -1; - string group_sep = ""; - - if (getQueryAttributeValue(&avps, "mode", mode) == OKAY){ - if (mode == "nodesc") { - add_desc = false; - *(mLog->log())<< DEBUGPREFIX - << " Mode: No Description" - << endl; - } - else { - *(mLog->log())<< DEBUGPREFIX - << " Mode: Unknown" - << endl; - } - } - if (getQueryAttributeValue(&avps, "channels", no_channels_str) == OKAY){ - no_channels = atoi(no_channels_str.c_str()) ; - } - - - string hdr = ""; - hdr += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - hdr += "<rss version=\"2.0\">\n"; - hdr+= "<channel>\n"; - hdr+= "<title>VDR Channels List</title>\n"; - - - *mResponseMessage += hdr; - - int count = mFactory->getConfig()->getLiveChannels(); - if (no_channels > 0) - count = no_channels +1; - - cSchedulesLock * lock = new cSchedulesLock(false, 500); - const cSchedules *schedules = cSchedules::Schedules(*lock); - - for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) { - if (channel->GroupSep()) { - 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", own_ip.c_str(), *(channel->GetChannelID()).ToString()); - string link = f; - - const cSchedule *schedule = schedules->GetSchedule(channel->GetChannelID()); - string desc = "No description available"; - string title = "Not available"; - time_t start_time = 0; - int duration = 0; - - if (schedule != NULL) { - const cEvent *ev = schedule->GetPresentEvent(); - if (ev != NULL) { - if ((ev->Description() != NULL) && add_desc) - desc = cUrlEncode::doXmlSaveEncode(ev->Description()); - - if ((ev->Title() != NULL) && add_desc) - title = cUrlEncode::doXmlSaveEncode(ev->Title()); - start_time = ev->StartTime(); - duration = ev->Duration(); - } - else { - *(mLog->log())<< DEBUGPREFIX - << " Event Info is Zero for Count= " - << count - << " Name= " << channel->Name() << endl; - } - } - else { - *(mLog->log())<< DEBUGPREFIX - << " Schedule is Zero for Count= " - << count - << " Name= " << channel->Name() << endl; - } - - 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(), channel->Number(), start_time, duration, -1, -1, -1) == ERROR) - return ERROR; - - } - - hdr = "</channel>\n"; - hdr += "</rss>\n"; - - *mResponseMessage += hdr; - delete lock; - sendHeaders(200, "OK", NULL, "application/xml", mResponseMessage->size(), statbuf->st_mtime); - -#endif - return OKAY; -} - -int cHttpResource::receiveResume() { - string dev_id; - cResumeEntry entry; - if (parseResume(entry, dev_id) == ERROR) { - *(mLog->log())<< DEBUGPREFIX - << " ERROR parsing resume" - << endl; - } - - *(mLog->log())<< DEBUGPREFIX - << " Resume: id= " << dev_id - << " resume= " << entry << endl; - - vector<sQueryAVP> avps; - parseQueryLine(&avps); - string guid; - string resume_str; - - if (getQueryAttributeValue(&avps, "guid", guid) == OKAY){ - entry.mFilename = guid; - *(mLog->log())<< DEBUGPREFIX - << " Found a id Parameter: " << guid - << endl; - } - if (getQueryAttributeValue(&avps, "resume", resume_str) == OKAY){ - entry.mResume = atof(resume_str.c_str()); - *(mLog->log())<< DEBUGPREFIX - << " Found a resume Parameter: " << entry.mResume - << endl; - } - - - - -#ifndef STANDALONE - cRecording *rec = Recordings.GetByName(entry.mFilename.c_str()); - if (rec == NULL) { - //Error 404 - sendError(404, "Not Found", NULL, "Failed to find recording."); - return OKAY; - } - - cResumeFile resume(entry.mFilename.c_str(), rec->IsPesRecording()); - *(mLog->log())<< DEBUGPREFIX - << " Resume: " << entry.mFilename - << " saving Index= " << int(entry.mResume * rec->FramesPerSecond() ) - << " mResume= " <<entry.mResume - << " fpr= " << rec->FramesPerSecond() - << endl; - - resume.Save(int(entry.mResume * rec->FramesPerSecond() )); -#endif - - sendHeaders(200, "OK", NULL, NULL, -1, -1); - return OKAY; -} - -//int cHttpResource::sendResumeXml (struct stat *statbuf) { -int cHttpResource::sendResumeXml () { -#ifndef STANDALONE - - mResponseMessage = new string(); - *mResponseMessage = ""; - mResponseMessagePos = 0; - mContentType = MEMBLOCK; - - mConnState = SERVING; - - char f[400]; - - cResumeEntry entry; - string id; - - parseResume(entry, id); - - vector<sQueryAVP> avps; - parseQueryLine(&avps); - string guid; - - if (getQueryAttributeValue(&avps, "guid", guid) == OKAY){ - entry.mFilename = guid; - *(mLog->log())<< DEBUGPREFIX - << " Found a id Parameter: " << guid - << endl; - } - - - cRecording *rec = Recordings.GetByName(entry.mFilename.c_str()); - if (rec == NULL) { - //Error 404 - *(mLog->log())<< DEBUGPREFIX - << " sendResume: File Not Found filename= " << entry.mFilename << endl; - sendError(404, "Not Found", NULL, "Failed to find recording."); - return OKAY; - } - if (rec->IsNew()) { - *(mLog->log())<< DEBUGPREFIX - << " sendResume: file is new " << endl; - sendError(400, "Bad Request", NULL, "File is new."); - return OKAY; - } - cResumeFile resume(entry.mFilename.c_str(), rec->IsPesRecording()); - - *(mLog->log())<< DEBUGPREFIX - << " resume request for " << entry.mFilename - << " resume= " << resume.Read() - << " (" << resume.Read() *1.0 / rec->FramesPerSecond() << "sec)" - << endl; - - *mResponseMessage += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - *mResponseMessage += "<resume>"; - snprintf(f, sizeof(f), "%.02f", resume.Read() *1.0 / rec->FramesPerSecond()); - *mResponseMessage += f; - *mResponseMessage += "</resume>\n"; - - - sendHeaders(200, "OK", NULL, "application/xml", mResponseMessage->size(), -1); - - return OKAY; -#endif -} - -int cHttpResource::deleteRecording() { - vector<sQueryAVP> avps; - parseQueryLine(&avps); - string id = ""; - - if (getQueryAttributeValue(&avps, "id", id) == ERROR){ - *(mLog->log())<< DEBUGPREFIX - << " ERROR: id not found in query." - << DEBUGHDR << endl; - sendError(400, "Bad Request", NULL, "no id in query line"); - return OKAY; - } - mPath = cUrlEncode::doUrlSaveDecode(id); - - 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; - } - if ( rec->Delete() ) { - Recordings.DelByName(rec->FileName()); - // 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; -} - - -int cHttpResource::sendRecordingsXml(struct stat *statbuf) { -#ifndef STANDALONE - - mResponseMessage = new string(); - *mResponseMessage = ""; - mResponseMessagePos = 0; - mContentType = MEMBLOCK; - - mConnState = SERVING; - - string own_ip = getOwnIp(mFd); - *(mLog->log()) << " OwnIP= " << own_ip << endl; - - vector<sQueryAVP> avps; - parseQueryLine(&avps); - string model = ""; - string link_ext = ""; - string type = ""; - string has_4_hd_str = ""; - bool has_4_hd = true; - string mode = ""; - bool add_desc = true; - - if (getQueryAttributeValue(&avps, "model", model) == OKAY){ - *(mLog->log())<< DEBUGPREFIX - << " Found a Model Parameter: " << model - << endl; - } - - if (getQueryAttributeValue(&avps, "type", type) == OKAY){ - *(mLog->log())<< DEBUGPREFIX - << " Found a Type Parameter: " << type - << endl; - if (type == "hls") { - if (model == "samsung") - link_ext = "/manifest-seg.m3u8|COMPONENT=HLS"; - else - link_ext = "/manifest-seg.m3u8"; - } - if (type == "has") { - if (model == "samsung") - link_ext = "/manifest-seg.mpd|COMPONENT=HAS"; - else - link_ext = "/manifest-seg.mpd"; - } - } - - if (getQueryAttributeValue(&avps, "mode", mode) == OKAY){ - if (mode == "nodesc") { - add_desc = false; - *(mLog->log())<< DEBUGPREFIX - << " Mode: No Description" - << endl; - } - } - - if (getQueryAttributeValue(&avps, "has4hd", has_4_hd_str) == OKAY){ - *(mLog->log())<< DEBUGPREFIX - << " Found a Has4Hd Parameter: " << has_4_hd_str - << endl; - if (has_4_hd_str == "false") - has_4_hd = false; - } - - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " generating /recordings.xml" - << DEBUGHDR << endl; -#endif - sendHeaders(200, "OK", NULL, "application/xml", -1, statbuf->st_mtime); - - 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"; - - *mResponseMessage += hdr; - - /* - if (writeXmlItem("HAS - Big Bugs Bunny", "http://192.168.1.122/sm/BBB-DASH/HAS_BigBuckTS.xml|COMPONENT=HAS", "NA", "Big Bucks Bunny - HAS", - "-", 0, 0) == ERROR) - return ERROR; - - if (writeXmlItem("HLS - Big Bugs Bunny", "http://192.168.1.122/sm/BBB-DASH/HLS_BigBuckTS.m3u8|COMPONENT=HLS", "NA", "Big Bucks Bunny - HLS", - "-", 0, 0) == ERROR) - return ERROR; - if (writeXmlItem("HAS - Big Bugs Bunny", "http://192.168.1.122:8000/hd2/mpeg/BBB-DASH/HAS_BigBuckTS.xml|COMPONENT=HAS", "NA", "Big Bucks Bunny - HAS from own Server", - "-", 0, 0) == ERROR) - return ERROR; -*/ - //-------------------- - cRecordings* recordings = &Recordings; - char f[600]; - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " recordings->Count()= " << recordings->Count() - << DEBUGHDR << endl; -#endif - - // List of recording timer - time_t now = time(NULL); - - vector<sTimerEntry> act_rec; - /*#ifndef DEBUG*/ - *(mLog->log())<< DEBUGPREFIX - << " checking avtive timer" - << endl; - /*#endif*/ - for (cTimer * ti = Timers.First(); ti; ti = Timers.Next(ti)){ - ti->Matches(); - - /* *(mLog->log()) << DEBUGPREFIX - << " Active Timer: " << ti->File() - << " EvStart= " << ti->Event()->StartTime() - << " EvDuration= " << ti->Event()->Duration() - << endl;*/ - /* *(mLog->log()) << DEBUGPREFIX - << " TiStart= " << ti->StartTime() - << " TiDuration= " << (ti->StopTime() - ti->StartTime()) - << 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() - << " Duration= " << ti->Event()->Duration() - << endl; -*/ - *(mLog->log()) << DEBUGPREFIX - << " Active Timer: " << ti->File() - << " Start= " << ti->StartTime() - << " Duration= " << (ti->StopTime() - ti->StartTime()) - << endl; - // act_rec.push_back(sTimerEntry(ti->File(), ti->Event()->StartTime(), ti->Event()->Duration())); - act_rec.push_back(sTimerEntry(ti->File(), ti->StartTime(), (ti->StopTime() - ti->StartTime()))); - } - } - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " Found " << act_rec.size() - << " running timers" - << endl; -#endif - - int rec_dur = 0; - for (cRecording *recording = recordings->First(); recording; recording = recordings->Next(recording)) { - 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", 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", own_ip.c_str(), mServerPort, - cUrlEncode::doUrlSaveEncode(recording->FileName()).c_str(), link_ext.c_str()); - - string link = f; - string desc = "No description available"; - rec_dur = recording->LengthInSeconds(); - - string name = recording->Name(); - - for (uint x = 0; x < act_rec.size(); x++) { - if (act_rec[x].name == name) { - - /* *(mLog->log())<< DEBUGPREFIX - << " !!!!! Found active Recording !!! " - << endl; -*/ - rec_dur += (act_rec[x].startTime + act_rec[x].duration - now); - - - } - } // for - - if (recording->Info() != NULL) { - if ((recording->Info()->Description() != NULL) && add_desc) { - desc = cUrlEncode::doXmlSaveEncode(recording->Info()->Description()); - } - } - - if (writeXmlItem(cUrlEncode::doXmlSaveEncode(recording->Name()), link, "NA", desc, - cUrlEncode::doUrlSaveEncode(recording->FileName()).c_str(), - -1, - recording->Start(), rec_dur, recording->FramesPerSecond(), - (recording->IsPesRecording() ? 0: 1), (recording->IsNew() ? 0: 1)) == ERROR) - // Better Internal Server Error - return ERROR; - - } - - hdr = "</channel>\n"; - hdr += "</rss>\n"; - - *mResponseMessage += hdr; - - -#endif - return OKAY; -} - -bool cHttpResource::isTimeRequest(struct stat *statbuf) { - - vector<sQueryAVP> avps; - parseQueryLine(&avps); - string time_str = ""; - string mode = ""; - float time = 0.0; - - if (getQueryAttributeValue(&avps, "time", time_str) != OKAY){ - return false; - } - - if (getQueryAttributeValue(&avps, "mode", mode) == OKAY){ - if (mode.compare ("streamtoend") ==0) { - mStreamToEnd = true; - } - } - - if (mIsRecording) - mStreamToEnd = true; - - time = atof(time_str.c_str()); - *(mLog->log())<< DEBUGPREFIX - << " Found a Time Parameter: " << time - << " streamToEnd= " << ((mStreamToEnd) ? "true" : "false") - << endl; - - mDir = mPath; - cRecording *rec = Recordings.GetByName(mPath.c_str()); - if (rec == NULL) { - *(mLog->log())<< DEBUGPREFIX - << " Error: Did not find recording= " << mPath << endl; - sendError(404, "Not Found", NULL, "File not found."); - return true; - } - - double fps = rec->FramesPerSecond(); - double dur = rec->NumFrames() * fps; - bool is_pes = rec->IsPesRecording(); - if (dur < time) { - sendError(400, "Bad Request", NULL, "Time to large."); - return true; - } - - int start_frame = int(time * fps) -25; - - FILE* idx_file= NULL; - - if (is_pes){ - idx_file = fopen((mDir +"/index.vdr").c_str(), "r"); - // sendError(400, "Bad Request", NULL, "PES not yet supported."); - // return true; - } - else { - idx_file = fopen((mDir +"/index").c_str(), "r"); - } - - if (idx_file == NULL){ - *(mLog->log()) << DEBUGPREFIX - << " failed to open idx file = "<< (mDir +"/index").c_str() - << endl; - sendError(404, "Not Found", NULL, "Failed to open Index file"); - return OKAY; - } - - int buffered_frames = 50; - char *index_buf = new char[8 *buffered_frames]; // 50 indexes - - *(mLog->log()) << DEBUGPREFIX - << " seeking to start_frame= " << start_frame - << " fps= " << fps << endl; - fseek(idx_file, start_frame * 8, SEEK_SET); - - int buffered_indexes = fread(index_buf, 8, (buffered_frames), idx_file); - - fclose(idx_file); - - if(buffered_indexes <= 0 ) { - *(mLog->log())<<DEBUGPREFIX - << " issue while reading, buffered_indexes <=0" << endl; - delete[] index_buf; - sendError(404, "Not Found", NULL, "Failed to read Index file"); - return OKAY; - } - - *(mLog->log()) << DEBUGPREFIX - << " Finding I-Frame now" << endl; - - - bool found_it = false; - int i = 0; - - uint32_t offset = 0; - int idx =0; - int type =0; - - for (i= 0; i < buffered_indexes; i++){ - if (is_pes) { - tIndexPes in_read_pes; - memcpy (&in_read_pes, &(index_buf[i*8]), 8); - type = in_read_pes.type == 1; - idx = in_read_pes.number; - offset = in_read_pes.offset; - } - else{ - tIndexTs in_read_ts; - memcpy (&in_read_ts, &(index_buf[i*8]), 8); - type = in_read_ts.independent; - idx = in_read_ts.number; - offset = in_read_ts.offset; - } - - *(mLog->log()) << DEBUGPREFIX - << " Frame= " << i - << " idx= "<< idx - << " offset= " << offset - << " type= " << type - << endl; - if (type){ - found_it = true; - break; - } - } - - if (!found_it) { - delete[] index_buf; - sendError(404, "Not Found", NULL, "Failed to read Index file"); - return OKAY; - } - - mVdrIdx = idx; - - *(mLog->log()) << DEBUGPREFIX - << " idx= "<< mVdrIdx - << " offset= " << offset - << endl; - - delete[] index_buf; - - char pathbuf[4096]; - snprintf(pathbuf, sizeof(pathbuf), mFileStructure.c_str(), mPath.c_str(), mVdrIdx); - - *(mLog->log()) << DEBUGPREFIX - << " Opening Path= " - << pathbuf << endl; - if (openFile(pathbuf) != OKAY) { - sendError(403, "Forbidden", NULL, "Access denied."); - return true; - } - - fseek(mFile, offset, SEEK_SET); - - if (mStreamToEnd) { - sendHeaders(200, "OK", NULL, "video/mpeg", -1, -1); - return true; - } - - uint64_t file_size = 0; - bool more_to_go = true; - int vdr_idx = mVdrIdx; - while (more_to_go) { - snprintf(pathbuf, sizeof(pathbuf), mFileStructure.c_str(), mPath.c_str(), vdr_idx); - if (stat(pathbuf, statbuf) >= 0) { - *(mLog->log())<< " found for " << pathbuf << endl; - file_size += statbuf->st_size; - } - else { - more_to_go = false; - } - vdr_idx ++; - } - mRemLength = file_size - offset; - - *(mLog->log()) << DEBUGPREFIX - << " Done. Start Streaming " - << endl; - - if (rangeHdr.isRangeRequest) { - snprintf(pathbuf, sizeof(pathbuf), "Content-Range: bytes 0-%lld/%lld", (mRemLength -1), mRemLength); - sendHeaders(206, "Partial Content", pathbuf, "video/mpeg", mRemLength, statbuf->st_mtime); - } - else { - sendHeaders(200, "OK", NULL, "video/mpeg", mRemLength, -1); - } - return true; -} - -int cHttpResource::sendVdrDir(struct stat *statbuf) { - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX << " *** sendVdrDir mPath= " << mPath << endl; -#endif - char pathbuf[4096]; - char f[400]; - int vdr_idx = 0; - uint64_t total_file_size = 0; - // int ret = OKAY; - string vdr_dir = mPath; - vector<sVdrFileEntry> file_sizes; - bool more_to_go = true; - - checkRecording(); - - mVdrIdx = 1; - mFileStructure = "%s/%03d.vdr"; - - snprintf(pathbuf, sizeof(pathbuf), mFileStructure.c_str(), mPath.c_str(), 1); - if (stat(pathbuf, statbuf) < 0) { - mFileStructure = "%s/%05d.ts"; -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX << " using dir format: " << mFileStructure.c_str() << endl; -#endif - } - - // The range request functions are activated, when a time header is detected - if (isTimeRequest(statbuf)) { - *(mLog->log())<< DEBUGPREFIX - << " isTimeRequest is true" - << endl; - return OKAY; - } - - // --- looup all vdr files in the dir --- - while (more_to_go) { - vdr_idx ++; - snprintf(pathbuf, sizeof(pathbuf), mFileStructure.c_str(), mPath.c_str(), vdr_idx); - if (stat(pathbuf, statbuf) >= 0) { -#ifndef DEBUG - *(mLog->log())<< " found for " << pathbuf << endl; -#endif - file_sizes.push_back(sVdrFileEntry(statbuf->st_size, total_file_size, vdr_idx)); - total_file_size += statbuf->st_size; - } - else { - more_to_go = false; - } - } - if (file_sizes.size() < 1) { - // There seems to be vdr video file in the directory - *(mLog->log())<< DEBUGPREFIX - << " No video file in the directory" - << DEBUGHDR << endl; - sendError(404, "Not Found", NULL, "File not found."); - return OKAY; - } - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " vdr filesize list " - << DEBUGHDR << endl; - for (uint i = 0; i < file_sizes.size(); i++) - *(mLog->log())<< " i= " << i << " size= " << file_sizes[i].sSize << " firstOffset= " << file_sizes[i].sFirstOffset << endl; - *(mLog->log())<< " total_file_size= " << total_file_size << endl << endl; -#endif - - // total_file_size (on disk) - - // ---------------- file sizes --------------------- - - uint cur_idx = 0; - -#ifndef DEBUG - if (mIsRecording) { - snprintf(f, sizeof(f), " CurFileSize= %lld mRecProgress= %f ExtFileSize= %lld", total_file_size, mRecProgress, (long long int)(mRecProgress * total_file_size)); - *(mLog->log()) << DEBUGPREFIX - << endl << " isRecording: " << f - << endl; - } -#endif - - if (!rangeHdr.isRangeRequest) { - snprintf(pathbuf, sizeof(pathbuf), mFileStructure.c_str(), mPath.c_str(), file_sizes[cur_idx].sIdx); - - if (openFile(pathbuf) != OKAY) { - sendError(403, "Forbidden", NULL, "Access denied."); - return OKAY; - } - - mRemLength = total_file_size; - - sendHeaders(200, "OK", NULL, "video/mpeg", ((mIsRecording) ? (mRecProgress * total_file_size): total_file_size ), statbuf->st_mtime); - } - else { // Range request - // idenify the first file -#ifndef DEBUG - *(mLog->log()) << DEBUGPREFIX - << endl <<" --- Range Request Handling ---" - << DEBUGHDR << endl; -#endif - if (mIsRecording && (rangeHdr.begin > total_file_size)) { - *(mLog->log()) << DEBUGPREFIX - << " ERROR: Not yet available" << endl; - sendError(404, "Not Found", NULL, "File not found."); - return OKAY; - } - cur_idx = file_sizes.size() -1; - for (uint i = 1; i < file_sizes.size(); i++) { - if (rangeHdr.begin < file_sizes[i].sFirstOffset ) { - cur_idx = i -1; - break; - } - } - -#ifndef DEBUG - *(mLog->log())<< " Identified Record i= " << cur_idx << " file_sizes[i].sFirstOffset= " - << file_sizes[cur_idx].sFirstOffset << " rangeHdr.begin= " << rangeHdr.begin - << " vdr_no= " << file_sizes[cur_idx].sIdx << endl; -#endif - - mVdrIdx = file_sizes[cur_idx].sIdx; - snprintf(pathbuf, sizeof(pathbuf), mFileStructure.c_str(), mPath.c_str(), file_sizes[cur_idx].sIdx); -#ifndef DEBUG - *(mLog->log())<< " file identified= " << pathbuf << endl; -#endif - if (openFile(pathbuf) != OKAY) { - *(mLog->log())<< "----- fopen failed dump ----------" << endl; - *(mLog->log())<< DEBUGPREFIX - << " vdr filesize list " - << DEBUGHDR << endl; - for (uint i = 0; i < file_sizes.size(); i++) - *(mLog->log())<< " i= " << i << " size= " << file_sizes[i].sSize << " firstOffset= " << file_sizes[i].sFirstOffset << endl; - *(mLog->log())<< " total_file_size= " << total_file_size << endl << endl; - - *(mLog->log())<< " Identified Record i= " << cur_idx << " file_sizes[i].sFirstOffset= " - << file_sizes[cur_idx].sFirstOffset << " rangeHdr.begin= " << rangeHdr.begin - << " vdr_no= " << file_sizes[cur_idx].sIdx << endl; - *(mLog->log())<< "---------------" << endl; - sendError(403, "Forbidden", NULL, "Access denied."); - return OKAY; - } - mDir = mPath; - mPath = pathbuf; -#ifndef DEBUG - *(mLog->log())<< " Seeking into file= " << (rangeHdr.begin - file_sizes[cur_idx].sFirstOffset) - << " cur_idx= " << cur_idx - << " file_sizes[cur_idx].sFirstOffset= " << file_sizes[cur_idx].sFirstOffset - << endl; -#endif - fseek(mFile, (rangeHdr.begin - file_sizes[cur_idx].sFirstOffset), SEEK_SET); - if (rangeHdr.end == 0) - rangeHdr.end = ((mIsRecording) ? (mRecProgress * total_file_size): total_file_size); - - mRemLength = (rangeHdr.end-rangeHdr.begin); - - snprintf(f, sizeof(f), "Content-Range: bytes %lld-%lld/%lld", rangeHdr.begin, (rangeHdr.end -1), - ((mIsRecording) ? (long long int)(mRecProgress * total_file_size): total_file_size)); - - sendHeaders(206, "Partial Content", f, "video/mpeg", (rangeHdr.end-rangeHdr.begin), statbuf->st_mtime); - } - -#ifndef DEBUG - *(mLog->log())<< " ***** Yes, vdr dir found ***** mPath= " << mPath<< endl; -#endif - - return OKAY; // handleRead() done -} - -void cHttpResource::sendHeaders(int status, const char *title, const char *extra, const char *mime, - long long int length, time_t date) { - - time_t now; - char timebuf[128]; - char f[400]; - - string hdr = ""; - snprintf(f, sizeof(f), "%s %d %s\r\n", PROTOCOL, status, title); - hdr += f; - snprintf(f, sizeof(f), "Server: %s\r\n", SERVER); - hdr += f; - now = time(NULL); - strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now)); - snprintf(f, sizeof(f), "Date: %s\r\n", timebuf); - hdr += f; - if (extra) { - snprintf(f, sizeof(f), "%s\r\n", extra); - *(mLog->log())<< DEBUGPREFIX << " " << f; - hdr += f; - } - if (mime) { - snprintf(f, sizeof(f), "Content-Type: %s\r\n", mime); - hdr += f; - } - if (length >= 0) { - snprintf(f, sizeof(f), "Content-Length: %lld\r\n", length); - // *(mLog->log())<< DEBUGPREFIX << " " << f << endl; - hdr += f; - } - if (date != -1) { - strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&date)); - snprintf(f, sizeof(f), "Last-Modified: %s\r\n", timebuf); - hdr += f; - } - if (mAcceptRanges) { - snprintf(f, sizeof(f), "Accept-Ranges: bytes\r\n"); - hdr += f; - } - snprintf(f, sizeof(f), "Connection: close\r\n"); - hdr += f; - - snprintf(f, sizeof(f), "\r\n"); - hdr += f; - - - if (mBlkLen != 0) { - *(mLog->log())<< DEBUGPREFIX - << " ERROR in SendHeader: mBlkLen != 0!!! --> Overwriting" << endl; - } - mBlkLen = hdr.size(); - strcpy(mBlkData, hdr.c_str()); - -} - -int cHttpResource::sendFile(struct stat *statbuf32) { - // Send the First Datachunk, incl all headers - struct stat64 statbuf; - - if (stat64(mPath.c_str(), &statbuf) < 0) { - sendError(404, "Not Found", NULL, "File not found."); - return OKAY; - } - *(mLog->log())<< DEBUGPREFIX - << mReqId << " SendFile mPath= " << mPath - << endl; - - char f[400]; - - if (openFile(mPath.c_str()) == ERROR) { - sendError(403, "Forbidden", NULL, "Access denied."); - return OKAY; - } - mFile = fopen(mPath.c_str(), "r"); - // int ret = OKAY; - - if (!mFile) { - sendError(403, "Forbidden", NULL, "Access denied."); - return OKAY; - } - - mFileSize = S_ISREG(statbuf.st_mode) ? statbuf.st_size : -1; - - *(mLog->log())<< "fd= " << mFd << " mReqId= "<< mReqId - << " mFileSize= " <<mFileSize << endl; - - if (!rangeHdr.isRangeRequest) { - mRemLength = mFileSize; - sendHeaders(200, "OK", NULL, getMimeType(mPath.c_str()), mFileSize, statbuf.st_mtime); - } - else { // Range request - fseeko64(mFile, rangeHdr.begin, SEEK_SET); - if (rangeHdr.end == 0) - rangeHdr.end = mFileSize; - mRemLength = (rangeHdr.end-rangeHdr.begin); - *(mLog->log())<< "fd= " << mFd << " mReqId= "<< mReqId - << " rangeHdr.begin= " <<rangeHdr.begin << " rangeHdr.end= " << rangeHdr.end - << " Content-Length= " << mRemLength << endl; - - snprintf(f, sizeof(f), "Content-Range: bytes %lld-%lld/%lld", rangeHdr.begin, (rangeHdr.end -1), mFileSize); - sendHeaders(206, "Partial Content", f, getMimeType(mPath.c_str()), (rangeHdr.end-rangeHdr.begin), statbuf.st_mtime); - } - -#ifndef DEBUG - *(mLog->log())<< "fd= " << mFd << " mReqId= "<< mReqId - << ": Done mRemLength= "<< mRemLength << " mContentType= " << mContentType - << endl; -#endif - mConnState = SERVING; - - return OKAY; - -} - -const char *cHttpResource::getMimeType(const char *name) { - char *ext = strrchr((char*)name, '.'); - if (!ext) - return NULL; - // if (ext.compare(".html") || ext.compare(".htm")) return "text/html"; - if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0) return "text/html"; - if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) return "image/jpeg"; - if (strcmp(ext, ".gif") == 0) return "image/gif"; - if (strcmp(ext, ".png") == 0) return "image/png"; - if (strcmp(ext, ".xml") == 0) return "application/xml"; - if (strcmp(ext, ".css") == 0) return "text/css"; - if (strcmp(ext, ".js") == 0) return "text/javascript"; - if (strcmp(ext, ".au") == 0) return "audio/basic"; - if (strcmp(ext, ".wav") == 0) return "audio/wav"; - if (strcmp(ext, ".avi") == 0) return "video/x-msvideo"; - if (strcmp(ext, ".mp4") == 0) return "video/mp4"; - if (strcmp(ext, ".vdr") == 0) return "video/mpeg"; - if (strcmp(ext, ".ts") == 0) return "video/mpeg"; - if (strcmp(ext, ".mpeg") == 0 || strcmp(ext, ".mpg") == 0) return "video/mpeg"; - if (strcmp(ext, ".mp3") == 0) return "audio/mpeg"; - if (strcmp(ext, ".mpd") == 0) return "application/dash+xml"; - if (strcmp(ext, ".m3u8") == 0) return "application/x-mpegURL"; - - return NULL; -} - - -string cHttpResource::getConnStateName() { - string state_string; - switch (mConnState) { - case WAITING: - state_string = "WAITING"; - break; - case READHDR: - state_string = "READ Req HDR"; - break; - case READPAYLOAD: - state_string = "READ Req Payload"; - break; - case SERVING: - state_string = "SERVING"; - break; - case TOCLOSE: - state_string = "TOCLOSE"; - break; - default: - state_string = "UNKNOWN"; - break; - } - 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)); -} - -uint64_t cHttpResource::getVdrFileSize() { - // iter over all vdr files and get file size - struct stat statbuf; - string file_structure = "%s/%05d.ts"; // Only ts supported for HLS and HAS - char pathbuf[4096]; - int vdr_idx = 0; - uint64_t total_file_size = 0; - bool more_to_go = true; - - while (more_to_go) { - vdr_idx ++; - snprintf(pathbuf, sizeof(pathbuf), file_structure.c_str(), mDir.c_str(), vdr_idx); - if (stat(pathbuf, &statbuf) >= 0) { - total_file_size += statbuf.st_size; - } - else { - more_to_go = false; - } - } - return total_file_size; -} - -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)); - mVersion = line.substr(line.find_last_of(" ") +1); -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " ReqLine= " << line << endl; -#endif - if (mVersion.compare(0, 4, "HTTP") != 0) { -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " ERROR: No HTTP request -> Closing Connection" << line << endl; -#endif - return ERROR; - } - - size_t pos = mRequest.find('?'); - if (pos != string::npos) - mQuery = mRequest.substr (pos+1, string::npos); - mPath = cUrlEncode::doUrlSaveDecode(mRequest.substr(0, mRequest.find('?'))); - *(mLog->log())<< DEBUGPREFIX - << " mMethod= " << mMethod - << " mPath= " << mPath - << " mVer= " << mVersion - << " mQuery= " << mQuery - // << " HexDump= " << endl << cUrlEncode::hexDump(mPath) << endl - << endl; - return OKAY; -} - -int cHttpResource::parseHttpHeaderLine (string line) { - string hdr_name = line.substr(0, line.find_first_of(":")); - string hdr_val = line.substr(line.find_first_of(":") +2); - - if (hdr_name.compare("Range") == 0) { - parseRangeHeaderValue(hdr_val); - *(mLog->log()) << DEBUGPREFIX - << " Range: Begin= " << rangeHdr.begin - << " End= " << rangeHdr.end - << endl; - } - if (hdr_name.compare("User-Agent") == 0) { - mUserAgent = hdr_val; - *(mLog->log())<< " User-Agent: " << hdr_val - << endl; - } - if (hdr_name.compare("Content-Length") == 0) { - mReqContentLength = atoll(hdr_val.c_str()); - //#ifndef DEBUG - *(mLog->log())<< " Content-Length: " << mReqContentLength - << endl; - //#endif - } - return 0; -} - -void cHttpResource::checkRecording() { - // sets mIsRecording to true when the recording is still on-going - mIsRecording = false; - time_t now = time(NULL); - -#ifndef STANDALONE - - // cRecordings* recordings = mFactory->getRecordings(); - cRecordings* recordings = &Recordings; -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " GetByName(" <<mPath.c_str() << ")" - << endl; -#endif - cRecording* rec = recordings->GetByName(mPath.c_str()); - if (rec != NULL) { - const cEvent *ev = rec->Info()->GetEvent(); - if (ev != NULL) { - if (now < ev->EndTime()) { - // still recording - mIsRecording = true; - - // mRecProgress * curFileSize = estimated File Size - mRecProgress = (ev->EndTime() - ev->StartTime()) *1.1 / (rec->NumFrames() / rec->FramesPerSecond()); - // mRecProgress = (ev->EndTime() - ev->StartTime()) *1.0/ (now - ev->StartTime()); -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " **** is still recording for mIsRecording= " - << mIsRecording - << " mRecProgress= " << mRecProgress << endl; -#endif - } - } - -#ifndef DEBUG - *(mLog->log())<< DEBUGPREFIX - << " checking, whether recording is on-going" - << " now= " << now << " start= " << rec->Start() - << " curDur= " << rec->LengthInSeconds() - << endl; -#endif - } -#ifndef DEBUG - else { - *(mLog->log())<< DEBUGPREFIX - << " **** Recording Entry Not found **** " << endl; - } -#endif -#endif -} - -int cHttpResource::parseRangeHeaderValue(string val) { - rangeHdr.isRangeRequest = true; - size_t pos_equal = val.find_first_of('='); - size_t pos_minus = val.find_first_of('-'); - - string range_type = val.substr(0, pos_equal); - string first_val= val.substr(pos_equal+1, pos_minus -(pos_equal+1)); - rangeHdr.begin = atoll(first_val.c_str()); - - string sec_val = ""; - if ((pos_minus +1)< val.size()){ - sec_val = val.substr(pos_minus+1); - rangeHdr.end = atoll(sec_val.c_str()); - } - return 0; -} - -int cHttpResource::openFile(const char *name) { - mFile = fopen(name, "r"); - if (!mFile) { - *(mLog->log())<< DEBUGPREFIX - << " fopen failed pathbuf= " << name - << endl; - // sendError(403, "Forbidden", NULL, "Access denied."); - return ERROR; - } - return OKAY; -} - diff --git a/vdr-smarttvweb/httpresource.h b/vdr-smarttvweb/httpresource.h deleted file mode 100755 index fbbab4d..0000000 --- a/vdr-smarttvweb/httpresource.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * httpresource.h: VDR on Smart TV plugin - * - * 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 - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - -#ifndef __HTTPREQUEST_H__ -#define __HTTPREQUEST_H__ - -#include <string> -#include <cstring> -#include <pthread.h> -#include "log.h" - -using namespace std; - -struct cRange { -cRange(): isRangeRequest(false), begin(0), end(0) {}; - bool isRangeRequest; - unsigned long long begin; - unsigned long long end; -}; - -struct sQueryAVP { - string attribute; - string value; -sQueryAVP(string a, string v) : attribute (a), value(v) {}; -}; - - -enum eConnState { - WAITING, - READHDR, - READPAYLOAD, - SERVING, - TOCLOSE -}; - -enum eContentType { - NYD, // Not Yet Defined - VDRDIR, - SINGLEFILE, - MEMBLOCK -}; - -struct sFileEntry { - string sName; - string sPath; - int sStart; - -sFileEntry(string n, string l, int s) : sName(n), sPath(l), sStart(s) { - }; -}; - -class SmartTvServer; -class cResumeEntry; - -class cHttpResource { - - public: - cHttpResource(int, int, int, SmartTvServer*); - virtual ~cHttpResource(); - - int handleRead(); - int handleWrite(); - - int checkStatus(); - - int readFromClient(); - void threadLoop(); - int run(); - - private: - SmartTvServer* mFactory; - Log* mLog; - - int mServerPort; - int mFd; - int mReqId; - - time_t mConnTime; - int mHandleReadCount; - bool mConnected; - eConnState mConnState; - eContentType mContentType; - - string mReadBuffer; - string mMethod; - - string *mResponseMessage; - int mResponseMessagePos; - char* mBlkData; - int mBlkPos; - int mBlkLen; - - string mRequest; - string mQuery; - string mPath; - string mDir; - string mVersion; - string protocol; - unsigned long long mReqContentLength; - string mPayload; - string mUserAgent; - - bool mAcceptRanges; - cRange rangeHdr; - unsigned long long mFileSize; - bool mStreamToEnd; - uint64_t mRemLength; - FILE *mFile; - int mVdrIdx; - string mFileStructure; - bool mIsRecording; - float mRecProgress; - - void setNonBlocking(); - int fillDataBlk(); - - int handlePost(); - int handleHeadRequest(); - int processRequest(); - int processHttpHeaderNew(); - - int readRequestPayload(); - void sendError(int status, const char *title, const char *extra, const char *text); - int sendDir(struct stat *statbuf); - int sendVdrDir(struct stat *statbuf); - int sendRecordingsXml (struct stat *statbuf); - int sendChannelsXml (struct stat *statbuf); - int sendResumeXml (); - int sendVdrStatusXml (struct stat *statbuf); - int sendEpgXml (struct stat *statbuf); - int sendMediaXml (struct stat *statbuf); - - int sendManifest (struct stat *statbuf, bool is_hls = true); - - int receiveResume(); - int deleteRecording(); - - void writeM3U8(double duration, int bitrate, float seg_dur, int end_seg); - void writeMPD(double duration, int bitrate, float seg_dur, int end_seg); - - - int sendMediaSegment (struct stat *statbuf); - - void sendHeaders(int status, const char *title, const char *extra, const char *mime, - long long int length, time_t date); - - int sendFile(struct stat *statbuf); - - // Helper Functions - const char *getMimeType(const char *name); - string getConnStateName(); - string getOwnIp(int fd); - uint64_t getVdrFileSize(); - void checkRecording(); - bool isTimeRequest(struct stat *statbuf); - int parseRangeHeaderValue(string); - int parseHttpRequestLine(string); - int parseHttpHeaderLine (string); - int parseQueryLine (vector<sQueryAVP> *avps); - int parseResume(cResumeEntry &entry, string &id); - - int parseFiles(vector<sFileEntry> *entries, string prefix, string dir_base, string dir_name, struct stat *statbuf); - - int getQueryAttributeValue(vector<sQueryAVP> *avps, string id, string &val); - int openFile(const char *name); - 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/log.c b/vdr-smarttvweb/log.c deleted file mode 100644 index 685bce3..0000000 --- a/vdr-smarttvweb/log.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * log.c: VDR on Smart TV plugin - * - * Copyright (C) 2012 Thorsten Lohmar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - - -#include "log.h" -#include <time.h> -#include <cstring> - -Log* Log::instance = NULL; - -Log::Log() { - if (instance) - return; - instance = this; - mLogFile = NULL; -} - -Log::~Log() { - instance = NULL; -} - -Log* Log::getInstance() { - return instance; -} -int Log::init(string fileName) { - char timebuf[128]; - time_t now = time(NULL); - strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); - - if (fileName != "") { - mLogFile = new ofstream(); - - mLogFile->open(fileName.c_str(), ios::out ); - *mLogFile << "Log Created: " << timebuf << endl; - } - else - mLogFile = new ofstream("/dev/null"); - return 0; -} - -int Log::init(char* fileName) { - - char timebuf[128]; - time_t now = time(NULL); - strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); - - if (strcmp(fileName, "") !=0) { - mLogFile = new ofstream(); - mLogFile->open(fileName, ios::out ); - *mLogFile << "Log Created: " << timebuf << endl; - } - else - mLogFile = new ofstream("/dev/null"); - return 0; -} - -int Log::shutdown() { - if (mLogFile) - mLogFile->close(); - return 1; -} - -ofstream* Log::log() { - return mLogFile; -} - diff --git a/vdr-smarttvweb/log.h b/vdr-smarttvweb/log.h deleted file mode 100644 index 8a09fe3..0000000 --- a/vdr-smarttvweb/log.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * log.h.h: VDR on Smart TV plugin - * - * Copyright (C) 2012 Thorsten Lohmar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - - -#ifndef LOG_H -#define LOG_H - -#include <iostream> -#include <fstream> - -using namespace std; - -class Log -{ - public: - Log(); - ~Log(); - static Log* getInstance(); - - int init(char* fileName); - int init(string fileName); - int shutdown(); - ofstream* log(); - - private: - static Log* instance; - - ofstream *mLogFile; -}; - -#endif diff --git a/vdr-smarttvweb/smarttvfactory.c b/vdr-smarttvweb/smarttvfactory.c deleted file mode 100755 index 3478e9d..0000000 --- a/vdr-smarttvweb/smarttvfactory.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * smarttvfactory.h: VDR on Smart TV plugin - * - * Copyright (C) 2012 T. Lohmar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - -#ifndef STANDALONE -#include <vdr/recording.h> -#include <vdr/videodir.h> -#endif - -#include <iostream> - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <time.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/select.h> -#include <sys/ioctl.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <net/if.h> -#include <netdb.h> -#include <fcntl.h> -#include <errno.h> -#include <dirent.h> - -#include <iostream> -#include <fstream> - - -#include "smarttvfactory.h" - -#ifndef STANDALONE -#define PORT 8000 -#else -#define PORT 9000 -#endif - -#define OKAY 0 -#define ERROR (-1) - -#define DEBUG - - -using namespace std; - -void SmartTvServerStartThread(void* arg) { - SmartTvServer* m = (SmartTvServer*)arg; - m->threadLoop(); - delete m; - pthread_exit(NULL); -} - -SmartTvServer::SmartTvServer(): mRequestCount(0), isInited(false), serverPort(PORT), mServerFd(-1), - mSegmentDuration(10), mHasMinBufferTime(40), mLiveChannels(20), - clientList(), mActiveSessions(0), mConfig(NULL) { -} - - -SmartTvServer::~SmartTvServer() { - - if (mConfig != NULL) - delete mConfig; -} - -void SmartTvServer::cleanUp() { - // close listening ports - for (uint idx= 0; idx < clientList.size(); idx++) { - if (clientList[idx] != NULL) { - close(idx); - delete clientList[idx]; - clientList[idx] = NULL; - } - } - - // close server port - close(mServerFd); - - // Leave thread - pthread_cancel(mThreadId); - pthread_join(mThreadId, NULL); - - mLog.shutdown(); -} - -int SmartTvServer::runAsThread() { - int res = pthread_create(&mThreadId, NULL, (void*(*)(void*))SmartTvServerStartThread, (void *)this); - if (res != 0) { - *(mLog.log()) << " Error creating thread. res= " << res - << endl; - return 0; - } - return 1; -} - -void SmartTvServer::threadLoop() { - *(mLog.log()) << " SmartTvServer Thread Started " << endl; - - loop(); - - *(mLog.log()) << " SmartTvServer Thread Stopped " << endl; -} - - -void SmartTvServer::loop() { - socklen_t addr_size = 0; - int rfd; - sockaddr_in sadr; - int req_id = 0; - int ret = 0; - struct timeval timeout; - - int maxfd; - - fd_set read_set; - fd_set write_set; - - FD_ZERO(&read_set); - FD_ZERO(&write_set); - - FD_ZERO(&mReadState); - FD_ZERO(&mWriteState); - - FD_SET(mServerFd, &mReadState); - maxfd = mServerFd; - - *(mLog.log()) << "mServerFd= " << mServerFd << endl; - - int handeled_fds = 0; - - for (;;) { - FD_ZERO(&read_set); - FD_ZERO(&write_set); - read_set = mReadState; - write_set = mWriteState; - - if (ret != handeled_fds) { - // Only ok, when the server has closed a handing HTTP connection - *(mLog.log()) << "WARNING: Select-ret= " << ret - << " != handeled_fds= " << handeled_fds << endl; - /* FD_ZERO(&mReadState); - FD_ZERO(&mWriteState); - FD_SET(mServerFd, &mReadState); - maxfd = mServerFd; - - read_set = mReadState; - write_set = mWriteState; - for (uint idx= 0; idx < clientList.size(); idx++) { - if (clientList[idx] != NULL) { - close(idx); - delete clientList[idx]; - clientList[idx] = NULL; - } - } - mActiveSessions = 0; -*/ - } - - handeled_fds = 0; - timeout.tv_sec = 5; - timeout.tv_usec = 0; - - ret = select(maxfd + 1, &read_set, &write_set, NULL, &timeout); - - if (ret == 0) { - // timeout: Check for dead TCP connections - for (uint idx= 0; idx < clientList.size(); idx++) { - if (clientList[idx] != NULL) - if (clientList[idx]->checkStatus() == ERROR) { - close(idx); - delete clientList[idx]; - clientList[idx] = NULL; - mActiveSessions--; - FD_CLR(idx, &mReadState); /* dead client */ - FD_CLR(idx, &mWriteState); - *(mLog.log()) << "WARNING: Timeout - Dead Client fd=" << idx << endl; - } - } - continue; - } // timeout - - if (ret < 0){ - *(mLog.log()) << "ERROR: select error " << errno << endl; - continue; - } // Error - - // new accept - if (FD_ISSET(mServerFd, &read_set)) { - handeled_fds ++; - if((rfd = accept(mServerFd, (sockaddr*)&sadr, &addr_size))!= -1){ - req_id ++; - -#ifndef DEBUG - *(mLog.log()) << "fd= " << rfd - << " --------------------- Received connection ---------------------" << endl; -#endif - - FD_SET(rfd, &mReadState); - FD_SET(rfd, &mWriteState); - - if (rfd > maxfd) { - maxfd = rfd; - } - - if (clientList.size() < (rfd+1)) { - clientList.resize(rfd+1, NULL); // Check. - } - clientList[rfd] = new cHttpResource(rfd, req_id, serverPort, this); - mActiveSessions ++; - *(mLog.log()) << " + mActiveSessions= " << mActiveSessions << endl; - } - else{ - *(mLog.log()) << "Error accepting " << errno << endl; - } - } - - // Check for data on already accepted connections - for (rfd = 0; rfd < clientList.size(); rfd++) { - if (clientList[rfd] == NULL) - continue; - if (FD_ISSET(rfd, &read_set)) { - handeled_fds ++; - // HandleRead - if (clientList[rfd] == NULL) { - *(mLog.log()) << "ERROR in Check Read: oops - no cHttpResource anymore fd= " << rfd << endl; - close(rfd); - FD_CLR(rfd, &mReadState); /* remove dead client */ - FD_CLR(rfd, &mWriteState); - continue; - } - if ( clientList[rfd]->handleRead() < 0){ -#ifndef DEBUG - *(mLog.log()) << "fd= " << rfd << " --------------------- Check Read: Closing ---------------------" << endl; -#endif - close(rfd); - delete clientList[rfd]; - clientList[rfd] = NULL; - mActiveSessions--; - *(mLog.log()) << " - Check Read: mActiveSessions= " << mActiveSessions << endl; - FD_CLR(rfd, &mReadState); /* dead client */ - FD_CLR(rfd, &mWriteState); - } - } - } - - // Check for write - for (rfd = 0; rfd < clientList.size(); rfd++) { - if (clientList[rfd] == NULL) - continue; - if (FD_ISSET(rfd, &write_set)) { - handeled_fds++; - // HandleWrite - if (clientList[rfd] == NULL) { - close(rfd); - FD_CLR(rfd, &mReadState); - FD_CLR(rfd, &mWriteState); - continue; - } - if ( clientList[rfd]->handleWrite() < 0){ -#ifndef DEBUG - *(mLog.log()) << "fd= " << rfd << " --------------------- Check Write: Closing ---------------------" << endl; -#endif - close(rfd); - delete clientList[rfd]; - clientList[rfd] = NULL; - mActiveSessions--; - *(mLog.log()) << " - Check Write: mActiveSessions= " << mActiveSessions << endl; - FD_CLR(rfd, &mReadState); - FD_CLR(rfd, &mWriteState); - } - } - } - - // selfcheck - /* *(mLog.log()) << "Select Summary: ret= " << ret - << " handeled_fds=" << handeled_fds - << " mActiveSessions= " << mActiveSessions - << " clientList.size()= " << clientList.size() - << endl; -*/ - //Check for active sessions - /* - *(mLog.log()) << "checking number of active sessions clientList.size()= " << clientList.size() << endl; - - int act_ses = 0; - for (uint idx= 0; idx < clientList.size(); idx++) { - if (clientList[idx] != NULL) - act_ses++; - } - if (act_ses != mActiveSessions) { - *(mLog.log()) << "ERROR: Lost somewhere a session: " - << "mActiveSessions= " << mActiveSessions - << "act_ses= " << act_ses - << endl; - mActiveSessions = act_ses; - } - *(mLog.log()) << "checking number of active sessions - done mActiveSessions= " << mActiveSessions << endl; -*/ - } // for (;;) -} // org bracket - -int SmartTvServer::isServing() { - return (mActiveSessions != 0 ? true : false); -} - -void SmartTvServer::initServer(string dir) { - /* This function initialtes the listening socket for the server - * and sets isInited to true - */ - mConfigDir = dir; - int ret; - struct sockaddr_in sock; - int yes = 1; - - -#ifndef STANDALONE - mConfig = new cSmartTvConfig(dir); - mLog.init(mConfig->getLogFile()); - esyslog("SmartTvWeb: Logfile created"); - - *(mLog.log()) << mConfig->getLogFile() << endl; - -#else - mConfig = new cSmartTvConfig("."); - mLog.init(mConfig->getLogFile()); - cout << "SmartTvWeb: Logfile created" << endl; - cout << "SmartTvWeb: Listening on port= " << PORT << endl; - -#endif - - // mConfig->printConfig(); - - mSegmentDuration= mConfig->getSegmentDuration(); - mHasMinBufferTime= mConfig->getHasMinBufferTime(); - mLiveChannels = mConfig->getLiveChannels(); - - *(mLog.log()) <<"HTTP server listening on port " << serverPort << endl; - - mServerFd = socket(PF_INET, SOCK_STREAM, 0); - if (mServerFd <0) { - *(mLog.log()) << "Error: Cannot create serving socket, exit" << endl; - exit(1); - } - - ret = setsockopt(mServerFd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); - if (ret <0) { - *(mLog.log()) << "Error: Cannot set sockopts on serving socket, exit" << endl; - exit(1); - } - - memset((char *) &sock, 0, sizeof(sock)); - sock.sin_family = AF_INET; - - 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)); - if (ret !=0) { - *(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) { - *(mLog.log()) << "Error: Cannot set listening on serving socket, exit" << endl; - exit(1); - } - - isInited = true; -} - - - - diff --git a/vdr-smarttvweb/smarttvfactory.h b/vdr-smarttvweb/smarttvfactory.h deleted file mode 100644 index 1073ab0..0000000 --- a/vdr-smarttvweb/smarttvfactory.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * smarttvfactory.h: VDR on Smart TV plugin - * - * Copyright (C) 2012 T. Lohmar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - - -#ifndef __SMARTTVSERVER_H__ -#define __SMARTTVSERVER_H__ - -#include <string> -#include <cstring> -#include <vector> -#include <list> -#include "httpresource.h" -#include "log.h" -#include "stvw_cfg.h" - -#ifndef STANDALONE -#include <vdr/recording.h> -#endif - -using namespace std; - -#define PLG_VERSION "0.9.6" -#define SERVER "SmartTvWeb/0.9.6" - -class SmartTvServer { - public: - SmartTvServer(); - virtual ~SmartTvServer(); - - void initServer(string c_dir); - void loop(); - void cleanUp(); - int runAsThread(); - void threadLoop(); - - Log mLog; - - void readRecordings(); - int isServing(); - - string getConfigDir() { return mConfigDir; }; - cSmartTvConfig* getConfig() { return mConfig; }; - - private: - pthread_t mThreadId; - int mRequestCount; - bool isInited; - int serverPort; - int mServerFd; - unsigned int mSegmentDuration; - int mHasMinBufferTime; - int mLiveChannels; - - vector<cHttpResource*> clientList; - int mActiveSessions; - string mConfigDir; - cSmartTvConfig *mConfig; - - int mMaxFd; - fd_set mReadState; - fd_set mWriteState; -}; - - -#endif diff --git a/vdr-smarttvweb/smarttvweb.c b/vdr-smarttvweb/smarttvweb.c deleted file mode 100644 index 9e3269e..0000000 --- a/vdr-smarttvweb/smarttvweb.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * smarttvweb.c: VDR on Smart TV plugin - * - * Copyright (C) 2012 T. Lohmar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - - -#ifndef STANDALONE -#include <vdr/plugin.h> -#endif - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <sys/socket.h> -#include <netdb.h> -#include <sys/stat.h> -#include <sys/select.h> -#include <errno.h> - -#include <dirent.h> - -#include "smarttvfactory.h" - - -static const char *VERSION = PLG_VERSION; -static const char *DESCRIPTION = "SmartTV Web Server"; - - -using namespace std; - -#ifndef STANDALONE -class cPluginSmartTvWeb : public cPlugin -{ -public: - cPluginSmartTvWeb(void); - virtual ~cPluginSmartTvWeb(); - virtual const char *Version(void) { return VERSION; } - virtual const char *Description(void) { return DESCRIPTION; } - virtual const char *CommandLineHelp(void); - virtual bool ProcessArgs(int argc, char *argv[]); - virtual bool Initialize(void); - virtual bool Start(void); - virtual bool SetupParse(const char *Name, const char *Value); -#if VDRVERSNUM > 10300 - virtual cString Active(void); -#endif - -private: - SmartTvServer mServer; - string mConfigDir; -}; - -cPluginSmartTvWeb::cPluginSmartTvWeb(void) { - // Initialize any member variables here. - // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL - // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! - mConfigDir = ""; -} - -bool cPluginSmartTvWeb::Start(void) { - // Start any background activities the plugin shall perform. - - if (mConfigDir.compare("") == 0) { - const char* dir_name = cPlugin::ConfigDirectory(Name()); - if (!dir_name) { - dsyslog("SmartTvWeb: Could not get config dir from VDR"); - } - else - mConfigDir = string(dir_name); - } - - mServer.initServer(mConfigDir); - int success = mServer.runAsThread(); - - esyslog("SmartTvWeb: started %s", (success == 1) ? "sucessfully" : "failed!!!!"); - - return ((success == 1) ? true: false); -} - -cPluginSmartTvWeb::~cPluginSmartTvWeb() { - // Clean up after yourself! - mServer.cleanUp(); -} - -const char *cPluginSmartTvWeb::CommandLineHelp(void) -{ - // Return a string that describes all known command line options. - return " \n"; -} - -bool cPluginSmartTvWeb::ProcessArgs(int argc, char *argv[]) { - // Implement command line argument processing here if applicable. - return true; -} - -bool cPluginSmartTvWeb::Initialize(void) { - // Initialize any background activities the plugin shall perform. - esyslog("SmartTvWeb: Initialize called"); - - return true; -} - -bool cPluginSmartTvWeb::SetupParse(const char *Name, const char *Value) -{ - // Parse your own setup parameters and store their values. - return false; -} - -#if VDRVERSNUM > 10300 - -cString cPluginSmartTvWeb::Active(void) { - esyslog("SmartTvWeb: Active called Checkme"); - if (mServer.isServing()) - return tr("SmartTV client(s) serving"); - else - return NULL; -} - -#endif - -VDRPLUGINCREATOR(cPluginSmartTvWeb); // Don't touch this! - -#else //VOMPSTANDALONE - - -int main(int argc, char *argv[]) { - printf ("Starting up\n"); - - SmartTvServer server; - server.initServer("."); - server.loop(); -} -#endif diff --git a/vdr-smarttvweb/smarttvweb.conf b/vdr-smarttvweb/smarttvweb.conf deleted file mode 100644 index 07920dc..0000000 --- a/vdr-smarttvweb/smarttvweb.conf +++ /dev/null @@ -1,28 +0,0 @@ -# - -LogFile /tmp/smarttvweb.txt - -MediaFolder /multimedia/video - -# Media Segment Duration for HLS/ DASH -SegmentDuration 10 - -# minBufferTime value for the DASH MPD -HasMinBufferTime 30 - -# Bitrate correction parameter for Hls and DASH MPD -HasBitrateCorrection 1.1 - -# Default number of Live Channel entries included in the channels.xml, when not requested specifically. -LiveChannels 30 - -# 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 deleted file mode 100755 index 75b8de6..0000000 --- a/vdr-smarttvweb/stvw_cfg.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * stvw_cfg.h: VDR on Smart TV plugin - * - * 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 - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - -#include "stvw_cfg.h" - -#ifndef STANDALONE -#include <vdr/plugin.h> -#endif - -#include <iostream> -#include <fstream> -#include <cstdio> -#include <cstdlib> - -cSmartTvConfig::cSmartTvConfig(string d): mConfigDir(d), mLog(NULL), mCfgFile(NULL), - mLogFile(), mMediaFolder(), mSegmentDuration(), mHasMinBufferTime(), mHasBitrateCorrection(), - mLiveChannels(), mGroupSep(IGNORE), mServerAddress("") { - -#ifndef STANDALONE - mLogFile= ""; -#else - mLogFile= "./smartvvweblog-standalone.txt"; -#endif - - // Defaults - mMediaFolder= "/hd2/mpeg"; - mSegmentDuration = 10; - mHasMinBufferTime = 40; - mHasBitrateCorrection = 1.1; - mLiveChannels = 30; - - readConfig(); -} - -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()) << " HasBitrateCorrection: " << mHasBitrateCorrection << 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]; - char value[200]; - - ifstream myfile ((mConfigDir +"/smarttvweb.conf").c_str()); - - if (!myfile.is_open()) { -#ifndef STANDALONE - esyslog ("ERROR in SmartTvWeb: Cannot open config file. Expecting %s", (mConfigDir +"/smarttvweb.conf").c_str() ); -#else - cout << "ERROR: Cannot open config file. Expecting "<< (mConfigDir +"/smarttvweb.conf") << endl; -#endif - return; - } - - while ( myfile.good() ) { - getline (myfile, line); - - if ((line == "") or (line[0] == '#')) - continue; - - sscanf(line.c_str(), "%s %s", attr, value); - - if (strcmp(attr, "LogFile")==0) { - mLogFile = string(value); - // cout << " Found mLogFile= " << mLogFile << endl; - continue; - } - - if (strcmp(attr, "MediaFolder") == 0) { - mMediaFolder = string (value); - // cout << " Found mMediaFolder= " << mMediaFolder << endl; - continue; - } - if (strcmp(attr, "SegmentDuration") == 0) { - mSegmentDuration = atoi(value); - // cout << " Found mSegmentDuration= " << mSegmentDuration << endl; - continue; - } - - if (strcmp(attr, "HasMinBufferTime") == 0) { - mHasMinBufferTime = atoi(value); - // cout << " Found mHasMinBufferTime= " << mHasMinBufferTime << endl; - continue; - } - if (strcmp(attr, "HasBitrateCorrection") == 0) { - mHasBitrateCorrection = atof(value); - // cout << " Found mHasBitrate= " <<mHasBitrate << endl; - continue; - } - if (strcmp(attr, "LiveChannels") == 0) { - mLiveChannels = atoi(value); - // cout << " Found mLiveChannels= " <<mLiveChannels << endl; - 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= " <<mLiveChannels << endl; - continue; - } - - -#ifndef STANDALONE - esyslog("WARNING in SmartTvWeb: Attribute= %s with value= %s was not processed, thus ignored.", attr, value); -#else - cout << "WARNING: Attribute= "<< attr << " with value= " << value << " was not processed, thus ignored." << endl; -#endif - } - myfile.close(); -} - - /* -cResumes* cSmartTvConfig::readConfig(string f) { - - - string line; - ifstream myfile ("example.txt"); - - if (myfile.is_open()) { - while ( myfile.good() ) { - getline (myfile,line); - *(mLog->log()) << " readConfig: " << line << endl; - if (line == "") - continue; - - string t; - time_t st; - int r; - time_t lv; - int count = scanf (line.c_str(), "%s %lld %d %lld", &t, &st, &r, &lv); - if (count == 4) { - *(mLog->log()) << " read: " << t << " st= " << st << " r= " << r << " lv= " << lv << endl; - } - // first title - - - } - myfile.close(); - } - - else { - *(mLog->log()) << " readConfig: Cannot open file " << f << endl; - return NULL; - } - - - // open the file - // read the lines - return NULL; -} -*/ diff --git a/vdr-smarttvweb/stvw_cfg.h b/vdr-smarttvweb/stvw_cfg.h deleted file mode 100755 index d894820..0000000 --- a/vdr-smarttvweb/stvw_cfg.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * stvw_cfg.h: VDR on Smart TV plugin - * - * 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 - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - - -#ifndef __SMARTTV_CONFIG_H__ -#define __SMARTTV_CONFIG_H__ - -#include <string> -#include <cstring> -#include <vector> -#include <ctime> -#include "log.h" - -using namespace std; - - -enum eGroupSep { - IGNORE, - EMPTYIGNORE, - EMPTYFOLDERDOWN -}; - -class cSmartTvConfig { - private: - string mConfigDir; - Log* mLog; - FILE *mCfgFile; - - string mLogFile; - string mMediaFolder; - unsigned int mSegmentDuration; - int mHasMinBufferTime; - float mHasBitrateCorrection; - int mLiveChannels; - - eGroupSep mGroupSep; - string mServerAddress; - - public: - cSmartTvConfig(string dir); - ~cSmartTvConfig(); - - void readConfig(); - void printConfig(); - - string getLogFile() { return mLogFile; }; - string getMediaFolder() { return mMediaFolder; }; - unsigned int getSegmentDuration() {return mSegmentDuration; }; - int getHasMinBufferTime() { return mHasMinBufferTime; }; - float getHasBitrateCorrection() { return mHasBitrateCorrection; }; - int getLiveChannels() {return mLiveChannels; }; - eGroupSep getGroupSep() { return mGroupSep; }; - string getServerAddress() { return mServerAddress; }; -}; - -#endif diff --git a/vdr-smarttvweb/url.c b/vdr-smarttvweb/url.c deleted file mode 100644 index 6446654..0000000 --- a/vdr-smarttvweb/url.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * url.c: VDR on Smart TV plugin - * - * 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 - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - -#include <cstdio> -#include"url.h" - - -//http://www.blooberry.com/indexdot/html/topics/urlencoding.htm -string cUrlEncode::doUrlSaveEncode(string in) { - string res = ""; - unsigned char num = 0; - char buf[5]; - - bool done = false; - unsigned int idx = 0; - while (!done) { - if (idx == in.size()) { - done = true; - continue; - } - num = in[idx]; - switch (num) { - case '&': - res += "%26"; - break; - case '%': - res += "%25"; - break; - case '#': - // break; - if (in.compare(idx, 3, "#3F") == 0) { - res += "%3F"; - idx +=3; - continue; - } - if (in.compare(idx, 3, "#3A") == 0) { - res += "%3A"; - idx += 3; - continue; - } - if (in.compare(idx, 3, "#2F") == 0) { - res += "%2F"; - idx += 3; - continue; - } - res += "%23"; // just a '#' char - break; - default: - // Copy the normal chars - if (num < 128) - res += char(num); - else { - sprintf (buf, "%02hhX", num); - res += "%"; - res += buf; - } - break; - } // switch - - idx ++; - } - return res; -} - - -string cUrlEncode::doUrlSaveDecode(string input) { - string res = ""; - unsigned int idx = 0; - int x; - while (idx < input.size()){ - if (input[idx] == '%') { - string num = input.substr(idx+1, 2); - sscanf(num.c_str(), "%X", &x); - idx+= 3; - switch (x) { - case 0x23: // '#' - res += "#"; - break; - case 0x25: // '%' - res += "%"; - break; - case 0x2f: // '/' - res += "#2F"; - break; - case 0x3a: // ':' - res += "#3A"; - break; - case 63: // '?' - res += "#3F"; - break; - default: - res += char(x); - break; - } - } - else { - res += input[idx]; - idx ++; - } - } - return res; -} - -string cUrlEncode::doXmlSaveEncode(string in) { - string res = ""; - unsigned char num = 0; - // char buf[5]; - - bool done = false; - unsigned int idx = 0; - while (!done) { - if (idx == in.size()) { - done = true; - continue; - } - num = in[idx]; - switch (num) { - case 0x26: // '&': - res += "&"; - break; - case 0x27: // '\'': - res += "'"; - break; - case 0x3c: // '<': - res += "<"; - break; - case 0x3e: // '>': - res += ">"; - break; - case 0x22: // '\"': - res += """; - break; - - /* case 0xc4: // Ä - res += "Ä"; - break; - case 0xe4: //'ä': - res += "ä"; - break; - case 0xd6: // Ö - res += "Ö"; - break; - case 0xf6: // 'ö': - res += "ö"; - break; - case 0xdc: //'Ü': - res += "Ü"; - break; - case 0xfc: //'ü': - res += "ü"; - break; - case 0xdf: //'ß': - res += "ß"; - break; -*/ - default: - // Copy the normal chars - res += char(num); - break; - } // switch - - idx ++; - } - return res; -} - -string cUrlEncode::doXmlSaveDecode(string input) { - string res = ""; - unsigned int idx = 0; - while (idx < input.size()){ - if (input[idx] == '&') { - if (input.compare(idx, 4, "<") == 0){ - res += "<"; - idx += 4; - } - else if (input.compare(idx, 4, ">") == 0){ - res += ">"; - idx += 4; - } - else if (input.compare(idx, 5, "&") == 0){ - res += "&"; - idx += 5; - } - else if (input.compare(idx, 6, """) == 0){ - res += "\""; - idx += 6; - } - else if (input.compare(idx, 6, "'") == 0){ - res += "\'"; - idx += 6; - } - else { - // ERROR - idx = input.size(); - res = ""; - } - } - else { - res += input[idx]; - idx ++; - } - - } - return res; -} - -string cUrlEncode::removeEtChar(string line, bool xml) { - bool done = false; - size_t cur_pos = 0; - size_t pos = 0; - string res = ""; - - int end_after_done = 0; - - while (!done) { - pos = line.find('&', cur_pos); - if (pos == string::npos) { - done = true; - res += line.substr(cur_pos); - break; - } - if (pos >= 0) { - if (xml) - res += line.substr(cur_pos, (pos-cur_pos)) + "&"; // xml save encoding - else - res += line.substr(cur_pos, (pos-cur_pos)) + "%26"; // url save encoding - // cur_pos = cur_pos+ pos +1; - cur_pos = pos +1; - end_after_done ++; - } - } - return res; -} - -string cUrlEncode::hexDump(char *line, int line_len) { - string res = ""; - string ascii = ""; - char buf[10]; - - int line_count = 0; - for (unsigned int i = 0; i < line_len; i++) { - unsigned char num = line[i]; - sprintf (buf, "%02hhX", num); - res += buf; - if ((num >= 32) && (num < 127)) { - ascii += char(num); - } - else - ascii += '.'; - - line_count++; - switch (line_count) { - case 8: - res += " "; - ascii += " "; - break; - case 17: - res += " " + ascii; - res += "\r\n"; - ascii = ""; - line_count = 0; - break; - default: - res += " "; - break; - } - } - if (line_count != 0) { - for (int i = 0; i < ((17 - line_count) * 3 ); i++) - res += " "; - if (line_count >= 8) - res += " "; - - res += " "; - res += ascii; - } - return res; -} - -string cUrlEncode::hexDump(string in) { - string res = ""; - string ascii = ""; - char buf[10]; - - int line_count = 0; - for (unsigned int i = 0; i < in.size(); i++) { - unsigned char num = in[i]; - sprintf (buf, "%02hhX", num); - res += buf; - if ((num >= 32) && (num < 127)) { - ascii += char(num); - } - else - ascii += '.'; - - line_count++; - switch (line_count) { - case 8: - res += " "; - ascii += " "; - break; - case 16: - res += " " + ascii; - res += "\r\n"; - ascii = ""; - line_count = 0; - break; - default: - res += " "; - break; - } - } - if (line_count != 0) { - for (int i = 0; i < ((16 - line_count) * 3 ); i++) - res += " "; - if (line_count >= 8) - res += " "; - res += ascii; - } - return res; -} diff --git a/vdr-smarttvweb/url.h b/vdr-smarttvweb/url.h deleted file mode 100644 index 4656a2a..0000000 --- a/vdr-smarttvweb/url.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * url.h: VDR on Smart TV plugin - * - * Copyright (C) 2012 T. Lohmar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - */ - - -#ifndef __URL_H__ -#define __URL_H__ - -#include <string> - -using namespace std; - -class cUrlEncode { - - public: - cUrlEncode() {}; - cUrlEncode(string &) {}; - - static string doUrlSaveEncode (string); - static string doUrlSaveDecode (string); - - static string doXmlSaveEncode (string); - static string doXmlSaveDecode (string); - static string removeEtChar(string line, bool xml=true); - static string hexDump(char *line, int line_len); - static string hexDump(string); - - private: - -}; - -#endif diff --git a/vdr-smarttvweb/web/Data.js b/vdr-smarttvweb/web/Data.js deleted file mode 100755 index 49e9026..0000000 --- a/vdr-smarttvweb/web/Data.js +++ /dev/null @@ -1,296 +0,0 @@ -//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});
-// Main.log("Data.reset: folderList.push. this.folderList.length= " + this.folderList.length);
-};
-
-Data.completed= function(sort) {
- if (sort == true)
- this.assets.sortPayload();
-
- this.folderList.push({item : this.assets, id: 0});
-// Main.log("Data.completed: folderList.push. this.folderList.length= " + this.folderList.length);
-// Main.log ("Data.completed()= " +this.folderList.length);
-
-};
-
-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.addItem = function(t_list, pyld) {
- this.assets.addChild(t_list, pyld, 0);
-};
-
-Data.dumpFolderStruct = function(){
- Main.log("---------- dumpFolderStruct ------------");
- this.assets.print(0);
- Main.log("---------- dumpFolderStruct Done -------");
-};
-
-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() {
- return this.folderList[this.folderList.length-1].item.childs.length;
-};
-
-Data.getNumString =function(num, fmt) {
- var res = "";
-
- if (num < 10) {
- for (var i = 1; i < fmt; i ++) {
- res += "0";
- };
- } else if (num < 100) {
- for (var i = 2; i < fmt; i ++) {
- res += "0";
- };
- }
-
- res = res + num;
-
- return res;
-};
-
-Data.deleteElm = function (pos) {
- Data.getCurrentItem().childs.remove(pos);
-};
-//-----------------------------------------
-function Item() {
- this.title = "root";
- this.isFolder = true;
- this.childs = [];
- this.payload = ""; // only set, if (isFolder == false)
-}
-
-Item.prototype.isFolder = function() {
- return this.isFolder;
-};
-
-Item.prototype.getTitle = function () {
- return this.title;
-};
-
-Item.prototype.getPayload = function () {
- if (this.isFolder == true) {
- Main.log("WARNING: getting payload on a folder title=" +this.title);
- }
- return this.payload;
-};
-
-Item.prototype.getItem = function (title) {
- for (var i = 0; i < this.childs.length; i++) {
- if (this.childs[i].title == title) {
- return this.childs[i];
- }
- }
- return 0;
-};
-
-Item.prototype.addChild = function (key, pyld, level) {
- if (key.length == 1) {
- var folder = new Item;
-// folder.title = pyld.startstr + " - " + key;
- folder.title = key[0];
- folder.payload = pyld;
- folder.isFolder = false;
- this.childs.push(folder);
-// this.titles.push({title: pyld.startstr + " - " + key , pyld : pyld});
- }
- else {
- if (level > 10) {
- Main.log(" too many levels");
- return;
- }
- var t = key.shift();
- var found = false;
- for (var i = 0; i < this.childs.length; i++) {
- if (this.childs[i].title == t) {
- this.childs[i].addChild(key, pyld, level +1);
- found = true;
- break;
- }
- }
- if (found == false) {
- var folder = new Item;
- folder.title = t;
- folder.addChild(key, pyld, level+1);
- this.childs.push(folder);
- }
- }
-};
-
-Item.prototype.findEpgUpdateTime = function (min, guid, level) {
- var prefix= "";
- for (var i = 0; i < level; i++)
- prefix += "-";
-
- for (var i = 0; i < this.childs.length; i++) {
- if (this.childs[i].isFolder == true) {
- 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.updateEpgEntry = function (guid, entry, level) {
- var prefix= "";
- for (var i = 0; i < level; i++)
- prefix += "-";
- for (var i = 0; i < this.childs.length; i++) {
- if (this.childs[i].isFolder == true) {
- var res = this.childs[i].updateEpgEntry(guid, entry, level+1);
- if (res == true)
- return true;
- }
- else {
- if (this.childs[i].payload['guid'] == guid) {
- Main.log("updateEpgEntry: Found " + this.childs[i].title);
- this.childs[i].payload.prog = entry.prog;
- this.childs[i].payload.desc = entry.desc;
- this.childs[i].payload.start = entry.start;
- this.childs[i].payload.dur = entry.dur;
- return true;
- }
- }
- }
- return false;
-};
-
-Item.prototype.print = function(level) {
- var prefix= "";
- for (var i = 0; i < level; i++)
- 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);
- }
- }
-};
-
-Item.prototype.createJQMDomTree = function(level) {
- var mydiv = $('<ul />');
-// if (level == 0) {
- mydiv.attr('data-role', 'listview');
- mydiv.attr('data-inset', 'true');
-// };
-//, id:'dyncreated'
- for (var i = 0; i < this.childs.length; i++) {
- if (this.childs[i].isFolder == true) {
- var myh = $('<div>', {text: this.childs[i].title});
- var myli = $('<li>');
- myli.append(myh);
- var mycount = $('<p>', {class: 'ui-li-count', text: this.childs[i].childs.length});
- myli.append(mycount);
- myli.append(this.childs[i].createJQMDomTree(level+1));
- mydiv.append(myli);
- }
- else {
- // Links
- var digi = new Date(this.childs[i].payload['start'] *1000);
- var mon = Data.getNumString ((digi.getMonth()+1), 2);
- var day = Data.getNumString (digi.getDate(), 2);
- var hour = Data.getNumString (digi.getHours(), 2);
- var min = Data.getNumString (digi.getMinutes(), 2);
-
- var d_str = mon + "/" + day + " " + hour + ":" + min;
- var mya = $('<a>', { text: d_str + " - " + this.childs[i].title,
- href: this.childs[i].payload['link'],
- rel: 'external'} );
- var myli = $('<li class="item"/>');
- myli.attr('data-icon', 'false');
- myli.attr('data-theme', 'c');
-
- myli.append(mya);
- mydiv.append(myli);
- }
- }
- return mydiv;
-};
-
-Item.prototype.sortPayload = function() {
- for (var i = 0; i < this.childs.length; i++) {
- if (this.childs[i].isFolder == true) {
- this.childs[i].sortPayload();
- }
- }
- this.childs.sort(function(a,b) {
- if (a.title == b.title) {
- return (b.payload.start - a.payload.start);
- }
- else {
- return ((a.title < b.title) ? -1 : 1);
- }
- });
-};
-
diff --git a/vdr-smarttvweb/web/Server.js b/vdr-smarttvweb/web/Server.js deleted file mode 100755 index 1ab6d0a..0000000 --- a/vdr-smarttvweb/web/Server.js +++ /dev/null @@ -1,180 +0,0 @@ -var Server = {
- dataReceivedCallback : null,
- errorCallback : null,
- doSort : false,
- retries : 0,
-
- XHRObj : null
-};
-
-Server.init = function()
-{
- var success = true;
-
- if (this.XHRObj) {
- this.XHRObj.destroy();
- this.XHRObj = null;
- }
-
- return success;
-};
-
-Server.setSort = function (val) {
- this.doSort = val;
-};
-//---------------------------------------------
-Server.fetchVideoList = function(url) {
-
- $.ajax({
- url: url,
- type : "GET",
- success : function(data, status, XHR ) {
-// Main.log("Server.fetchVideoList Success Response - status= " + status + " mime= " + XHR.responseType + " data= "+ data);
-
- $(data).find("item").each(function () {
- var title = $(this).find('title').text();
-// var link = $(this).find('link').text();
- var link = $(this).find('enclosure').attr('url');
- var guid = $(this).find('guid').text();
- var programme = $(this).find('programme').text();
- var description = $(this).find('description').text();
- var startVal = parseInt($(this).find('start').text());
- var durVal = parseInt($(this).find('duration').text());
- var fps = parseFloat($(this).find('fps').text());
- var ispes = $(this).find('ispes').text();
- var isnew = $(this).find('isnew').text();
-// Main.log("Server.fetchVideoList: title= " + title + " start= " + startVal + " dur= " + durVal + " fps= " + fps);
-
-/* if (Main.state == Main.eLIVE) {
- Epg.guidTitle[guid] = title;
- }
-*/
- var title_list = title.split("~");
- Data.addItem( title_list, {link : link, prog: programme, desc: description, guid : guid, start: startVal,
- dur: durVal, ispes : ispes, isnew : isnew, fps : fps});
-
- }); // each
-
- Data.completed(Server.doSort);
-
- if (Server.dataReceivedCallback) {
- Server.dataReceivedCallback();
- }
-
- },
- error : function (jqXHR, status, error) {
-// Main.logToServer("Server.fetchVideoList Error Response - status= " + status + " error= "+ error);
-// Display.showPopup("Error with XML File: " + status);
- Server.retries ++;
- },
- parsererror : function () {
- // Main.logToServer("Server.fetchVideoList parserError " );
- // Display.showPopup("Error in XML File");
- Server.retries ++;
- if (Server.errorCallback != null) {
- Server.errorCallback("XmlError");
- }
-
- }
- });
-};
-
-
-//---------------------------------------------
-
-Server.updateVdrStatus = function (){
- Main.log ("get VDR Status");
- $.ajax({
- url: Config.serverUrl + "/vdrstatus.xml",
- type : "GET",
- success : function(data, status, XHR){
- var free = $(data).find('free').text() / 1024.0;
- var used = $(data).find('used').text() / 1024.0;
- var percent = $(data).find('percent').text();
-
- var unit = "GB";
- var free_str = free.toFixed(2);
- if (free_str.length > 6) {
- free = free / 1024.0;
- free_str = free.toFixed(2);
- unit = "TB";
- }
- $("#logoDisk").text("Free: " +free_str + unit);
- $("#selectDisk").text("Free: " +free_str + unit);
- },
- error: function(jqXHR, status, error){
- Main.log("VdrStatus: Error");
- }
- });
-}
-
-
-Server.getResume = function (guid) {
-// Main.log ("***** getResume *****");
- $.ajax({
- url: Config.serverUrl + "/getResume.xml",
- type : "POST",
- data : "filename:" + guid +"\n",
- success : function(data, status, XHR ) {
- Main.log("**** Resome Success Response - status= " + status + " mime= " + XHR.responseType + " data= "+ data);
-
- var resume_str = $(data).find("resume").text();
- if (resume_str != "") {
- var resume_val = parseFloat(resume_str);
- Main.log("resume val= " + resume_val );
- Main.logToServer("resume val= " + resume_val );
- Player.resumePos = resume_val;
- Player.playVideo( resume_val);
- }
- else {
- Display.hide();
- Display.showProgress();
- Player.playVideo(-1);
- }
-
- },
- error : function (jqXHR, status, error) {
- Main.log("**** Resome Error Response - status= " + status + " error= "+ error);
- Display.hide();
- Display.showProgress();
- Player.playVideo(-1);
- }
- });
-};
-
-Server.saveResume = function() {
- var msg = "";
- msg += "filename:" + Data.getCurrentItem().childs[Main.selectedVideo].payload.guid + "\n";
- msg += "resume:"+ (Player.curPlayTime/1000) + "\n" ;
-
- $.post(Config.serverUrl + "/setResume.xml", msg, function(data, textStatus, XHR) {
- Main.logToServer("SaveResume Status= " + XHR.status );
- }, "text");
-
-};
-
-Server.deleteRecording = function(guid) {
- Main.log("Server.deleteRecording guid=" + guid);
- Main.logToServer("Server.deleteRecording guid=" + guid);
- Notify.handlerShowNotify("Deleting...", false);
-
- $.ajax({
- url: Config.serverUrl + "/deleteRecording.xml?id=" +guid,
- type : "POST",
- success : function(data, status, XHR ) {
- Notify.showNotify("Deleted", true);
- Data.deleteElm(Main.selectedVideo);
- if (Main.selectedVideo >= Data.getVideoCount())
- Main.selectedVideo = Data.getVideoCount() -1;
- Server.updateVdrStatus();
- Display.setVideoList(Main.selectedVideo, (Main.selectedVideo - Display.currentWindow));
- Main.logToServer("Server.deleteRecording: Success" );
- },
- error : function (XHR, status, error) {
- Main.logToServer("Server.deleteRecording: Error" );
-
- // show popup
- Notify.showNotify("Error", true);
- }
- });
-};
diff --git a/vdr-smarttvweb/web/favicon.ico b/vdr-smarttvweb/web/favicon.ico Binary files differdeleted file mode 100755 index 2236569..0000000 --- a/vdr-smarttvweb/web/favicon.ico +++ /dev/null diff --git a/vdr-smarttvweb/web/index.html b/vdr-smarttvweb/web/index.html deleted file mode 100755 index f396ed4..0000000 --- a/vdr-smarttvweb/web/index.html +++ /dev/null @@ -1,104 +0,0 @@ -<!DOCTYPE html> -<html> -<head> -<meta name="viewport" content="width=device-width, initial-scale=1"> -<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" /> -<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> -<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script> -<script language="javascript" type="text/javascript" src="Server.js"></script> -<script language="javascript" type="text/javascript" src="Data.js"></script> -<script> -$(document).ready(function(){ - var state = 'rec'; // Rec - - Server.init(); - - Server.dataReceivedCallback = function() { - console.log("Loaded"); - $("#anchor").append(Data.createJQMDomTree()).trigger('create'); - $.mobile.loading('hide'); - //http://jquerymobile.com/ - - // end of dataReceivedCallBack - }; - Server.errorCallback = function (msg) { - alert (msg); - buttonHandler('rec'); - }; - - $.mobile.loading('show'); - Server.setSort(true); - Server.fetchVideoList("/recordings.xml?mode=nodesc"); - - removeDomTree = function () { - // parent should not be deleted. - $("#anchor").children().remove(); - }; - - buttonHandler = function(btn) { - console.log("Click: " + btn); - if (state == btn) { - console.log("No Change"); - }; - $.mobile.loading('show'); - Data.reset(); - removeDomTree(); - switch (btn) { - case 'rec': - state = 'rec'; - $('#recbtn').addClass('ui-btn-active'); - $('#medbtn').removeClass('ui-btn-active'); - $('#chnbtn').removeClass('ui-btn-active'); - Server.setSort(true); - Server.fetchVideoList("/recordings.xml?mode=nodesc"); - break; - case 'med': - state = 'med'; - $('#medbtn').addClass('ui-btn-active'); - $('#recbtn').removeClass('ui-btn-active'); - $('#chnbtn').removeClass('ui-btn-active'); - Server.setSort(true); - Server.fetchVideoList("/media.xml"); - break; - case 'chn': - state = 'chn'; - $('#chnbtn').addClass('ui-btn-active'); - $('#medbtn').removeClass('ui-btn-active'); - $('#recbtn').removeClass('ui-btn-active'); - Server.setSort(false); - Server.fetchVideoList("/channels.xml?mode=nodesc"); - break; - }; - }; - -}); -</script> -<style type="text/css" > -h2 { margin:1.2em 0 .4em 0; } - } -</style> -</head> - -<body> - <div data-role="page" class="type-interior"> - - <div data-role="header" data-theme="b"> - <h1>Recordings</h1> - </div> <!-- /header --> - - <div data-role="content"> - <div class="content-primary" > - - <div data-role="controlgroup" data-type="horizontal" data-mini="true"> - <a href="#" id="recbtn" data-role="button" data-transition="fade" class="ui-btn-active" onclick="return buttonHandler('rec')">Recordings</a> - <a href="#" id="medbtn" data-role="button" data-transition="fade" onclick="return buttonHandler('med')">Media</a> - <a href="#" id="chnbtn" data-role="button" data-transition="fade" onclick="return buttonHandler('chn')">Channels</a> - </div> - - <div id="anchor"/> - </div> - </div> -</div> - </body> -</html> - diff --git a/vdr-smarttvweb/widget.conf b/vdr-smarttvweb/widget.conf deleted file mode 100644 index da4a006..0000000 --- a/vdr-smarttvweb/widget.conf +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<config> -<format>hls</format> -<tgtBufferBitrate>6000000</tgtBufferBitrate> -<totalBufferDuration>40</totalBufferDuration> -<initialBuffer>5</initialBuffer> -<pendingBuffer>5</pendingBuffer> -<initialTimeOut>5</initialTimeOut> -<skipDuration>30</skipDuration> -<liveChannels>20</liveChannels> -</config> |