Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

vdr-plugin-vnsiserver: add channel filter

  • Loading branch information...
commit 608495ea8a9c75d72bebf1f2b04fa36d168e9c32 1 parent 73ea039
@FernetMenta FernetMenta authored
View
2  addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/Makefile
@@ -90,7 +90,7 @@ OBJS = vnsi.o bitstream.o vnsiclient.o config.o cxsocket.o parser.o parser_AAC.o
parser_AC3.o parser_DTS.o parser_h264.o parser_MPEGAudio.o parser_MPEGVideo.o \
parser_Subtitle.o parser_Teletext.o streamer.o recplayer.o requestpacket.o responsepacket.o \
vnsiserver.o hash.o recordingscache.o setup.o vnsiosd.o demuxer.o videobuffer.o \
- videoinput.o
+ videoinput.o channelfilter.o
### The main target:
View
332 addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/channelfilter.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "channelfilter.h"
+#include "config.h"
+#include "hash.h"
+#include <string>
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+#include <vdr/tools.h>
+
+cVNSIProvider::cVNSIProvider()
+ :m_name(""), m_caid(0)
+{
+
+}
+
+cVNSIProvider::cVNSIProvider(std::string name, int caid)
+ :m_name(name), m_caid(caid)
+{
+};
+
+bool cVNSIProvider::operator==(const cVNSIProvider &rhs)
+{
+ if (rhs.m_caid != m_caid)
+ return false;
+ if (rhs.m_name.compare(m_name) != 0)
+ return false;
+ return true;
+}
+
+
+bool cVNSIChannelFilter::IsRadio(const cChannel* channel)
+{
+ bool isRadio = false;
+
+ // assume channels without VPID & APID are video channels
+ if (channel->Vpid() == 0 && channel->Apid(0) == 0)
+ isRadio = false;
+ // channels without VPID are radio channels (channels with VPID 1 are encrypted radio channels)
+ else if (channel->Vpid() == 0 || channel->Vpid() == 1)
+ isRadio = true;
+
+ return isRadio;
+}
+
+void cVNSIChannelFilter::Load()
+{
+ cMutexLock lock(&m_Mutex);
+
+ cString filename;
+ std::string line;
+ std::ifstream rfile;
+ cVNSIProvider provider;
+ std::vector<cVNSIProvider>::iterator p_it;
+
+ filename = cString::sprintf("%s/videowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory);
+ m_providersVideo.clear();
+ rfile.open(filename);
+ if (rfile.is_open())
+ {
+ while(std::getline(rfile,line))
+ {
+ size_t pos = line.find("|");
+ if(pos == line.npos)
+ {
+ provider.m_name = line;
+ provider.m_caid = 0;
+ }
+ else
+ {
+ provider.m_name = line.substr(0, pos);
+ std::string tmp = line.substr(pos+1);
+ char *pend;
+ provider.m_caid = strtol(tmp.c_str(), &pend, 10);
+ }
+ p_it = std::find(m_providersVideo.begin(), m_providersVideo.end(), provider);
+ if(p_it == m_providersVideo.end())
+ {
+ m_providersVideo.push_back(provider);
+ }
+ }
+ rfile.close();
+ }
+
+ filename = cString::sprintf("%s/radiowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory);
+ rfile.open(filename);
+ m_providersRadio.clear();
+ if (rfile.is_open())
+ {
+ while(std::getline(rfile,line))
+ {
+ unsigned int pos = line.find("|");
+ if(pos == line.npos)
+ {
+ provider.m_name = line;
+ provider.m_caid = 0;
+ }
+ else
+ {
+ provider.m_name = line.substr(0, pos);
+ std::string tmp = line.substr(pos+1);
+ char *pend;
+ provider.m_caid = strtol(tmp.c_str(), &pend, 10);
+ }
+ p_it = std::find(m_providersRadio.begin(), m_providersRadio.end(), provider);
+ if(p_it == m_providersRadio.end())
+ {
+ m_providersRadio.push_back(provider);
+ }
+ }
+ rfile.close();
+ }
+
+ filename = cString::sprintf("%s/videoblacklist.vnsi", *VNSIServerConfig.ConfigDirectory);
+ rfile.open(filename);
+ m_channelsVideo.clear();
+ if (rfile.is_open())
+ {
+ while(getline(rfile,line))
+ {
+ char *pend;
+ int id = strtol(line.c_str(), &pend, 10);
+ m_channelsVideo.push_back(id);
+ }
+ rfile.close();
+ }
+
+ filename = cString::sprintf("%s/radioblacklist.vnsi", *VNSIServerConfig.ConfigDirectory);
+ rfile.open(filename);
+ m_channelsRadio.clear();
+ if (rfile.is_open())
+ {
+ while(getline(rfile,line))
+ {
+ char *pend;
+ int id = strtol(line.c_str(), &pend, 10);
+ m_channelsRadio.push_back(id);
+ }
+ rfile.close();
+ }
+}
+
+void cVNSIChannelFilter::StoreWhitelist(bool radio)
+{
+ cMutexLock lock(&m_Mutex);
+
+ cString filename;
+ std::ofstream wfile;
+ cVNSIProvider provider;
+ std::vector<cVNSIProvider>::iterator p_it;
+ std::vector<cVNSIProvider> *whitelist;
+
+ if (radio)
+ {
+ filename = cString::sprintf("%s/radiowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory);
+ whitelist = &m_providersRadio;
+ }
+ else
+ {
+ filename = cString::sprintf("%s/videowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory);
+ whitelist = &m_providersVideo;
+ }
+
+ wfile.open(filename);
+ if(wfile.is_open())
+ {
+ std::string tmp;
+ char buf[16];
+ for(p_it=whitelist->begin(); p_it!=whitelist->end(); ++p_it)
+ {
+ tmp = p_it->m_name;
+ tmp += "|";
+ sprintf(buf, "%d\n", p_it->m_caid);
+ tmp += buf;
+ wfile << tmp;
+ }
+ wfile.close();
+ }
+
+ SortChannels();
+}
+
+void cVNSIChannelFilter::StoreBlacklist(bool radio)
+{
+ cMutexLock lock(&m_Mutex);
+
+ cString filename;
+ std::ofstream wfile;
+ cVNSIProvider provider;
+ std::vector<int>::iterator it;
+ std::vector<int> *blacklist;
+
+ if (radio)
+ {
+ filename = cString::sprintf("%s/radioblacklist.vnsi", *VNSIServerConfig.ConfigDirectory);
+ blacklist = &m_channelsRadio;
+ }
+ else
+ {
+ filename = cString::sprintf("%s/videoblacklist.vnsi", *VNSIServerConfig.ConfigDirectory);
+ blacklist = &m_channelsVideo;
+ }
+
+ wfile.open(filename);
+ if(wfile.is_open())
+ {
+ std::string tmp;
+ char buf[16];
+ for(it=blacklist->begin(); it!=blacklist->end(); ++it)
+ {
+ sprintf(buf, "%d\n", *it);
+ tmp = buf;
+ wfile << tmp;
+ }
+ wfile.close();
+ }
+
+ SortChannels();
+}
+
+bool cVNSIChannelFilter::IsWhitelist(const cChannel &channel)
+{
+ cVNSIProvider provider;
+ std::vector<cVNSIProvider>::iterator p_it;
+ std::vector<cVNSIProvider> *providers;
+ provider.m_name = channel.Provider();
+
+ if (IsRadio(&channel))
+ providers = &m_providersRadio;
+ else
+ providers = &m_providersVideo;
+
+ if(providers->empty())
+ return true;
+
+ if (channel.Ca(0) == 0)
+ {
+ provider.m_caid = 0;
+ p_it = std::find(providers->begin(), providers->end(), provider);
+ if(p_it!=providers->end())
+ return true;
+ else
+ return false;
+ }
+
+ int caid;
+ int idx = 0;
+ while((caid = channel.Ca(idx)) != 0)
+ {
+ provider.m_caid = caid;
+ p_it = std::find(providers->begin(), providers->end(), provider);
+ if(p_it!=providers->end())
+ return true;
+
+ idx++;
+ }
+ return false;
+}
+
+bool cVNSIChannelFilter::PassFilter(const cChannel &channel)
+{
+ cMutexLock lock(&m_Mutex);
+
+ if(channel.GroupSep())
+ return true;
+
+ if (!IsWhitelist(channel))
+ return false;
+
+ std::vector<int>::iterator it;
+ if (IsRadio(&channel))
+ {
+ it = std::find(m_channelsRadio.begin(), m_channelsRadio.end(), CreateChannelUID(&channel));
+ if(it!=m_channelsRadio.end())
+ return false;
+ }
+ else
+ {
+ it = std::find(m_channelsVideo.begin(), m_channelsVideo.end(), CreateChannelUID(&channel));
+ if(it!=m_channelsVideo.end())
+ return false;
+ }
+
+ return true;
+}
+
+void cVNSIChannelFilter::SortChannels()
+{
+ Channels.IncBeingEdited();
+ Channels.Lock(true);
+
+ for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
+ {
+ if(!PassFilter(*channel))
+ {
+ for (cChannel *whitechan = Channels.Next(channel); whitechan; whitechan = Channels.Next(whitechan))
+ {
+ if(PassFilter(*whitechan))
+ {
+ Channels.Move(whitechan, channel);
+ channel = whitechan;
+ break;
+ }
+ }
+ }
+ }
+
+ Channels.SetModified(true);
+ Channels.Unlock();
+ Channels.DecBeingEdited();
+}
+
+cVNSIChannelFilter VNSIChannelFilter;
View
55 addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/channelfilter.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <vdr/thread.h>
+#include <vdr/channels.h>
+
+class cVNSIProvider
+{
+public:
+ cVNSIProvider();
+ cVNSIProvider(std::string name, int caid);
+ bool operator==(const cVNSIProvider &rhs);
+ std::string m_name;
+ int m_caid;
+};
+
+class cVNSIChannelFilter
+{
+public:
+ void Load();
+ void StoreWhitelist(bool radio);
+ void StoreBlacklist(bool radio);
+ bool IsWhitelist(const cChannel &channel);
+ bool PassFilter(const cChannel &channel);
+ void SortChannels();
+ static bool IsRadio(const cChannel* channel);
+ std::vector<cVNSIProvider> m_providersVideo;
+ std::vector<cVNSIProvider> m_providersRadio;
+ std::vector<int> m_channelsVideo;
+ std::vector<int> m_channelsRadio;
+ cMutex m_Mutex;
+};
+
+extern cVNSIChannelFilter VNSIChannelFilter;
View
218 addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.c
@@ -47,24 +47,11 @@
#include "requestpacket.h"
#include "responsepacket.h"
#include "hash.h"
+#include "channelfilter.h"
#include "wirbelscanservice.h" /// copied from modified wirbelscan plugin
/// must be hold up to date with wirbelscan
-static bool IsRadio(const cChannel* channel)
-{
- bool isRadio = false;
-
- // assume channels without VPID & APID are video channels
- if (channel->Vpid() == 0 && channel->Apid(0) == 0)
- isRadio = false;
- // channels without VPID are radio channels (channels with VPID 1 are encrypted radio channels)
- else if (channel->Vpid() == 0 || channel->Vpid() == 1)
- isRadio = true;
-
- return isRadio;
-}
-
cMutex cVNSIClient::m_timerLock;
cVNSIClient::cVNSIClient(int fd, unsigned int id, const char *ClientAdr)
@@ -275,6 +262,18 @@ void cVNSIClient::EpgChange()
if (!lastEvent)
continue;
+ Channels.Lock(false);
+ const cChannel *channel = Channels.GetByChannelID(schedule->ChannelID());
+ Channels.Unlock();
+
+ if (!channel)
+ continue;
+
+ if (!VNSIChannelFilter.PassFilter(*channel))
+ continue;
+
+ INFOLOG("Trigger EPG update for channel %s", channel->Name());
+
uint32_t channelId = CreateStringHash(schedule->ChannelID().ToString());
it = m_epgUpdate.find(channelId);
if (it == m_epgUpdate.end())
@@ -295,10 +294,6 @@ void cVNSIClient::EpgChange()
resp->finalise();
m_socket.write(resp->getPtr(), resp->getLen());
delete resp;
-
- const cChannel *channel = FindChannelByUID(channelId);
- if (channel)
- INFOLOG("Trigger EPG update for channel %s", channel->Name());
}
}
@@ -480,6 +475,26 @@ bool cVNSIClient::processRequest(cRequestPacket* req)
result = processCHANNELS_GetGroupMembers();
break;
+ case VNSI_CHANNELS_GETCAIDS:
+ result = processCHANNELS_GetCaids();
+ break;
+
+ case VNSI_CHANNELS_GETWHITELIST:
+ result = processCHANNELS_GetWhitelist();
+ break;
+
+ case VNSI_CHANNELS_GETBLACKLIST:
+ result = processCHANNELS_GetBlacklist();
+ break;
+
+ case VNSI_CHANNELS_SETWHITELIST:
+ result = processCHANNELS_SetWhitelist();
+ break;
+
+ case VNSI_CHANNELS_SETBLACKLIST:
+ result = processCHANNELS_SetBlacklist();
+ break;
+
/** OPCODE 80 - 99: VNSI network functions for timer access */
case VNSI_TIMER_GETCOUNT:
result = processTIMER_GetCount();
@@ -940,31 +955,42 @@ bool cVNSIClient::processCHANNELS_ChannelsCount() /* OPCODE 61 */
bool cVNSIClient::processCHANNELS_GetChannels() /* OPCODE 63 */
{
- if (m_req->getDataLength() != 4) return false;
+ if (m_req->getDataLength() != 5) return false;
bool radio = m_req->extract_U32();
+ bool filter = m_req->extract_U8();
Channels.Lock(false);
+ cString caids;
+ int caid;
+ int caid_idx;
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
{
- if (radio != IsRadio(channel))
+ if (radio != cVNSIChannelFilter::IsRadio(channel))
continue;
// skip invalid channels
if (channel->Sid() == 0)
continue;
+ // check filter
+ if (filter && !VNSIChannelFilter.PassFilter(*channel))
+ continue;
+
m_resp->add_U32(channel->Number());
m_resp->add_String(m_toUTF8.Convert(channel->Name()));
+ m_resp->add_String(m_toUTF8.Convert(channel->Provider()));
m_resp->add_U32(CreateChannelUID(channel));
- m_resp->add_U32(0); // groupindex unused
- m_resp->add_U32(channel->Ca());
-#if APIVERSNUM >= 10701
- m_resp->add_U32(channel->Vtype());
-#else
- m_resp->add_U32(2);
-#endif
+ m_resp->add_U32(channel->Ca(0));
+ caid_idx = 0;
+ caids = "caids:";
+ while((caid = channel->Ca(caid_idx)) != 0)
+ {
+ caids = cString::sprintf("%s%d;", (const char*)caids, caid);
+ caid_idx++;
+ }
+ m_resp->add_String((const char*)caids);
}
Channels.Unlock();
@@ -1027,6 +1053,7 @@ bool cVNSIClient::processCHANNELS_GetGroupMembers()
{
char* groupname = m_req->extract_String();
uint32_t radio = m_req->extract_U8();
+ bool filter = m_req->extract_U8();
int index = 0;
// unknown group
@@ -1060,7 +1087,11 @@ bool cVNSIClient::processCHANNELS_GetGroupMembers()
if(name.empty())
continue;
- if(IsRadio(channel) != radio)
+ if(cVNSIChannelFilter::IsRadio(channel) != radio)
+ continue;
+
+ // check filter
+ if (filter && !VNSIChannelFilter.PassFilter(*channel))
continue;
if(name == groupname)
@@ -1078,13 +1109,142 @@ bool cVNSIClient::processCHANNELS_GetGroupMembers()
return true;
}
+bool cVNSIClient::processCHANNELS_GetCaids()
+{
+ uint32_t uid = m_req->extract_U32();
+
+ Channels.Lock(false);
+ const cChannel *channel = NULL;
+ channel = FindChannelByUID(uid);
+ Channels.Unlock();
+
+ if (channel != NULL)
+ {
+ int caid;
+ int idx = 0;
+ while((caid = channel->Ca(idx)) != 0)
+ {
+ m_resp->add_U32(caid);
+ idx++;
+ }
+ }
+
+ m_resp->finalise();
+ m_socket.write(m_resp->getPtr(), m_resp->getLen());
+
+ return true;
+}
+
+bool cVNSIClient::processCHANNELS_GetWhitelist()
+{
+ bool radio = m_req->extract_U8();
+ std::vector<cVNSIProvider> *providers;
+
+ if(radio)
+ providers = &VNSIChannelFilter.m_providersRadio;
+ else
+ providers = &VNSIChannelFilter.m_providersVideo;
+
+ VNSIChannelFilter.m_Mutex.Lock();
+ for(unsigned int i=0; i<providers->size(); i++)
+ {
+ m_resp->add_String((*providers)[i].m_name.c_str());
+ m_resp->add_U32((*providers)[i].m_caid);
+ }
+ VNSIChannelFilter.m_Mutex.Unlock();
+
+ m_resp->finalise();
+ m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ return true;
+}
+
+bool cVNSIClient::processCHANNELS_GetBlacklist()
+{
+ bool radio = m_req->extract_U8();
+ std::vector<int> *channels;
+
+ if(radio)
+ channels = &VNSIChannelFilter.m_channelsRadio;
+ else
+ channels = &VNSIChannelFilter.m_channelsVideo;
+
+ VNSIChannelFilter.m_Mutex.Lock();
+ for(unsigned int i=0; i<channels->size(); i++)
+ {
+ m_resp->add_U32((*channels)[i]);
+ }
+ VNSIChannelFilter.m_Mutex.Unlock();
+
+ m_resp->finalise();
+ m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ return true;
+}
+
+bool cVNSIClient::processCHANNELS_SetWhitelist()
+{
+ bool radio = m_req->extract_U8();
+ cVNSIProvider provider;
+ std::vector<cVNSIProvider> *providers;
+
+ if(radio)
+ providers = &VNSIChannelFilter.m_providersRadio;
+ else
+ providers = &VNSIChannelFilter.m_providersVideo;
+
+ VNSIChannelFilter.m_Mutex.Lock();
+ providers->clear();
+
+ while(!m_req->end())
+ {
+ char *str = m_req->extract_String();
+ provider.m_name = str;
+ provider.m_caid = m_req->extract_U32();
+ delete [] str;
+ providers->push_back(provider);
+ }
+ VNSIChannelFilter.StoreWhitelist(radio);
+ VNSIChannelFilter.m_Mutex.Unlock();
+
+ m_resp->finalise();
+ m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ return true;
+}
+
+bool cVNSIClient::processCHANNELS_SetBlacklist()
+{
+ bool radio = m_req->extract_U8();
+ cVNSIProvider provider;
+ std::vector<int> *channels;
+
+ if(radio)
+ channels = &VNSIChannelFilter.m_channelsRadio;
+ else
+ channels = &VNSIChannelFilter.m_channelsVideo;
+
+ VNSIChannelFilter.m_Mutex.Lock();
+ channels->clear();
+
+ int id;
+ while(!m_req->end())
+ {
+ id = m_req->extract_U32();
+ channels->push_back(id);
+ }
+ VNSIChannelFilter.StoreBlacklist(radio);
+ VNSIChannelFilter.m_Mutex.Unlock();
+
+ m_resp->finalise();
+ m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ return true;
+}
+
void cVNSIClient::CreateChannelGroups(bool automatic)
{
std::string groupname;
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
{
- bool isRadio = IsRadio(channel);
+ bool isRadio = cVNSIChannelFilter::IsRadio(channel);
if(automatic && !channel->GroupSep())
groupname = channel->Provider();
View
5 addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiclient.h
@@ -130,6 +130,11 @@ class cVNSIClient : public cThread
bool processCHANNELS_GroupList();
bool processCHANNELS_GetChannels();
bool processCHANNELS_GetGroupMembers();
+ bool processCHANNELS_GetCaids();
+ bool processCHANNELS_GetWhitelist();
+ bool processCHANNELS_GetBlacklist();
+ bool processCHANNELS_SetWhitelist();
+ bool processCHANNELS_SetBlacklist();
void CreateChannelGroups(bool automatic);
View
5 addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsicommand.h
@@ -73,6 +73,11 @@
#define VNSI_CHANNELGROUP_GETCOUNT 65
#define VNSI_CHANNELGROUP_LIST 66
#define VNSI_CHANNELGROUP_MEMBERS 67
+#define VNSI_CHANNELS_GETCAIDS 68
+#define VNSI_CHANNELS_GETWHITELIST 69
+#define VNSI_CHANNELS_GETBLACKLIST 70
+#define VNSI_CHANNELS_SETWHITELIST 71
+#define VNSI_CHANNELS_SETBLACKLIST 72
/* OPCODE 80 - 99: VNSI network functions for timer access */
#define VNSI_TIMER_GETCOUNT 80
View
4 addons/pvr.vdr.vnsi/vdr-plugin-vnsiserver/vnsiserver.c
@@ -45,6 +45,7 @@
#include "vnsi.h"
#include "vnsiserver.h"
#include "vnsiclient.h"
+#include "channelfilter.h"
unsigned int cVNSIServer::m_IdCnt = 0;
@@ -84,6 +85,9 @@ cVNSIServer::cVNSIServer(int listenPort) : cThread("VDR VNSI Server")
m_AllowedHostsFile = cString::sprintf("/video/" ALLOWED_HOSTS_FILE);
}
+ VNSIChannelFilter.Load();
+ VNSIChannelFilter.SortChannels();
+
m_ServerFD = socket(AF_INET, SOCK_STREAM, 0);
if(m_ServerFD == -1)
return;
Please sign in to comment.
Something went wrong with that request. Please try again.