This is an automated email from the git hooks/post-receive script. tiber-guest pushed a commit to branch master in repository vdr-plugin-vompserver.
commit baa7efb53be86a00970ac6bf4e20e76feb87d13f Author: Tobias Grimm <[email protected]> Date: Sat Feb 17 15:49:39 2018 +0100 New upstream version 0.5.0 --- Makefile | 7 +- config.c | 7 +- mediafile.c | 10 +- mvpreceiver.c | 15 +- mvpreceiver.h | 7 +- mvpserver.c | 60 ++++- mvpserver.h | 4 + picturereader.c | 397 ++++++++++++++++++++++++++++ picturereader.h | 75 ++++++ recplayer.c | 12 +- recplayer.h | 6 +- ringbuffer.c | 2 +- ringbuffer.h | 2 +- services/readme.txt | 3 + services/scraper2vdr.h | 196 ++++++++++++++ udpreplier.c | 4 +- vdrcommand.h | 13 +- vomp.conf.sample | 10 + vompclient.c | 62 ++--- vompclient.h | 19 +- vompclientrrproc.c | 702 ++++++++++++++++++++++++++++++++++++++++++------- vompclientrrproc.h | 15 +- vompserver.c | 19 +- 23 files changed, 1465 insertions(+), 182 deletions(-) diff --git a/Makefile b/Makefile index 9c99e28..b6a0d99 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ pri ### The directory environment: # Use package data if installed...otherwise assume we're under the VDR source directory: -PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc)) +PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell PKG_CONFIG_PATH="$$PKG_CONFIG_PATH:../../.." pkg-config --variable=$(1) vdr)) LIBDIR = $(call PKGCFG,libdir) LOCDIR = $(call PKGCFG,locdir) PLGCFG = $(call PKGCFG,plgcfg) @@ -53,7 +53,7 @@ SOFILE = libvdr-$(PLUGIN).so INCLUDES += -DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -D__STL_CONFIG_H # VOMP-INSERT DEFINES += -DVOMPSERVER @@ -68,7 +68,8 @@ OBJS += dsock.o mvpserver.o udpreplier.o bootpd.o tftpd.o i18n.o vompclient.o tc ringbuffer.o mvprelay.o vompclientrrproc.o \ config.o log.o thread.o tftpclient.o \ media.o responsepacket.o \ - mediafile.o mediaplayer.o servermediafile.o serialize.o medialauncher.o + mediafile.o mediaplayer.o servermediafile.o serialize.o medialauncher.o \ + picturereader.o OBJS2 = recplayer.o mvpreceiver.o # END-VOMP-INSERT diff --git a/config.c b/config.c index 3866abc..f4a5e01 100644 --- a/config.c +++ b/config.c @@ -137,7 +137,7 @@ FILE* Config::copyToHere(long position) while (newPos < position) { - fgets(buffer, BUFFER_LENGTH-1, file); + if (!fgets(buffer, BUFFER_LENGTH-1, file)) break; fputs(buffer, newFile); newPos += strlen(buffer); } @@ -183,7 +183,8 @@ int Config::deleteValue(const char* section, char* key) } FILE* newFile = copyToHere(ftell(file) - lastLineLength); - fgets(buffer, BUFFER_LENGTH-1, file); + + if ( fgets(buffer, BUFFER_LENGTH-1, file) ); return copyRest(newFile); } @@ -226,7 +227,7 @@ int Config::setValueString(const char* section, const char* key, const char* new return 0; } - fgets(buffer, BUFFER_LENGTH-1, file); + if ( fgets(buffer, BUFFER_LENGTH-1, file) ); fprintf(newFile, "%s = %s\n", key, newValue); return copyRest(newFile); } diff --git a/mediafile.c b/mediafile.c index 93bbfca..a148e5d 100644 --- a/mediafile.c +++ b/mediafile.c @@ -121,13 +121,19 @@ MediaList* MediaFile::getMediaList(const MediaURI * parent){ const char *dirname=parent->getName(); //open the directory and read out the entries DIR *d=opendir(dirname); + if (d == NULL) return rt; struct dirent *e; + + /* readdir_r is now deprecated in favour of readdir (which is effectively thread safe) union { // according to "The GNU C Library Reference Manual" struct dirent d; char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; } u; while (d != NULL && (readdir_r(d,&u.d,&e) == 0) && e != NULL) { + */ + + while (e = readdir(d)) { const char * fname=e->d_name; if ( fname == NULL) continue; if (strcmp(fname,".") == 0) continue; @@ -141,9 +147,9 @@ MediaList* MediaFile::getMediaList(const MediaURI * parent){ if (m) delete m; } } - if (d != NULL) closedir(d); + closedir(d); return rt; - } +} int MediaFile::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize) { diff --git a/mvpreceiver.c b/mvpreceiver.c index f4259a7..3ffb4b7 100644 --- a/mvpreceiver.c +++ b/mvpreceiver.c @@ -2,7 +2,7 @@ int MVPReceiver::numMVPReceivers = 0; -MVPReceiver* MVPReceiver::create(cChannel* channel, int priority) +MVPReceiver* MVPReceiver::create(const cChannel* channel, int priority) { #if VDRVERSNUM < 10500 bool NeedsDetachReceivers; @@ -34,7 +34,7 @@ MVPReceiver* MVPReceiver::create(cChannel* channel, int priority) return m; } -MVPReceiver::MVPReceiver(cChannel* channel, cDevice* device) +MVPReceiver::MVPReceiver(const cChannel* channel, cDevice* device) #if VDRVERSNUM < 10300 : cReceiver(channel->Ca(), 0, 7, channel->Vpid(), channel->Ppid(), channel->Apid1(), channel->Apid2(), channel->Dpid1(), channel->Dpid2(), channel->Tpid()) #elif VDRVERSNUM < 10500 @@ -57,7 +57,7 @@ MVPReceiver::MVPReceiver(cChannel* channel, cDevice* device) // logger->log("MVPReceiver", Log::DEBUG, "Channel has VPID %i APID %i", channel->Vpid(), channel->Apid(0)); - if (!processed.init(1000000)) return; + if (!processed.init(6000000)) return; // Ringbuffer increased for better performance pthread_mutex_init(&processedRingLock, NULL); // OK @@ -113,6 +113,7 @@ void MVPReceiver::detachMVPReceiver() Detach(); } + void MVPReceiver::Receive(UCHAR* data, int length) { pthread_mutex_lock(&processedRingLock); @@ -120,6 +121,14 @@ void MVPReceiver::Receive(UCHAR* data, int length) if (processed.getContent() > streamChunkSize) threadSignal(); pthread_mutex_unlock(&processedRingLock); } +void MVPReceiver::Receive(const UCHAR* data, int length) +{ + pthread_mutex_lock(&processedRingLock); + processed.put(data, length); + if (processed.getContent() > streamChunkSize) threadSignal(); + pthread_mutex_unlock(&processedRingLock); +} + void MVPReceiver::threadMethod() { diff --git a/mvpreceiver.h b/mvpreceiver.h index e1acf39..747e925 100644 --- a/mvpreceiver.h +++ b/mvpreceiver.h @@ -34,14 +34,14 @@ class MVPReceiver : public cReceiver, public Thread { public: - static MVPReceiver* create(cChannel*, int priority); + static MVPReceiver* create(const cChannel*, int priority); virtual ~MVPReceiver(); int init(TCP* tcp, ULONG streamID); bool isVdrActivated(); void detachMVPReceiver(); private: - MVPReceiver(cChannel* channel, cDevice* device); + MVPReceiver(const cChannel* channel, cDevice* device); Log* logger; bool vdrActivated; @@ -56,7 +56,8 @@ class MVPReceiver : public cReceiver, public Thread // cReciever stuff void Activate(bool On); - void Receive(UCHAR *Data, int Length); + void Receive(UCHAR *Data, int Length); // VDR 2.2.0 + void Receive(const UCHAR *Data, int Length); // > VDR 2.2.0 void sendStreamEnd(); static int numMVPReceivers; diff --git a/mvpserver.c b/mvpserver.c index 8ae63b8..bbf8fbd 100644 --- a/mvpserver.c +++ b/mvpserver.c @@ -30,10 +30,18 @@ MVPServer::MVPServer() // MH in case anbody has a better position :-) pthread_mutex_init(&threadClientMutex, NULL); tcpServerPort = 0; + logoDir = NULL; + resourceDir = NULL; + imageDir = NULL; + cacheDir = NULL; } MVPServer::~MVPServer() { + if (logoDir) delete[] logoDir; + if (resourceDir) delete[] resourceDir; + if (imageDir) delete[] imageDir; + if (cacheDir) delete[] cacheDir; stop(); } @@ -92,6 +100,56 @@ int MVPServer::run(char* tconfigDir) dsyslog("VOMP: Logging disabled"); } + const char *bigresdir = cPlugin::ResourceDirectory(); + const char *bigcachedir = cPlugin::CacheDirectory(); + // get logo directory + logoDir = config.getValueString("General", "Channel logo directory"); + + if (logoDir) + { + log.log("Main", Log::INFO, "LogoDir set %s", logoDir); + } else { + if (bigresdir) { + logoDir = new char[strlen(bigresdir)+1+7]; + sprintf(logoDir,"%s/logos/",bigresdir); + log.log("Main", Log::INFO, "No LogoDir set, default %s",logoDir); + } else { + log.log("Main", Log::INFO, "No LogoDir set, no res dir"); + } + + } + + // get epg Image directory + imageDir = config.getValueString("General", "Epg image directory"); + + if (imageDir) + { + log.log("Main", Log::INFO, "ImageDir set %s", imageDir); + } else { + if (bigcachedir) { + imageDir = new char[strlen(bigcachedir)+1+11+3]; + sprintf(imageDir,"%s/../epgimages/",bigcachedir); + log.log("Main", Log::INFO, "No ImageDir set, default %s",imageDir); + } else { + log.log("Main", Log::INFO, "No ImageDir set, no cache dir"); + } + } + + if (bigresdir) { + resourceDir = new char[strlen(bigresdir)+1]; + strcpy(resourceDir,bigresdir); + log.log("Main", Log::INFO, "Resource directory is %s",bigresdir); + } else { + log.log("Main", Log::INFO, "Resource directory is not set"); + } + + if (bigcachedir) { + cacheDir = new char[strlen(bigcachedir)+1]; + strcpy(cacheDir,bigcachedir); + log.log("Main", Log::INFO, "Cache directory is %s",bigcachedir); + } else { + log.log("Main", Log::INFO, "Cache directory is not set"); + } // Get UDP port number for discovery service int fail = 1; @@ -272,7 +330,7 @@ void MVPServer::threadMethod() while(1) { clientSocket = accept(listeningSocket,(struct sockaddr *)&address, &length); - VompClient* m = new VompClient(&config, configDir, clientSocket); + VompClient* m = new VompClient(&config, configDir, logoDir, resourceDir, imageDir, cacheDir, clientSocket); m->run(); } } diff --git a/mvpserver.h b/mvpserver.h index 80cc211..ed29c65 100644 --- a/mvpserver.h +++ b/mvpserver.h @@ -54,6 +54,10 @@ class MVPServer : public Thread MVPRelay mvprelay; int listeningSocket; char* configDir; + char* logoDir; + char* imageDir; + char* resourceDir; + char* cacheDir; USHORT tcpServerPort; }; diff --git a/picturereader.c b/picturereader.c new file mode 100644 index 0000000..59353b7 --- /dev/null +++ b/picturereader.c @@ -0,0 +1,397 @@ +#include "picturereader.h" +#include <vdr/plugin.h> +#include <vdr/channels.h> +#include <sstream> +#include <algorithm> + + +PictureReader::PictureReader(VompClient *client) +{ + logger = Log::getInstance(); + inittedOK = 0; + tcp = NULL; + x = client; + + pthread_mutex_init(&pictureLock, NULL); +} + +int PictureReader::init(TCP* ttcp) +{ + tcp = ttcp; + threadStart(); + + return inittedOK; +} + +PictureReader::~PictureReader() +{ + threadStop(); +} + +void PictureReader::addTVMediaRequest(TVMediaRequest& req) +{ + logger->log("PictRead",Log::DEBUG,"Got TVMediaRequest, signal thread!"); + + pthread_mutex_lock(&pictureLock); + pictures.push(req); + threadSignal(); // Signal, that we have something to do!!! + pthread_mutex_unlock(&pictureLock); +} + +bool PictureReader::epgImageExists(int event) +{ + if (x->imageDir) { + std::ostringstream file; + file<< std::string(x->imageDir)<< event << std::string(".jpg"); + if (!access(file.str().c_str() ,F_OK)) + { + return true; + } + + std::ostringstream file2; + file2 << std::string(x->imageDir) << event << std::string("_0.jpg"); + if (!access(file2.str().c_str() ,F_OK)) + { + return true; + } + } else if (x->cacheDir) { + + std::ostringstream file; + file<<std::string(x->cacheDir)<<std::string("/../epgimages/") + << event << std::string(".jpg"); + if (!access(file.str().c_str() ,F_OK)) + { + return true; + } + std::ostringstream file2; + file2<<std::string(x->cacheDir)<<std::string("/../epgimages/")<< + event <<std::string("_0.jpg"); + if (!access(file2.str().c_str() ,F_OK)) + { + return true; + } + } + return false; +} + +std::string PictureReader::getPictName(TVMediaRequest & req) +{ + logger->log("PictRead",Log::DEBUG, + "Request %d %d; %d %d %d %d",req.primary_id,req.secondary_id, + req.type,req.type_pict, + req.container,req.container_member); + + switch (req.type) { + case 0: { //serie + if (series.seriesId != (int)req.primary_id || + series.episodeId != (int)req.secondary_id) { + series.actors.clear(); + series.posters.clear(); + series.banners.clear(); + series.fanarts.clear(); + + series.seriesId = req.primary_id; + series.episodeId = req.secondary_id; + x->scraper->Service("GetSeries",&series); + } + if (req.type_pict == 0) { + switch (req.container) { + case 0: { + return series.episode.episodeImage.path; + } break; + case 1: { + if (series.actors.size()>req.container_member) { + return series.actors[req.container_member].actorThumb.path; + } + } break; + case 2: { + if (series.posters.size()>req.container_member) { + return series.posters[req.container_member].path; + } + } break; + case 3: { + if (series.banners.size()>req.container_member) { + return series.banners[req.container_member].path; + } + } break; + case 4: { + if (series.fanarts.size()>req.container_member) { + return series.fanarts[req.container_member].path; + } + } break; + case 5: { + return series.seasonPoster.path; + } break; + default: { + return std::string(""); + } break; + }; + } else if (req.type_pict == 1 && series.posters.size()) { //poster + std::string str=series.posters[0].path; + size_t pos=str.rfind('/'); + if (pos!=std::string::npos) { + str.resize(pos); + str=str+"poster_thumb.jpg"; + return str; + } + } else if (req.type_pict == 2) { //poster + std::string str=series.seasonPoster.path; + size_t pos=str.rfind('/'); + if (pos!=std::string::npos) { + str.resize(pos); + std::ostringstream out; + out << str << "season_" <<series.episode.season <<"_thumb.jpg"; + return out.str(); + } + } + return std::string(""); + } break; + case 1: { //movie + if (movie.movieId != (int)req.primary_id ) { + movie.actors.clear(); + movie.movieId = req.primary_id; + x->scraper->Service("GetMovie",&movie); + } + if (req.type_pict == 0) { + + switch (req.container) { + case 0: { + return movie.poster.path; + } break; + case 1: { + return movie.fanart.path; + } break; + case 2: { + return movie.collectionPoster.path; + } break; + case 3: { + return movie.collectionFanart.path; + } break; + case 4: { + if (movie.actors.size()>req.container_member) { + return movie.actors[req.container_member].actorThumb.path; + } + } break; + default: { + return std::string(""); + } break; + }; + } else if (req.type_pict == 1) { //poster + std::string str=movie.poster.path; + size_t pos=str.rfind('/'); + if (pos!=std::string::npos) { + str.resize(pos); + str=str+"poster_thumb.jpg"; + return str; + } + } + return std::string(""); + + + } break; + case 3: { // I do not know + // First get the recording +#if VDRVERSNUM >= 20301 + LOCK_RECORDINGS_READ; + const cRecordings* tRecordings = Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings* tRecordings = &Recordings; +#endif + const cRecording *recording = tRecordings->GetByName((char*) req.primary_name.c_str()); + ScraperGetPosterThumb getter; + getter.recording = recording; + getter.event = NULL; + if (x->scraper && recording) { + x->scraper->Service("GetPosterThumb",&getter); + return getter.poster.path; + } else { + return std::string(""); + } + }; break; + case 4: { // I do not know + // First get the schedules + +#if VDRVERSNUM >= 20301 + LOCK_CHANNELS_READ; + const cChannels* tChannels = Channels; +#else + cChannels* tChannels = &Channels; +#endif + + +#if VDRVERSNUM < 10300 + cMutexLock MutexLock; + const cSchedules *tSchedules = cSIProcessor::Schedules(MutexLock); +#elif VDRVERSNUM < 20301 + cSchedulesLock MutexLock; + const cSchedules *tSchedules = cSchedules::Schedules(MutexLock); +#else + LOCK_SCHEDULES_READ; + const cSchedules *tSchedules = Schedules; +#endif + + const cSchedule *Schedule = NULL; + if (tSchedules) + { + const cChannel* channel = tChannels->GetByChannelID(tChannelID::FromString(req.primary_name.c_str())); + Schedule = tSchedules->GetSchedule(channel); + } + const cEvent *event = NULL; + if (Schedule) event=Schedule->GetEvent(req.primary_id); + ScraperGetPosterThumb getter; + getter.event = event; + getter.recording = NULL; + + if (x->scraper && event) { + x->scraper->Service("GetPosterThumb",&getter); + if (getter.poster.width) return getter.poster.path; + } + if (x->imageDir) { + std::ostringstream file; + file<< std::string(x->imageDir)<< req.primary_id << std::string(".jpg"); + if (!access(file.str().c_str() ,F_OK)) + { + return file.str(); + } + + std::ostringstream file2; + file2 << std::string(x->imageDir) << req.primary_id << std::string("_0.jpg"); + if (!access(file2.str().c_str() ,F_OK)) + { + return file2.str(); + } + } else if (x->cacheDir) { + + std::ostringstream file; + file<<std::string(x->cacheDir)<<std::string("/../epgimages/") + <<req.primary_id << std::string(".jpg"); + if (!access(file.str().c_str() ,F_OK)) + { + return file.str(); + } + std::ostringstream file2; + file2<<std::string(x->cacheDir)<<std::string("/../epgimages/")<< + req.primary_id<<std::string("_0.jpg"); + if (!access(file2.str().c_str() ,F_OK)) + { + return file2.str(); + } + } + return std::string(""); + }; break; + case 5: { // Channel logo + std::transform(req.primary_name.begin(),req.primary_name.end(), + req.primary_name.begin(),::tolower); + if (x->logoDir) { + std::string file=std::string(x->logoDir)+req.primary_name+std::string(".png"); + if (!access(file.c_str() ,F_OK)) + { + return file; + } + } + // if noopacity is there steal the logos + if (x->resourceDir) { + std::string file=std::string(x->resourceDir) + +std::string("/skinnopacity/logos/")+req.primary_name+std::string(".png"); + if (!access(file.c_str() ,F_OK)) + { + return file; + } + } + return std::string(""); + + + }; break; + default: + return std::string(""); + break; + }; + return std::string(""); + +} + + +void PictureReader::threadMethod() +{ + ULONG *p; + ULONG headerLength = sizeof(ULONG) * 4; + UCHAR buffer[headerLength]; + +// threadSetKillable(); ?? + + logger->log("PictRead",Log::DEBUG,"PictureReaderThread started"); + while(1) + { + threadLock(); + threadWaitForSignal(); + threadUnlock(); + threadCheckExit(); + bool newpicture; + logger->log("PictRead",Log::DEBUG,"Thread was signaled, wake up"); + + do + { + newpicture = false; + TVMediaRequest req; + pthread_mutex_lock(&pictureLock); + if (!pictures.empty()) { + newpicture = true; + req = pictures.front(); + pictures.pop(); + } + pthread_mutex_unlock(&pictureLock); + if (!newpicture) break; + std::string pictname = getPictName(req); + UCHAR * mem = NULL; + ULONG memsize = 0; + ULONG flag = 2; + logger->log("PictRead",Log::DEBUG,"Load Pict %s",pictname.c_str()); + + + if (pictname.length()) { + struct stat st; + ULONG filesize = 0 ; + + stat(pictname.c_str(), &st); + filesize = st.st_size; + memsize = filesize + headerLength; + + if (memsize && memsize < 1000000) { // No pictures over 1 MB + mem = (UCHAR*)malloc(memsize); + if (mem) { + FILE * file=fopen(pictname.c_str(),"r"); + + if (file) { + size_t size=fread(mem+headerLength,1,filesize,file); + + fclose(file); + if (size!=filesize) memsize=headerLength; // error + else flag = 0; + } + } + } + } + if (!mem) { + mem = buffer; + } + + + + p = (ULONG*)&mem[0]; *p = htonl(5); // stream channel + p = (ULONG*)&mem[4]; *p = htonl(req.streamID); + p = (ULONG*)&mem[8]; *p = htonl(flag); // here insert flag: 0 = ok, data follows + p = (ULONG*)&mem[12]; *p = htonl(memsize); + + if (!tcp->sendPacket(mem, memsize + headerLength)) { + logger->log("PictRead",Log::DEBUG,"Sending Picture failed"); + } + + if (mem != buffer && mem) free(mem); + + } while (newpicture); + } + logger->log("PictRead",Log::DEBUG,"PictureReaderThread ended"); + +} + diff --git a/picturereader.h b/picturereader.h new file mode 100644 index 0000000..5cbbaec --- /dev/null +++ b/picturereader.h @@ -0,0 +1,75 @@ +/* + Copyright 2004-2005 Chris Tallon, 2014 Marten Richter + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef PICTUREREADER_H +#define PICTUREREADER_H + +#include "defines.h" +#include "log.h" +#include "thread.h" +#include "tcp.h" +#include "thread.h" +#include "vompclient.h" +#include "services/scraper2vdr.h" +#include <queue> +#include <string> + +struct TVMediaRequest{ + ULONG streamID; + ULONG type; + ULONG primary_id; + ULONG secondary_id; + ULONG type_pict; + ULONG container; + ULONG container_member; + std::string primary_name; +}; + +class PictureReader : public Thread +{ + public: + PictureReader(VompClient * client); + virtual ~PictureReader(); + int init(TCP* tcp); + void detachMVPReceiver(); + void addTVMediaRequest(TVMediaRequest&); + bool epgImageExists(int event); + + private: + + std::string getPictName(TVMediaRequest&); + + Log* logger; + int inittedOK; + pthread_mutex_t pictureLock; // needs outside locking + std::queue<TVMediaRequest> pictures; + + TCP* tcp; + VompClient * x; + cSeries series; + cMovie movie; + + protected: + void threadMethod(); +}; + +#endif + + diff --git a/recplayer.c b/recplayer.c index 9fac759..ce01e26 100644 --- a/recplayer.c +++ b/recplayer.c @@ -26,7 +26,7 @@ #include <fcntl.h> -RecPlayer::RecPlayer(cRecording* rec) +RecPlayer::RecPlayer(const cRecording* rec) { log = Log::getInstance(); file = NULL; @@ -76,7 +76,7 @@ void RecPlayer::scan() segments[i] = new Segment(); segments[i]->start = totalLength; fseek(file, 0, SEEK_END); - totalLength += ftell(file); + totalLength += ftello(file); totalFrames = indexFile->Last(); log->log("RecPlayer", Log::DEBUG, "File %i found, totalLength now %llu, numFrames = %lu", i, totalLength, totalFrames); segments[i]->end = totalLength; @@ -132,7 +132,7 @@ ULONG RecPlayer::getLengthFrames() unsigned long RecPlayer::getBlock(unsigned char* buffer, ULLONG position, unsigned long amount) { - if ((amount > totalLength) || (amount > 500000)) + if ((amount > totalLength) || (amount > 1000000)) { log->log("RecPlayer", Log::DEBUG, "Amount %lu requested and rejected", amount); return 0; @@ -168,7 +168,7 @@ unsigned long RecPlayer::getBlock(unsigned char* buffer, ULLONG position, unsign ULONG yetToGet = amount; ULONG got = 0; ULONG getFromThisSegment = 0; - ULONG filePosition; + ULLONG filePosition; while(got < amount) { @@ -186,7 +186,7 @@ unsigned long RecPlayer::getBlock(unsigned char* buffer, ULLONG position, unsign getFromThisSegment = segments[segmentNumber]->end - currentPosition; filePosition = currentPosition - segments[segmentNumber]->start; - fseek(file, filePosition, SEEK_SET); + fseeko(file, filePosition, SEEK_SET); if (fread(&buffer[got], getFromThisSegment, 1, file) != 1) return 0; // umm, big problem. // Tell linux not to bother keeping the data in the FS cache @@ -206,7 +206,7 @@ ULLONG RecPlayer::getLastPosition() return lastPosition; } -cRecording* RecPlayer::getCurrentRecording() +const cRecording* RecPlayer::getCurrentRecording() { return recording; } diff --git a/recplayer.h b/recplayer.h index 95f310a..288e60d 100644 --- a/recplayer.h +++ b/recplayer.h @@ -37,14 +37,14 @@ class Segment class RecPlayer { public: - RecPlayer(cRecording* rec); + RecPlayer(const cRecording* rec); ~RecPlayer(); ULLONG getLengthBytes(); ULONG getLengthFrames(); unsigned long getBlock(unsigned char* buffer, ULLONG position, unsigned long amount); int openFile(int index); ULLONG getLastPosition(); - cRecording* getCurrentRecording(); + const cRecording* getCurrentRecording(); void scan(); ULLONG positionFromFrameNumber(ULONG frameNumber); ULONG frameNumberFromPosition(ULLONG position); @@ -52,7 +52,7 @@ class RecPlayer private: Log* log; - cRecording* recording; + const cRecording* recording; cIndexFile* indexFile; FILE* file; int fileOpen; diff --git a/ringbuffer.c b/ringbuffer.c index 20db41c..9de4be9 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -49,7 +49,7 @@ int Ringbuffer::init(size_t size) return 1; } -int Ringbuffer::put(UCHAR* from, size_t amount) +int Ringbuffer::put(const UCHAR* from, size_t amount) { if (amount > capacity) return 0; diff --git a/ringbuffer.h b/ringbuffer.h index c5a6e14..139eb72 100644 --- a/ringbuffer.h +++ b/ringbuffer.h @@ -33,7 +33,7 @@ class Ringbuffer Ringbuffer(); ~Ringbuffer(); int init(size_t size); - int put(UCHAR* from, size_t amount); + int put(const UCHAR* from, size_t amount); int get(UCHAR* to, size_t amount); int getContent(); diff --git a/services/readme.txt b/services/readme.txt new file mode 100644 index 0000000..94d29c4 --- /dev/null +++ b/services/readme.txt @@ -0,0 +1,3 @@ +In this directories are API header files for calls to other plugins. +Copyright by the authors of the respective plugins. +* scraper2vdr by Louis Braun \ No newline at end of file diff --git a/services/scraper2vdr.h b/services/scraper2vdr.h new file mode 100644 index 0000000..80a3374 --- /dev/null +++ b/services/scraper2vdr.h @@ -0,0 +1,196 @@ +#ifndef __SCRAPER2VDRSERVICES_H +#define __SCRAPER2VDRSERVICES_H + +#include <string> +#include <vector> +#include <vdr/epg.h> +#include <vdr/recording.h> + +enum tvType { + tSeries, + tMovie, + tNone, +}; + +/********************************************************************* +* Helper Structures +*********************************************************************/ +class cTvMedia { +public: + cTvMedia(void) { + path = ""; + width = height = 0; + }; + std::string path; + int width; + int height; +}; + +class cEpisode { +public: + cEpisode(void) { + number = 0; + season = 0; + name = ""; + firstAired = ""; + guestStars = ""; + overview = ""; + rating = 0.0; + }; + int number; + int season; + std::string name; + std::string firstAired; + std::string guestStars; + std::string overview; + float rating; + cTvMedia episodeImage; +}; + +class cActor { +public: + cActor(void) { + name = ""; + role = ""; + }; + std::string name; + std::string role; + cTvMedia actorThumb; +}; + +/********************************************************************* +* Data Structures for Service Calls +*********************************************************************/ + +// Data structure for service "GetEventType" +class ScraperGetEventType { +public: + ScraperGetEventType(void) { + event = NULL; + recording = NULL; + type = tNone; + movieId = 0; + seriesId = 0; + episodeId = 0; + }; +// in + const cEvent *event; // check type for this event + const cRecording *recording; // or for this recording +//out + tvType type; //typeSeries or typeMovie + int movieId; + int seriesId; + int episodeId; +}; + +//Data structure for full series and episode information +class cMovie { +public: + cMovie(void) { + title = ""; + originalTitle = ""; + tagline = ""; + overview = ""; + adult = false; + collectionName = ""; + budget = 0; + revenue = 0; + genres = ""; + homepage = ""; + releaseDate = ""; + runtime = 0; + popularity = 0.0; + voteAverage = 0.0; + }; +//IN + int movieId; // movieId fetched from ScraperGetEventType +//OUT + std::string title; + std::string originalTitle; + std::string tagline; + std::string overview; + bool adult; + std::string collectionName; + int budget; + int revenue; + std::string genres; + std::string homepage; + std::string releaseDate; + int runtime; + float popularity; + float voteAverage; + cTvMedia poster; + cTvMedia fanart; + cTvMedia collectionPoster; + cTvMedia collectionFanart; + std::vector<cActor> actors; +}; + +//Data structure for full series and episode information +class cSeries { +public: + cSeries(void) { + seriesId = 0; + episodeId = 0; + name = ""; + overview = ""; + firstAired = ""; + network = ""; + genre = ""; + rating = 0.0; + status = ""; + }; +//IN + int seriesId; // seriesId fetched from ScraperGetEventType + int episodeId; // episodeId fetched from ScraperGetEventType +//OUT + std::string name; + std::string overview; + std::string firstAired; + std::string network; + std::string genre; + float rating; + std::string status; + cEpisode episode; + std::vector<cActor> actors; + std::vector<cTvMedia> posters; + std::vector<cTvMedia> banners; + std::vector<cTvMedia> fanarts; + cTvMedia seasonPoster; +}; + +// Data structure for service "GetPosterBanner" +class ScraperGetPosterBanner { +public: + ScraperGetPosterBanner(void) { + type = tNone; + }; +// in + const cEvent *event; // check type for this event +//out + tvType type; //typeSeries or typeMovie + cTvMedia poster; + cTvMedia banner; +}; + +// Data structure for service "GetPoster" +class ScraperGetPoster { +public: +// in + const cEvent *event; // check type for this event + const cRecording *recording; // or for this recording +//out + cTvMedia poster; +}; + +// Data structure for service "GetPosterThumb" +class ScraperGetPosterThumb { +public: +// in + const cEvent *event; // check type for this event + const cRecording *recording; // or for this recording +//out + cTvMedia poster; +}; + +#endif //__SCRAPER2VDRSERVICES_H \ No newline at end of file diff --git a/udpreplier.c b/udpreplier.c index a98a1e2..88f83e4 100644 --- a/udpreplier.c +++ b/udpreplier.c @@ -84,11 +84,11 @@ int UDPReplier::run(USHORT port, char* serverName, USHORT serverPort) USHORT temp = htons(serverPort); memcpy(&message[26], &temp, 2); - ULONG temp2 = htonl(VompClientRRProc::getProtocolVersion()); + ULONG temp2 = htonl(VompClientRRProc::getProtocolVersionMin()); memcpy(&message[28], &temp2, 4); strcpy(&message[32], serverName); - + // Fix Me add also the maximum version somewhere if (!ds.init(port)) { shutdown(); diff --git a/vdrcommand.h b/vdrcommand.h index 76dde28..c9e4032 100644 --- a/vdrcommand.h +++ b/vdrcommand.h @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with VOMP; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef VDRCOMMAND_H @@ -63,11 +63,22 @@ const static ULONG VDR_GETCHANNELPIDS = 22; const static ULONG VDR_DELETETIMER = 23; const static ULONG VDR_GETLANGUAGELIST = 33; const static ULONG VDR_GETLANGUAGECONTENT = 34; +const static ULONG VDR_SETCHARSET = 37; const static ULONG VDR_GETMEDIALIST = 30; const static ULONG VDR_OPENMEDIA = 31; const static ULONG VDR_GETMEDIABLOCK = 32; const static ULONG VDR_GETMEDIAINFO = 35; const static ULONG VDR_CLOSECHANNEL = 36; +const static ULONG VDR_GETRECSCRAPEREVENTTYPE = 38; +const static ULONG VDR_GETSCRAPERMOVIEINFO = 39; +const static ULONG VDR_GETSCRAPERSERIESINFO = 40; +const static ULONG VDR_LOADTVMEDIA =41; +const static ULONG VDR_LOADTVMEDIARECTHUMB =42; +const static ULONG VDR_GETEVENTSCRAPEREVENTTYPE = 43; +const static ULONG VDR_LOADTVMEDIAEVENTTHUMB =44; +const static ULONG VDR_LOADCHANNELLOGO = 45; + +const static ULONG VDR_SHUTDOWN = 666; class VDR_Command : public SerializableList { public: diff --git a/vomp.conf.sample b/vomp.conf.sample index e83756a..49b6caf 100644 --- a/vomp.conf.sample +++ b/vomp.conf.sample @@ -34,3 +34,13 @@ # MVPRelay enabled = yes +# Change the following to the directory, where the channel logos reside, +# all png and the channel name in lower case +# if not set a logo directory below the plugin directory is used + +# Channel logo directory = /logodir + +# Change the following to the directory, where the EPG image reside, +# if not set a image directory is try to be set automatically + +# Epg image directory = /EpgImage diff --git a/vompclient.c b/vompclient.c index 011b5c6..37de93c 100644 --- a/vompclient.c +++ b/vompclient.c @@ -29,23 +29,32 @@ #ifndef VOMPSTANDALONE #include <vdr/channels.h> #include <vdr/recording.h> +#include <vdr/plugin.h> #include "recplayer.h" #include "mvpreceiver.h" +#include "picturereader.h" #endif pthread_mutex_t threadClientMutex; int VompClient::nr_clients = 0; +cPlugin *VompClient::scraper = NULL; +time_t VompClient::lastScrapQuery = 0; - -VompClient::VompClient(Config* cfgBase, char* tconfigDir, int tsocket) +VompClient::VompClient(Config* cfgBase, char* tconfigDir, char* tlogoDir, + char *tresourceDir, char * timageDir, char * tcacheDir, int tsocket) : rrproc(*this), tcp(tsocket), i18n(tconfigDir) { #ifndef VOMPSTANDALONE lp = NULL; recplayer = NULL; - recordingManager = NULL; + pict = new PictureReader(this); + if (!scraper) scrapQuery(); + logoDir = tlogoDir; + resourceDir = tresourceDir; + imageDir = timageDir; + cacheDir = tcacheDir; #endif log = Log::getInstance(); loggedIn = false; @@ -79,14 +88,14 @@ VompClient::~VompClient() writeResumeData(); delete recplayer; - delete recordingManager; recplayer = NULL; - recordingManager = NULL; } #endif //if (loggedIn) cleanConfig(); decClients(); + delete pict; + delete media; delete mediaprovider; @@ -101,6 +110,16 @@ VompClient::~VompClient() } } +cPlugin *VompClient::scrapQuery() +{ + if (scraper) return scraper; + if ((time(NULL)-lastScrapQuery) > 5*60) { + lastScrapQuery = time(NULL); + if (!scraper) scraper = cPluginManager::GetPlugin("scraper2vdr"); + } + return scraper; +} + void VompClient::setCharset(int charset) { charcoding=charset; @@ -237,6 +256,7 @@ void VompClient::run2() // tcp.setSoKeepTime(3); tcp.setNonBlocking(); + pict->init(&tcp); ULONG channelID; ULONG requestID; ULONG opcode; @@ -386,38 +406,6 @@ ULLONG VompClient::htonll(ULLONG a) #ifndef VOMPSTANDALONE -cChannel* VompClient::channelFromNumber(ULONG channelNumber) -{ - cChannel* channel = NULL; - - for (channel = Channels.First(); channel; channel = Channels.Next(channel)) - { - if (!channel->GroupSep()) - { - log->log("Client", Log::DEBUG, "Looking for channel %lu::: number: %i name: '%s'", channelNumber, channel->Number(), channel->Name()); - - if (channel->Number() == (int)channelNumber) - { - int vpid = channel->Vpid(); -#if VDRVERSNUM < 10300 - int apid1 = channel->Apid1(); -#else - int apid1 = channel->Apid(0); -#endif - log->log("Client", Log::DEBUG, "Found channel number %lu, vpid = %i, apid1 = %i", channelNumber, vpid, apid1); - return channel; - } - } - } - - if (!channel) - { - log->log("Client", Log::DEBUG, "Channel not found"); - } - - return channel; -} - void VompClient::writeResumeData() { /*config.setValueLong("ResumeData", diff --git a/vompclient.h b/vompclient.h index 4ec905e..7a4f20c 100644 --- a/vompclient.h +++ b/vompclient.h @@ -48,7 +48,7 @@ class RecPlayer; class MVPReceiver; class cChannel; -class cRecordings; +class cPlugin; #endif #include "defines.h" @@ -62,13 +62,16 @@ class ResponsePacket; class ServerMediaFile; class SerializeBuffer; class MediaPlayer; +class PictureReader; class VompClient { friend class VompClientRRProc; + friend class PictureReader; public: - VompClient(Config* baseConfig, char* configDir, int tsocket); + VompClient(Config* baseConfig, char* configDir, char* logoDir, + char* resourceDir, char* imageDir, char*cacheDir, int tsocket); ~VompClient(); int run(); @@ -101,12 +104,19 @@ class VompClient //void cleanConfig(); #ifndef VOMPSTANDALONE - cChannel* channelFromNumber(ULONG channelNumber); void writeResumeData(); MVPReceiver* lp; - cRecordings* recordingManager; RecPlayer* recplayer; + static cPlugin * scraper; + static time_t lastScrapQuery; + static cPlugin* scrapQuery(); + PictureReader * pict; + char *logoDir; + char *imageDir; + char *resourceDir; + char *cacheDir; + #endif MediaPlayer *media; ServerMediaFile *mediaprovider; @@ -116,6 +126,7 @@ class VompClient cCharSetConv *charconvutf8; cCharSetConv *charconvsys; + }; #endif diff --git a/vompclientrrproc.c b/vompclientrrproc.c index 841d382..f8e8d7d 100644 --- a/vompclientrrproc.c +++ b/vompclientrrproc.c @@ -30,6 +30,7 @@ #include <vdr/remote.h> #include "recplayer.h" #include "mvpreceiver.h" +#include "services/scraper2vdr.h" #endif #include "vompclientrrproc.h" @@ -40,20 +41,65 @@ #include "servermediafile.h" #include "i18n.h" #include "vdrcommand.h" +#include "picturereader.h" bool ResumeIDLock; -ULONG VompClientRRProc::VOMP_PROTOCOL_VERSION = 0x00000300; +ULONG VompClientRRProc::VOMP_PROTOCOL_VERSION_MIN = 0x00000301; +ULONG VompClientRRProc::VOMP_PROTOCOL_VERSION_MAX = 0x00000400; // format is aabbccdd // cc is release protocol version, increase with every release, that changes protocol // dd is development protocol version, set to zero at every release, // increase for every protocol change in git // bb not equal zero should indicate a non loggytronic protocol // aa is reserved for future use +// VOMP_PROTOCOL_VERSION_MIN is the protocol version minimal supported by the server +// VOMP_PROTOCOL_VERSION_MAX is the protocol version maximal supported by the server +// This allows to run older clients from a new server +// Increase the minimal protocol version everytime you break compatibility for a certain +// command. + + +/* Locking information from VDR: + + + Instead of directly accessing the global variables Timers, Channels or Recordings, + they need to set up a cStateKey variable and call the proper getter function, + as in + cStateKey StateKey; + if (const cTimers *Timers = cTimers::GetTimersRead(StateKey)) { + // access the timers + StateKey.Remove(); + } + and + cStateKey StateKey; + if (cTimers *Timers = cTimers::GetTimersWrite(StateKey)) { + // access the timers + StateKey.Remove(); + } + See timers.h, thread.h and tools.h for details on this new locking mechanism. + + There are convenience macros for easily accessing these lists without having + to explicitly set up a cStateKey and calling its Remove() function. These macros + have the form LOCK_*_READ/WRITE (with '*' being TIMERS, CHANNELS, SCHEDULES or + RECORDINGS). Simply put such a macro before the point where you need to access + the respective list, and there will be a pointer named Timers, Channels, Schedules + or Recordings, respectively, which is valid until the end of the current block. + + If a plugin needs to access several of the global lists in parallel, locking must + always be done in the sequence Timers, Channels, Recordings, Schedules. This is + necessary to make sure that different threads that need to lock several lists at + the same time don't end up in a deadlock. + + */ + +// TODO: Use VDRs recording->ChangeName(option)) for move recording ? + +ULONG VompClientRRProc::getProtocolVersionMin() +{ + return VOMP_PROTOCOL_VERSION_MIN; +} -ULONG VompClientRRProc::getProtocolVersion() +ULONG VompClientRRProc::getProtocolVersionMax() { - return VOMP_PROTOCOL_VERSION; + return VOMP_PROTOCOL_VERSION_MAX; } VompClientRRProc::VompClientRRProc(VompClient& x) @@ -262,6 +308,30 @@ bool VompClientRRProc::processPacket() case 666: result = processVDRShutdown(); break; + case VDR_GETRECSCRAPEREVENTTYPE: + result = processGetRecScraperEventType(); + break; + case VDR_GETSCRAPERMOVIEINFO: + result = processGetScraperMovieInfo(); + break; + case VDR_GETSCRAPERSERIESINFO: + result = processGetScraperSeriesInfo(); + break; + case VDR_LOADTVMEDIA: + result = processLoadTvMedia(); + break; + case VDR_LOADTVMEDIARECTHUMB: + result = processLoadTvMediaRecThumb(); + break; + case VDR_GETEVENTSCRAPEREVENTTYPE: + result = processGetEventScraperEventType(); + break; + case VDR_LOADTVMEDIAEVENTTHUMB: + result = processLoadTvMediaEventThumb(); + break; + case VDR_LOADCHANNELLOGO: + result = processLoadChannelLogo(); + break; #endif case VDR_GETMEDIALIST: result = processGetMediaList(); @@ -300,6 +370,7 @@ bool VompClientRRProc::processPacket() return false; } + int VompClientRRProc::processLogin() { if (req->dataLength != 6) return 0; @@ -318,7 +389,18 @@ int VompClientRRProc::processLogin() resp->addULONG(timeNow); resp->addLONG(timeOffset); - resp->addULONG(VOMP_PROTOCOL_VERSION); + resp->addULONG(VOMP_PROTOCOL_VERSION_MIN); + resp->addULONG(VOMP_PROTOCOL_VERSION_MAX); + + // also send information about languages + resp->addULONG(I18nLanguages()->Size()); + resp->addLONG(Setup.DisplaySubtitles); + for (int i=0;i < I18nLanguages()->Size(); i++) { + resp->addLONG(Setup.AudioLanguages[i]); + resp->addLONG(Setup.SubtitleLanguages[i]); + resp->addString(I18nLanguageCode(i)); + } + resp->finalise(); x.tcp.sendPacket(resp->getPtr(), resp->getLen()); log->log("RRProc", Log::DEBUG, "written login reply len %lu", resp->getLen()); @@ -668,10 +750,15 @@ int VompClientRRProc::processGetRecordingsList() resp->addULONG(FreeMB); resp->addULONG(Percent); - cRecordings Recordings; - Recordings.Load(); +#if VDRVERSNUM >= 20301 + LOCK_RECORDINGS_READ; + const cRecordings* tRecordings = Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + const cRecordings* tRecordings = &Recordings; +#endif - for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) + for (const cRecording *recording = tRecordings->First(); recording; recording = tRecordings->Next(recording)) { #if VDRVERSNUM < 10721 resp->addULONG(recording->start); @@ -695,10 +782,15 @@ int VompClientRRProc::processDeleteRecording() { // data is a pointer to the fileName string - cRecordings Recordings; - Recordings.Load(); // probably have to do this +#if VDRVERSNUM >= 20301 + LOCK_RECORDINGS_WRITE; + cRecordings* tRecordings = Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings* tRecordings = &Recordings; +#endif - cRecording* recording = Recordings.GetByName((char*)req->data); + cRecording* recording = tRecordings->GetByName((char*)req->data); log->log("RRProc", Log::DEBUG, "recording pointer %p", recording); @@ -706,13 +798,17 @@ int VompClientRRProc::processDeleteRecording() { log->log("RRProc", Log::DEBUG, "deleting recording: %s", recording->Name()); +// TODO: Switch to using: cRecording::IsInUse(void) const cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName()); if (!rc) { if (recording->Delete()) { +#if VDRVERSNUM >= 20301 + tRecordings->DelByName(recording->FileName()); + tRecordings->SetModified(); +#elif VDRVERSNUM > 10300 // Copy svdrp's way of doing this, see if it works -#if VDRVERSNUM > 10300 ::Recordings.DelByName(recording->FileName()); #endif resp->addULONG(1); @@ -754,15 +850,22 @@ int VompClientRRProc::processMoveRecording() } if (!newPath) return 0; - cRecordings Recordings; - Recordings.Load(); // probably have to do this - cRecording* recording = Recordings.GetByName((char*)fileName); +#if VDRVERSNUM >= 20301 + LOCK_RECORDINGS_WRITE; + cRecordings* tRecordings = Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings* tRecordings = &Recordings; +#endif + + cRecording* recording = tRecordings->GetByName((char*)fileName); log->log("RRProc", Log::DEBUG, "recording pointer %p", recording); if (recording) { + // TODO: Switch to using: int cRecording::IsInUse(void) const cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName()); if (!rc) { @@ -857,6 +960,7 @@ int VompClientRRProc::processMoveRecording() return 1; } + // Ok, the directory container has been made, or it pre-existed. char* newDir = new char[strlen(newContainer) + 1 + strlen(dateDirName) + 1]; @@ -873,12 +977,10 @@ int VompClientRRProc::processMoveRecording() log->log("RRProc", Log::DEBUG, "len: %i, cp: %i, strlen: %i, oldtitledir: %s", k+1, k, strlen(oldTitleDir), oldTitleDir); rmdir(oldTitleDir); // can't do anything about a fail result at this point. delete[] oldTitleDir; - } - if (renameret == 0) - { -#if VDRVERSNUM > 10311 - // Tell VDR +#if VDRVERSNUM >= 20301 + tRecordings->SetModified(); +#elif VDRVERSNUM > 10311 ::Recordings.Update(); #endif // Success. Send a different packet from just a ulong @@ -923,7 +1025,14 @@ int VompClientRRProc::processGetChannelsList() int allChans = 1; if (chanConfig) allChans = strcasecmp(chanConfig, "FTA only"); - for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) +#if VDRVERSNUM >= 20301 + LOCK_CHANNELS_READ; + const cChannels* tChannels = Channels; +#else + const cChannels* tChannels = &Channels; +#endif + + for (const cChannel *channel = tChannels->First(); channel; channel = tChannels->Next(channel)) { #if VDRVERSNUM < 10300 if (!channel->GroupSep() && (!channel->Ca() || allChans)) @@ -964,7 +1073,14 @@ int VompClientRRProc::processGetChannelPids() { ULONG channelNumber = ntohl(*(ULONG*)req->data); - cChannel* channel = x.channelFromNumber(channelNumber); +#if VDRVERSNUM >= 20301 + LOCK_CHANNELS_READ; + const cChannels* tChannels = Channels; +#else + cChannels* tChannels = &Channels; +#endif + + const cChannel* channel = tChannels->GetByNumber(channelNumber); if (!channel) { resp->addULONG(0); @@ -1139,7 +1255,14 @@ int VompClientRRProc::processStartStreamingChannel() log->log("RRProc", Log::DEBUG, "req->dataLength = %i", req->dataLength); ULONG channelNumber = ntohl(*(ULONG*)req->data); - cChannel* channel = x.channelFromNumber(channelNumber); +#if VDRVERSNUM >= 20301 + LOCK_CHANNELS_READ; + const cChannels* tChannels = Channels; +#else + cChannels* tChannels = &Channels; +#endif + + const cChannel* channel = tChannels->GetByNumber(channelNumber); if (!channel) { resp->addULONG(0); @@ -1210,9 +1333,7 @@ int VompClientRRProc::processStopStreaming() x.writeResumeData(); delete x.recplayer; - delete x.recordingManager; x.recplayer = NULL; - x.recordingManager = NULL; } resp->addULONG(1); @@ -1267,10 +1388,15 @@ int VompClientRRProc::processStartStreamingRecording() { // data is a pointer to the fileName string - x.recordingManager = new cRecordings; - x.recordingManager->Load(); +#if VDRVERSNUM >= 20301 + LOCK_RECORDINGS_READ; + const cRecordings* tRecordings = Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings* tRecordings = &Recordings; +#endif - cRecording* recording = x.recordingManager->GetByName((char*)req->data); + const cRecording* recording = tRecordings->GetByName((char*)req->data); log->log("RRProc", Log::DEBUG, "recording pointer %p", recording); @@ -1292,11 +1418,7 @@ int VompClientRRProc::processStartStreamingRecording() log->log("RRProc", Log::DEBUG, "written totalLength"); } - else - { - delete x.recordingManager; - x.recordingManager = NULL; - } + return 1; } @@ -1401,7 +1523,14 @@ int VompClientRRProc::processGetChannelSchedule() log->log("RRProc", Log::DEBUG, "get schedule called for channel %lu", channelNumber); - cChannel* channel = x.channelFromNumber(channelNumber); +#if VDRVERSNUM >= 20301 + LOCK_CHANNELS_READ; + const cChannels* tChannels = Channels; +#else + cChannels* tChannels = &Channels; +#endif + + const cChannel* channel = tChannels->GetByNumber(channelNumber); if (!channel) { resp->addULONG(0); @@ -1416,12 +1545,16 @@ int VompClientRRProc::processGetChannelSchedule() #if VDRVERSNUM < 10300 cMutexLock MutexLock; - const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock); -#else + const cSchedules *tSchedules = cSIProcessor::Schedules(MutexLock); +#elif VDRVERSNUM < 20301 cSchedulesLock MutexLock; - const cSchedules *Schedules = cSchedules::Schedules(MutexLock); + const cSchedules *tSchedules = cSchedules::Schedules(MutexLock); +#else + LOCK_SCHEDULES_READ; + const cSchedules *tSchedules = Schedules; #endif - if (!Schedules) + + if (!tSchedules) { resp->addULONG(0); resp->finalise(); @@ -1433,7 +1566,7 @@ int VompClientRRProc::processGetChannelSchedule() log->log("RRProc", Log::DEBUG, "Got schedule!s! object"); - const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID()); + const cSchedule *Schedule = tSchedules->GetSchedule(channel->GetChannelID()); if (!Schedule) { resp->addULONG(0); @@ -1525,14 +1658,21 @@ int VompClientRRProc::processGetChannelSchedule() int VompClientRRProc::processGetTimers() { - cTimer *timer; - int numTimers = Timers.Count(); +#if VDRVERSNUM >= 20301 + LOCK_TIMERS_READ; + const cTimers* tTimers = Timers; +#else + const cTimers* tTimers = &Timers; +#endif + + const cTimer *timer; + int numTimers = tTimers->Count(); resp->addULONG(numTimers); for (int i = 0; i < numTimers; i++) { - timer = Timers.Get(i); + timer = tTimers->Get(i); #if VDRVERSNUM < 10300 resp->addULONG(timer->Active()); @@ -1597,36 +1737,43 @@ int VompClientRRProc::processSetTimer() log->log("RRProc", Log::DEBUG, "%s", timerString); cTimer *timer = new cTimer; - if (timer->Parse((char*)timerString)) + if (!timer->Parse((char*)timerString)) { - cTimer *t = Timers.GetTimer(timer); - if (!t) - { - Timers.Add(timer); -#if VDRVERSNUM < 10300 - Timers.Save(); + resp->addULONG(2); + resp->finalise(); + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + delete timer; + return 1; + } + +#if VDRVERSNUM >= 20301 + LOCK_TIMERS_WRITE; + cTimers* tTimers = Timers; #else - Timers.SetModified(); + cTimers* tTimers = &Timers; #endif - resp->addULONG(0); - resp->finalise(); - x.tcp.sendPacket(resp->getPtr(), resp->getLen()); - return 1; // FIXME - cTimer* timer is leaked here! - } - else - { - resp->addULONG(1); - resp->finalise(); - x.tcp.sendPacket(resp->getPtr(), resp->getLen()); - } - } - else + + cTimer *t = tTimers->GetTimer(timer); + if (t) { - resp->addULONG(2); + resp->addULONG(1); resp->finalise(); x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + delete timer; + return 1; } - delete timer; + + timer->ClrFlags(tfRecording); + tTimers->Add(timer); +#if VDRVERSNUM < 10300 + tTimers->Save(); +#elif VDRVERSNUM < 20301 + tTimers->SetModified(); +#endif + + resp->addULONG(0); + resp->finalise(); + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); return 1; } @@ -1642,9 +1789,16 @@ int VompClientRRProc::processDeleteTimer() INT delDay = ntohl(*(ULONG*)&req->data[position]); position += 4; INT delStart = ntohl(*(ULONG*)&req->data[position]); position += 4; INT delStop = ntohl(*(ULONG*)&req->data[position]); position += 4; - + +#if VDRVERSNUM >= 20301 + LOCK_TIMERS_WRITE; + cTimers* tTimers = Timers; +#else + cTimers* tTimers = &Timers; +#endif + cTimer* ti = NULL; - for (ti = Timers.First(); ti; ti = Timers.Next(ti)) + for (ti = tTimers->First(); ti; ti = tTimers->Next(ti)) { if ( (ti->Channel()->Number() == delChannel) && ((ti->WeekDays() && (ti->WeekDays() == delWeekdays)) || (!ti->WeekDays() && (ti->Day() == delDay))) @@ -1660,51 +1814,56 @@ int VompClientRRProc::processDeleteTimer() x.tcp.sendPacket(resp->getPtr(), resp->getLen()); return 1; } - - if (!Timers.BeingEdited()) - { - if (!ti->Recording()) - { - Timers.Del(ti); - Timers.SetModified(); - resp->addULONG(10); - resp->finalise(); - x.tcp.sendPacket(resp->getPtr(), resp->getLen()); - return 1; - } - else - { - log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running"); - resp->addULONG(3); - resp->finalise(); - x.tcp.sendPacket(resp->getPtr(), resp->getLen()); - return 1; - } - } - else + +#if VDRVERSNUM < 20301 +// I suppose with the new locking this just can't happen + if (tTimers->BeingEdited()) { log->log("RRProc", Log::ERR, "Unable to delete timer - timers being edited at VDR"); resp->addULONG(1); resp->finalise(); x.tcp.sendPacket(resp->getPtr(), resp->getLen()); return 1; - } + } +#endif + + if (ti->Recording()) + { + log->log("RRProc", Log::ERR, "Unable to delete timer - timer is running"); + resp->addULONG(3); + resp->finalise(); + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + return 1; + } + + tTimers->Del(ti); + tTimers->SetModified(); + + resp->addULONG(10); + resp->finalise(); + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + return 1; } int VompClientRRProc::processGetRecInfo() { // data is a pointer to the fileName string +#if VDRVERSNUM >= 20301 + LOCK_RECORDINGS_READ; + const cRecordings* tRecordings = Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings* tRecordings = &Recordings; +#endif - cRecordings Recordings; - Recordings.Load(); // probably have to do this - - cRecording *recording = Recordings.GetByName((char*)req->data); + const cRecording *recording = tRecordings->GetByName((char*)req->data); time_t timerStart = 0; time_t timerStop = 0; char* summary = NULL; char* shorttext = NULL; char* description = NULL; + char* title = NULL; bool newsummary=false; ULONG resumePoint = 0; @@ -1872,7 +2031,16 @@ int VompClientRRProc::processGetRecInfo() framespersec = Info->FramesPerSecond(); #endif resp->adddouble(framespersec); - + title = (char*)Info->Title(); + if (title) + { + resp->addString(x.charconvsys->Convert(title)); + } + else + { + resp->addString(x.charconvsys->Convert(recording->Name())); + } + // Done. send it resp->finalise(); @@ -1911,17 +2079,20 @@ int VompClientRRProc::processReScanRecording() int VompClientRRProc::processGetMarks() { // data is a pointer to the fileName string +#if VDRVERSNUM >= 20301 + LOCK_RECORDINGS_READ; + const cRecordings* tRecordings = Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings* tRecordings = &Recordings; +#endif - cMarks Marks; - cRecordings Recordings; - Recordings.Load(); // probably have to do this - - cRecording *recording = Recordings.GetByName((char*)req->data); - + const cRecording *recording = tRecordings->GetByName((char*)req->data); log->log("RRProc", Log::DEBUG, "recording pointer %p", recording); if (recording) { + cMarks Marks; #if VDRVERSNUM < 10703 Marks.Load(recording->FileName()); #else @@ -1966,7 +2137,336 @@ int VompClientRRProc::processVDRShutdown() x.tcp.sendPacket(resp->getPtr(), resp->getLen()); return 1; } + +int VompClientRRProc::processGetRecScraperEventType() +{ +#if VDRVERSNUM >= 20301 + LOCK_RECORDINGS_READ; + const cRecordings* tRecordings = Recordings; +#else + cThreadLock RecordingsLock(&Recordings); + cRecordings* tRecordings = &Recordings; +#endif + + const cRecording *recording = tRecordings->GetByName((char*)req->data); + ScraperGetEventType call; + call.type = tNone; + + if (recording && x.scrapQuery()) + { + call.recording = recording; + x.scraper->Service("GetEventType", &call); + } + resp->addUCHAR(call.type); + if (call.type == tMovie) + { + resp->addLONG(call.movieId); + } + else if (call.type == tSeries) + { + resp->addLONG(call.seriesId); + resp->addLONG(call.episodeId); + } + resp->finalise(); + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + + return 1; +} + +int VompClientRRProc::processGetEventScraperEventType() +{ + ScraperGetEventType call; + call.type = tNone; + ULONG channelid = ntohl(*(ULONG*)req->data); + ULONG eventid = ntohl(*(ULONG*)(req->data+4)); + const cEvent *event = NULL; + +#if VDRVERSNUM >= 20301 + LOCK_CHANNELS_READ; + const cChannels* tChannels = Channels; +#else + cChannels* tChannels = &Channels; +#endif + + const cChannel* channel = tChannels->GetByNumber(channelid); + +#if VDRVERSNUM < 10300 + cMutexLock MutexLock; + const cSchedules *tSchedules = cSIProcessor::Schedules(MutexLock); +#elif VDRVERSNUM < 20301 + cSchedulesLock MutexLock; + const cSchedules *tSchedules = cSchedules::Schedules(MutexLock); +#else + LOCK_SCHEDULES_READ; + const cSchedules *tSchedules = Schedules; +#endif + + if (tSchedules && channel) + { + const cSchedule *Schedule = tSchedules->GetSchedule(channel->GetChannelID()); + if (Schedule) { + event = Schedule->GetEvent(eventid); + } + } + + if (event && x.scrapQuery()) + { + call.event = event; + x.scraper->Service("GetEventType",&call); + } + resp->addUCHAR(call.type); + if (call.type == tMovie) + { + resp->addLONG(call.movieId); + } else if (call.type == tSeries){ + resp->addLONG(call.seriesId); + resp->addLONG(call.episodeId); + } + if (x.pict->epgImageExists(eventid)) { + resp->addLONG(1); + } else { + resp->addLONG(0); + } + + resp->finalise(); + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + + return 1; +} + +#define ADDSTRING_TO_PAKET(y) if ((y)!=0) resp->addString(x.charconvutf8->Convert(y)); else resp->addString(""); + +int VompClientRRProc::processGetScraperMovieInfo() +{ + + cMovie movie; + movie.movieId = ntohl(*(ULONG*)req->data); + if (!x.scrapQuery()) { + log->log("RRProc", Log::DEBUG, "No Scraper, get SeriesInfo"); + return 0; //stupid, I have no scraper why are you still asking + } + x.scraper->Service("GetMovie",&movie); + + + ADDSTRING_TO_PAKET(movie.title.c_str()); + ADDSTRING_TO_PAKET(movie.originalTitle.c_str()); + ADDSTRING_TO_PAKET(movie.tagline.c_str()); + ADDSTRING_TO_PAKET(movie.overview.c_str()); + resp->addUCHAR(movie.adult); + ADDSTRING_TO_PAKET(movie.collectionName.c_str()); + + resp->addLONG(movie.budget); + resp->addLONG(movie.revenue); + ADDSTRING_TO_PAKET(movie.genres.c_str()); + ADDSTRING_TO_PAKET(movie.homepage.c_str()); + ADDSTRING_TO_PAKET(movie.releaseDate.c_str()); + resp->addLONG(movie.runtime); + resp->adddouble(movie.popularity); + resp->adddouble(movie.voteAverage); + resp->addULONG(movie.poster.width); + resp->addULONG(movie.poster.height); + resp->addULONG(movie.fanart.width); + resp->addULONG(movie.fanart.height); + resp->addULONG(movie.collectionPoster.width); + resp->addULONG(movie.collectionPoster.height); + resp->addULONG(movie.collectionFanart.width); + resp->addULONG(movie.collectionFanart.height); + resp->addULONG(movie.actors.size()); + for (ULONG acty=0; acty < movie.actors.size(); acty++) { + ADDSTRING_TO_PAKET(movie.actors[acty].name.c_str()); + ADDSTRING_TO_PAKET(movie.actors[acty].role.c_str()); + resp->addULONG(movie.actors[acty].actorThumb.width); + resp->addULONG(movie.actors[acty].actorThumb.height); + } + resp->finalise(); -#endif // !VOMPSTANDALONE + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + + + return 1; + +} + +int VompClientRRProc::processGetScraperSeriesInfo() +{ + cSeries series; + series.seriesId = ntohl(*(ULONG*)req->data); + series.episodeId = ntohl(*(ULONG*)(req->data+4)); + if (!x.scrapQuery()) { + log->log("RRProc", Log::DEBUG, "No Scraper, get SeriesInfo"); + return 0; //stupid, I have no scraper why are you still asking + } + x.scraper->Service("GetSeries",&series); + + ADDSTRING_TO_PAKET(series.name.c_str()); + ADDSTRING_TO_PAKET(series.overview.c_str()); + ADDSTRING_TO_PAKET(series.firstAired.c_str()); + ADDSTRING_TO_PAKET(series.network.c_str()); + ADDSTRING_TO_PAKET(series.genre.c_str()); + resp->adddouble(series.rating); + ADDSTRING_TO_PAKET(series.status.c_str()); + + resp->addLONG(series.episode.number); + resp->addLONG(series.episode.season); + ADDSTRING_TO_PAKET(series.episode.name.c_str()); + ADDSTRING_TO_PAKET(series.episode.firstAired.c_str()); + ADDSTRING_TO_PAKET(series.episode.guestStars.c_str()); + ADDSTRING_TO_PAKET(series.episode.overview.c_str()); + resp->adddouble(series.episode.rating); + resp->addULONG(series.episode.episodeImage.width); + resp->addULONG(series.episode.episodeImage.height); + + ULONG num_actors = series.actors.size(); + resp->addULONG(num_actors); + for (ULONG acty=0; acty < num_actors; acty++) { + ADDSTRING_TO_PAKET(series.actors[acty].name.c_str()); + ADDSTRING_TO_PAKET(series.actors[acty].role.c_str()); + resp->addULONG(series.actors[acty].actorThumb.width); + resp->addULONG(series.actors[acty].actorThumb.height); + } + ULONG num_posters = series.posters.size(); + resp->addULONG(num_posters); + for (ULONG medias = 0; medias < num_posters; medias++ ) { + cTvMedia media=series.posters[medias]; + resp->addULONG(media.width); + resp->addULONG(media.height); + } + + ULONG num_banners = series.banners.size(); + resp->addULONG(num_banners); + for (ULONG medias = 0; medias < num_banners; medias++ ) { + cTvMedia media=series.banners[medias]; + resp->addULONG(media.width); + resp->addULONG(media.height); + } + ULONG num_fanarts = series.fanarts.size(); + resp->addULONG(num_fanarts); + for (ULONG medias = 0; medias < num_fanarts; medias++ ) { + cTvMedia media=series.fanarts[medias]; + resp->addULONG(media.width); + resp->addULONG(media.height); + } + resp->addULONG(series.seasonPoster.width); + resp->addULONG(series.seasonPoster.height); + + resp->finalise(); + + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + + return 1; +} + +int VompClientRRProc::processLoadTvMedia() +{ + TVMediaRequest tvreq; + tvreq.streamID = req->requestID; + tvreq.type = ntohl(*(ULONG*)req->data); + tvreq.primary_id = ntohl(*(ULONG*)(req->data+4)); + tvreq.secondary_id = ntohl(*(ULONG*)(req->data+8)); + tvreq.type_pict = ntohl(*(ULONG*)(req->data+12)); + tvreq.container = ntohl(*(ULONG*)(req->data+16)); + tvreq.container_member = ntohl(*(ULONG*)(req->data+20)); + log->log("RRProc", Log::DEBUG, "TVMedia request %d",req->requestID); + x.pict->addTVMediaRequest(tvreq); + + + resp->finalise(); + + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + + return 1; +} +int VompClientRRProc::processLoadTvMediaRecThumb() +{ + TVMediaRequest tvreq; + tvreq.streamID = req->requestID; + tvreq.type = 3; // unknown but primary_name is set + tvreq.primary_id = 0; + tvreq.primary_name = std::string((const char*) req->data); + tvreq.secondary_id = 0; + tvreq.type_pict = 1; + tvreq.container = 0; + tvreq.container_member = 0; + log->log("RRProc", Log::DEBUG, "TVMedia request %d %s",req->requestID,req->data); + x.pict->addTVMediaRequest(tvreq); + + + resp->finalise(); + + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + + return 1; +} + +int VompClientRRProc::processLoadTvMediaEventThumb() +{ + TVMediaRequest tvreq; + tvreq.streamID = req->requestID; + tvreq.type = 4; // unknown but primary_id is set + UINT channelid = ntohl(*(ULONG*)req->data); + tvreq.primary_id = ntohl(*(ULONG*)(req->data+4)); + tvreq.secondary_id = 0; + +#if VDRVERSNUM >= 20301 + LOCK_CHANNELS_READ; + const cChannels* tChannels = Channels; +#else + cChannels* tChannels = &Channels; +#endif + + const cChannel* channel = tChannels->GetByNumber(channelid); + + if (channel) tvreq.primary_name = std::string((const char*)channel->GetChannelID().ToString()); + tvreq.type_pict = 1; + tvreq.container = 0; + tvreq.container_member = 0; + log->log("RRProc", Log::DEBUG, "TVMedia request %d %s",req->requestID,req->data); + x.pict->addTVMediaRequest(tvreq); + + + resp->finalise(); + + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + + return 1; +} + +int VompClientRRProc::processLoadChannelLogo() +{ + TVMediaRequest tvreq; + tvreq.streamID = req->requestID; + tvreq.type = 5; // channel logo + UINT channelid = ntohl(*(ULONG*)req->data); + tvreq.primary_id = channelid; + tvreq.secondary_id = 0; + +#if VDRVERSNUM >= 20301 + LOCK_CHANNELS_READ; + const cChannels* tChannels = Channels; +#else + cChannels* tChannels = &Channels; +#endif + + const cChannel* channel = tChannels->GetByNumber(channelid); + + if (channel) tvreq.primary_name = std::string((const char*)channel->Name()); + tvreq.type_pict = 1; + tvreq.container = 0; + tvreq.container_member = 0; + if (channel) log->log("RRProc", Log::DEBUG, "TVMedia request %d %d %s",req->requestID,channelid, channel->Name()); + x.pict->addTVMediaRequest(tvreq); + + + resp->finalise(); + + x.tcp.sendPacket(resp->getPtr(), resp->getLen()); + + return 1; +} + + + + +#endif // !VOMPSTANDALONE diff --git a/vompclientrrproc.h b/vompclientrrproc.h index da6ef12..1c0fb6b 100644 --- a/vompclientrrproc.h +++ b/vompclientrrproc.h @@ -52,7 +52,8 @@ class VompClientRRProc : public Thread public: VompClientRRProc(VompClient& x); ~VompClientRRProc(); - static ULONG getProtocolVersion(); + static ULONG getProtocolVersionMin(); + static ULONG getProtocolVersionMax(); bool init(); bool recvRequest(RequestPacket*); @@ -82,6 +83,15 @@ class VompClientRRProc : public Thread int processDeleteTimer(); int processReScanRecording(); // FIXME obselete int processVDRShutdown(); + int processGetRecScraperEventType(); + int processGetScraperMovieInfo(); + int processGetScraperSeriesInfo(); + int processLoadTvMedia(); + int processLoadTvMediaRecThumb(); + int processGetEventScraperEventType(); + int processLoadTvMediaEventThumb(); + int processLoadChannelLogo(); + #endif int processLogin(); int processConfigSave(); @@ -101,7 +111,8 @@ class VompClientRRProc : public Thread RequestPacket* req; RequestPacketQueue req_queue; ResponsePacket* resp; - static ULONG VOMP_PROTOCOL_VERSION; + static ULONG VOMP_PROTOCOL_VERSION_MIN; + static ULONG VOMP_PROTOCOL_VERSION_MAX; Log* log; }; diff --git a/vompserver.c b/vompserver.c index b59a037..6bc6e54 100644 --- a/vompserver.c +++ b/vompserver.c @@ -27,7 +27,7 @@ #include "mvpserver.h" //#include "vompclient.h" -static const char *VERSION = "0.4.1"; +static const char *VERSION = "0.5.0"; static const char *DESCRIPTION = "Vompserver plugin by Chris Tallon"; static const char *MAINMENUENTRY = "Vompserver"; @@ -74,6 +74,7 @@ cPluginVompserver::~cPluginVompserver() // Clean up after yourself! mvpserver.stop(); if (configDir) delete[] configDir; + } const char *cPluginVompserver::CommandLineHelp(void) @@ -91,15 +92,15 @@ bool cPluginVompserver::ProcessArgs(int argc, char *argv[]) { if (c == 'c') { - const char* vdrdeveldevelret = cPlugin::ConfigDirectory(optarg); - if (!vdrdeveldevelret) + const char* vdrret = cPlugin::ConfigDirectory(optarg); + if (!vdrret) { dsyslog("VOMP: Could not get config dir from VDR"); return false; } - configDir = new char[strlen(vdrdeveldevelret)+1]; - strcpy(configDir, vdrdeveldevelret); + configDir = new char[strlen(vdrret)+1]; + strcpy(configDir, vdrret); } else { @@ -122,14 +123,14 @@ bool cPluginVompserver::Start(void) if (!configDir) { - const char* vdrdeveldevelret = cPlugin::ConfigDirectory("vompserver"); - if (!vdrdeveldevelret) + const char* vdrret = cPlugin::ConfigDirectory("vompserver"); + if (!vdrret) { dsyslog("VOMP: Could not get config dir from VDR"); return false; } - configDir = new char[strlen(vdrdeveldevelret)+1]; - strcpy(configDir, vdrdeveldevelret); + configDir = new char[strlen(vdrret)+1]; + strcpy(configDir, vdrret); } int success = mvpserver.run(configDir); -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-vompserver.git _______________________________________________ pkg-vdr-dvb-changes mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-vdr-dvb-changes
