[vdr-plugin-vompserver] 01/05: New upstream version 0.5.0
Tobias Grimm
tiber-guest at moszumanska.debian.org
Sat Feb 17 14:52:50 UTC 2018
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 <git at e-tobi.net>
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
More information about the pkg-vdr-dvb-changes
mailing list