Files
recycled-ni-neutrino/src/zapit/src/bouquets.cpp
TangoCash b38647eff4 fix m3u parse
Origin commit data
------------------
Branch: ni/coolstream
Commit: b5a726ea94
Author: TangoCash <eric@loxat.de>
Date: 2023-11-30 (Thu, 30 Nov 2023)


------------------
No further description and justification available within origin commit message!

------------------
This commit was generated by Migit
2023-12-03 21:29:00 +01:00

1561 lines
45 KiB
C++

/*
* $Id: bouquets.cpp,v 1.101 2004/08/02 08:09:44 thegoodguy Exp $
*
* BouquetManager for zapit - d-box2 linux project
*
* (C) 2002 by Simplex <simplex@berlios.de>,
* rasc <rasc@berlios.de>,
* thegoodguy <thegoodguy@berlios.de>
*
* (C) 2009, 2011-2013 Stefan Seyfried
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <map>
#include <set>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <dirent.h>
#include <fstream>
#include <iostream>
#include <global.h>
#include <neutrino.h>
#include <driver/pictureviewer/pictureviewer.h>
#include <system/helpers.h>
#include <system/set_threadname.h>
#include <zapit/bouquets.h>
#include <zapit/debug.h>
#include <zapit/getservices.h>
#include <zapit/settings.h>
#include <zapit/zapit.h>
#include <xmlinterface.h>
#define M3U_START_MARKER "#EXTM3U"
#define M3U_INFO_MARKER "#EXTINF"
#define TVG_URL_MARKER "tvg-url="
#define X_TVG_URL_MARKER "x-tvg-url="
#define TVG_ID_MARKER "tvg-id="
#define TVG_NAME_MARKER "tvg-name="
#define TVG_LOGO_MARKER "tvg-logo="
#define TVG_SCRIPT_MARKER "tvg-script="
#define TVG_SHIFT_MARKER "tvg-shift="
#define GROUP_PREFIX_MARKER "group-prefix="
#define GROUP_NAME_MARKER "group-title="
extern CBouquetManager *g_bouquetManager;
extern CPictureViewer *g_PicViewer;
#define GET_ATTR(node, name, fmt, arg) \
do { \
const char * ptr = xmlGetAttribute(node, name); \
if ((ptr == NULL) || (sscanf(ptr, fmt, &arg) <= 0)) \
arg = 0; \
} \
while (0)
/**** class CBouquet ********************************************************/
// -- servicetype 0 queries TV and Radio Channels
CZapitChannel* CZapitBouquet::getChannelByChannelID(const t_channel_id channel_id, const unsigned char serviceType)
{
CZapitChannel* result = NULL;
ZapitChannelList* channels = &tvChannels;
switch (serviceType) {
case ST_RESERVED: // ?
case ST_DIGITAL_TELEVISION_SERVICE:
case ST_NVOD_REFERENCE_SERVICE:
case ST_NVOD_TIME_SHIFTED_SERVICE:
channels = &tvChannels;
break;
case ST_DIGITAL_RADIO_SOUND_SERVICE:
channels = &radioChannels;
break;
}
unsigned int i;
for (i = 0; (i < channels->size()) && ((*channels)[i]->getChannelID() != channel_id); i++)
{};
if (i<channels->size())
result = (*channels)[i];
if ((serviceType == ST_RESERVED) && (result == NULL)) {
result = getChannelByChannelID(channel_id, ST_DIGITAL_RADIO_SOUND_SERVICE);
}
return result;
}
void CZapitBouquet::sortBouquet(void)
{
sort(tvChannels.begin(), tvChannels.end(), CmpChannelByChName());
sort(radioChannels.begin(), radioChannels.end(), CmpChannelByChName());
}
void CZapitBouquet::sortBouquetByNumber(void)
{
sort(tvChannels.begin(), tvChannels.end(), CmpChannelByChNum());
sort(radioChannels.begin(), radioChannels.end(), CmpChannelByChNum());
}
void CZapitBouquet::addService(CZapitChannel* newChannel)
{
switch (newChannel->getServiceType())
{
case ST_DIGITAL_TELEVISION_SERVICE:
case ST_NVOD_REFERENCE_SERVICE:
case ST_NVOD_TIME_SHIFTED_SERVICE:
tvChannels.push_back(newChannel);
break;
case ST_DIGITAL_RADIO_SOUND_SERVICE:
radioChannels.push_back(newChannel);
break;
}
if (bLocked)
newChannel->bLockCount++;
}
void CZapitBouquet::removeService(CZapitChannel* oldChannel)
{
if (oldChannel != NULL) {
ZapitChannelList* channels = &tvChannels;
switch (oldChannel->getServiceType()) {
case ST_DIGITAL_TELEVISION_SERVICE:
case ST_NVOD_REFERENCE_SERVICE:
case ST_NVOD_TIME_SHIFTED_SERVICE:
channels = &tvChannels;
break;
case ST_DIGITAL_RADIO_SOUND_SERVICE:
channels = &radioChannels;
break;
}
if (bLocked)
oldChannel->bLockCount--;
(*channels).erase(remove(channels->begin(), channels->end(), oldChannel), channels->end());
}
}
void CZapitBouquet::moveService(const unsigned int oldPosition, const unsigned int newPosition, const unsigned char serviceType)
{
ZapitChannelList* channels = &tvChannels;
switch (serviceType) {
case ST_DIGITAL_TELEVISION_SERVICE:
case ST_NVOD_REFERENCE_SERVICE:
case ST_NVOD_TIME_SHIFTED_SERVICE:
channels = &tvChannels;
break;
case ST_DIGITAL_RADIO_SOUND_SERVICE:
channels = &radioChannels;
break;
}
if ((oldPosition < channels->size()) && (newPosition < channels->size())) {
ZapitChannelList::iterator it = channels->begin();
advance(it, oldPosition);
CZapitChannel* tmp = *it;
channels->erase(it);
it = channels->begin();
advance(it, newPosition);
channels->insert(it, tmp);
}
}
bool CZapitBouquet::getTvChannels(ZapitChannelList &list, int flags)
{
list.clear();
for (ZapitChannelList::iterator it = tvChannels.begin(); it != tvChannels.end(); ++it) {
if ((*it)->flags & flags)
list.push_back(*it);
}
return (!list.empty());
}
bool CZapitBouquet::getRadioChannels(ZapitChannelList &list, int flags)
{
list.clear();
for (ZapitChannelList::iterator it = radioChannels.begin(); it != radioChannels.end(); ++it) {
if ((*it)->flags & flags)
list.push_back(*it);
}
return (!list.empty());
}
bool CZapitBouquet::getChannels(ZapitChannelList &list, bool tv, int flags)
{
list.clear();
ZapitChannelList *current = tv ? &tvChannels : &radioChannels;
for (ZapitChannelList::iterator it = current->begin(); it != current->end(); ++it) {
if ((*it)->flags & flags)
list.push_back(*it);
}
return (!list.empty());
}
#if 0
size_t CZapitBouquet::recModeRadioSize(const transponder_id_t transponder_id)
{
size_t size = 0;
for (size_t i = 0; i < radioChannels.size(); i++)
if (transponder_id == radioChannels[i]->getTransponderId())
size++;
return size;
}
size_t CZapitBouquet::recModeTVSize(const transponder_id_t transponder_id)
{
size_t size = 0;
for (size_t i = 0; i < tvChannels.size(); i++)
if (transponder_id == tvChannels[i]->getTransponderId())
size++;
return size;
}
#endif
CBouquetManager::~CBouquetManager()
{
clearAll();
}
void CBouquetManager::writeBouquetHeader(FILE * bouq_fd, uint32_t i, const char * bouquetName)
{
//printf("[bouquets] writing bouquet header: %s\n", bouquetName);
fprintf(bouq_fd, "\t<Bouquet name=\"%s\"", bouquetName);
if (Bouquets[i]->BqID!=DEFAULT_BQ_ID) fprintf(bouq_fd, " bqID=\"%04x\"", Bouquets[i]->BqID); // optional_attribute > default=0
if (Bouquets[i]->bHidden!=DEFAULT_BQ_HIDDEN) fprintf(bouq_fd, " hidden=\"%d\"", Bouquets[i]->bHidden ? 1 : 0);
if (Bouquets[i]->bLocked!=DEFAULT_BQ_LOCKED) fprintf(bouq_fd, " locked=\"%d\"", Bouquets[i]->bLocked ? 1 : 0);
if (Bouquets[i]->bScanEpg!=DEFAULT_BQ_SCANEPG) fprintf(bouq_fd, " epg=\"%d\"", Bouquets[i]->bScanEpg ? 1 : 0);
if (Bouquets[i]->bUseCI) fprintf(bouq_fd, " ci=\"1\"");
fprintf(bouq_fd, ">\n");
}
void CBouquetManager::writeBouquetFooter(FILE * bouq_fd)
{
fprintf(bouq_fd, "\t</Bouquet>\n");
}
void CBouquetManager::writeChannels(FILE * bouq_fd, ZapitChannelList &list, bool bUser)
{
for(zapit_list_it_t it = list.begin(); it != list.end(); it++)
(*it)->dumpBouquetXml(bouq_fd, bUser);
}
void CBouquetManager::writeBouquetChannels(FILE * bouq_fd, uint32_t i, bool bUser)
{
writeChannels(bouq_fd, Bouquets[i]->tvChannels, bUser);
writeChannels(bouq_fd, Bouquets[i]->radioChannels, bUser);
}
void CBouquetManager::writeBouquet(FILE * bouq_fd, uint32_t i, bool /* bUser */)
{
writeBouquetHeader(bouq_fd, i, convert_UTF8_To_UTF8_XML(Bouquets[i]->Name.c_str()).c_str());
writeBouquetChannels(bouq_fd, i, Bouquets[i]->bUser);
writeBouquetFooter(bouq_fd);
}
/**** class CBouquetManager *************************************************/
void CBouquetManager::saveBouquets(void)
{
FILE * bouq_fd;
printf("CBouquetManager::saveBouquets: %s\n", BOUQUETS_XML);
bouq_fd = fopen(BOUQUETS_XML, "w");
if (!bouq_fd) {
perror(BOUQUETS_XML);
return;
}
fprintf(bouq_fd, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<zapit api=\"4\">\n");
for (unsigned int i = 0; i < Bouquets.size(); i++) {
if (Bouquets[i] != remainChannels) {
DBG("save Bouquets: name %s user: %d\n", Bouquets[i]->Name.c_str(), Bouquets[i]->bUser);
if(!Bouquets[i]->bUser && !Bouquets[i]->bWebtv && !Bouquets[i]->bWebradio) {
writeBouquet(bouq_fd, i,false);
}
}
}
fprintf(bouq_fd, "</zapit>\n");
fdatasync(fileno(bouq_fd));
fclose(bouq_fd);
chmod(BOUQUETS_XML, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
}
void CBouquetManager::saveUBouquets(void)
{
FILE * ubouq_fd;
printf("CBouquetManager::saveUBouquets: %s\n", UBOUQUETS_XML);
ubouq_fd = fopen(UBOUQUETS_XML, "w");
if (!ubouq_fd) {
perror(BOUQUETS_XML);
return;
}
fprintf(ubouq_fd, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<zapit api=\"4\">\n");
for (unsigned int i = 0; i < Bouquets.size(); i++) {
if (Bouquets[i] != remainChannels) {
if(Bouquets[i]->bUser) {
writeBouquet(ubouq_fd, i, true);
}
}
}
fprintf(ubouq_fd, "</zapit>\n");
fdatasync(fileno(ubouq_fd));
fclose(ubouq_fd);
chmod(UBOUQUETS_XML, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
}
void CBouquetManager::saveBouquets(const CZapitClient::bouquetMode bouquetMode, const char * const providerName, t_satellite_position satellitePosition)
{
if (bouquetMode == CZapitClient::BM_DELETEBOUQUETS) {
INFO("removing existing bouquets");
if (satellitePosition != INVALID_SAT_POSITION) {
if (CFEManager::getInstance()->cableOnly())
g_bouquetManager->clearAll(false);
else
g_bouquetManager->deletePosition(satellitePosition);
}
}
if (bouquetMode == CZapitClient::BM_DONTTOUCHBOUQUETS)
return;
if (bouquetMode == CZapitClient::BM_CREATESATELLITEBOUQUET) {
while (Bouquets.size() > 1) {
BouquetList::iterator it = Bouquets.begin() + 1;
Bouquets[0]->tvChannels.insert(Bouquets[0]->tvChannels.end(), (*it)->tvChannels.begin(), (*it)->tvChannels.end());
Bouquets[0]->radioChannels.insert(Bouquets[0]->radioChannels.end(), (*it)->radioChannels.begin(), (*it)->radioChannels.end());
delete (*it);
Bouquets.erase(it);
}
if( !Bouquets.empty() )
Bouquets[0]->Name = providerName;
}
if ((bouquetMode == CZapitClient::BM_UPDATEBOUQUETS) || (bouquetMode == CZapitClient::BM_DELETEBOUQUETS)) {
while (!(Bouquets.empty())) {
CZapitBouquet* bouquet;
int dest = g_bouquetManager->existsBouquet(Bouquets[0]->Name.c_str(), true);
DBG("save Bouquets: dest %d for name %s\n", dest, Bouquets[0]->Name.c_str());
if(dest == -1) {
bouquet = g_bouquetManager->addBouquet(Bouquets[0]->Name.c_str(), false);
dest = g_bouquetManager->existsBouquet(Bouquets[0]->Name.c_str(), true);
}
else
bouquet = g_bouquetManager->Bouquets[dest];
/* list from scanned exist in file */
for(unsigned int i = 0; i < Bouquets[0]->tvChannels.size(); i++) {
if(!(g_bouquetManager->existsChannelInBouquet(dest, Bouquets[0]->tvChannels[i]->getChannelID()))) {
bouquet->addService(Bouquets[0]->tvChannels[i]);
//Bouquets[0]->tvChannels[i]->pname = (char *) bouquet->Name.c_str();
DBG("save Bouquets: adding channel %s\n", Bouquets[0]->tvChannels[i]->getName().c_str());
}
}
for(unsigned int i = 0; i < Bouquets[0]->radioChannels.size(); i++) {
if(!(g_bouquetManager->existsChannelInBouquet(dest, Bouquets[0]->radioChannels[i]->getChannelID()))) {
bouquet->addService(Bouquets[0]->radioChannels[i]);
//Bouquets[0]->tvChannels[i]->pname = (char *) bouquet->Name.c_str();
DBG("save Bouquets: adding channel %s\n", Bouquets[0]->radioChannels[i]->getName().c_str());
}
}
bouquet->sortBouquet();
delete Bouquets[0];
Bouquets.erase(Bouquets.begin());
}
}
}
void CBouquetManager::sortBouquets(void)
{
sort(Bouquets.begin(), Bouquets.end(), CmpBouquetByChName());
}
void CBouquetManager::parseBouquetsXml(const char *fname, bool bUser)
{
xmlDocPtr parser;
parser = parseXmlFile(fname);
if (parser == NULL)
return;
xmlNodePtr root = xmlDocGetRootElement(parser);
xmlNodePtr search = xmlChildrenNode(root);
xmlNodePtr channel_node;
if (search) {
t_original_network_id original_network_id;
t_service_id service_id;
t_transport_stream_id transport_stream_id;
int16_t satellitePosition;
freq_id_t freq = 0;
INFO("reading bouquets from %s", fname);
while ((search = xmlGetNextOccurence(search, "Bouquet")) != NULL) {
const char * name = xmlGetAttribute(search, "name");
if(name == NULL)
name = const_cast<char*>("Unknown");
CZapitBouquet* newBouquet = addBouquet(name, bUser);
// per default in contructor: newBouquet->BqID = 0; //set to default, override if bqID exists
GET_ATTR(search, "bqID", SCANF_BOUQUET_ID_TYPE, newBouquet->BqID);
const char* hidden = xmlGetAttribute(search, "hidden");
const char* locked = xmlGetAttribute(search, "locked");
const char* scanepg = xmlGetAttribute(search, "epg");
const char* useci = xmlGetAttribute(search, "ci");
newBouquet->bHidden = hidden ? (strcmp(hidden, "1") == 0) : false;
newBouquet->bLocked = locked ? (strcmp(locked, "1") == 0) : false;
newBouquet->bFav = (strcasecmp(name, DEFAULT_BQ_NAME_FAV) == 0);
if (newBouquet->bFav)
newBouquet->bName = g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME);
else
newBouquet->bName = name;
newBouquet->bScanEpg = scanepg ? (strcmp(scanepg, "1") == 0) : false;
newBouquet->bUseCI = useci ? (strcmp(useci, "1") == 0) : false;
channel_node = xmlChildrenNode(search);
while ((channel_node = xmlGetNextOccurence(channel_node, "S")) != NULL) {
std::string name2;
name = xmlGetAttribute(channel_node, "n");
if (name)
name2 = name;
std::string uname;
const char *uName = xmlGetAttribute(channel_node, "un");
if (uName)
uname = uName;
const char *url = xmlGetAttribute(channel_node, "u");
GET_ATTR(channel_node, "i", SCANF_SERVICE_ID_TYPE, service_id);
GET_ATTR(channel_node, "on", SCANF_ORIGINAL_NETWORK_ID_TYPE, original_network_id);
GET_ATTR(channel_node, "s", SCANF_SATELLITE_POSITION_TYPE, satellitePosition);
GET_ATTR(channel_node, "t", SCANF_TRANSPORT_STREAM_ID_TYPE, transport_stream_id);
GET_ATTR(channel_node, "frq", SCANF_SATELLITE_POSITION_TYPE, freq);
bool clock = xmlGetNumericAttribute(channel_node, "l", 10);
if(freq > 20000)
freq = freq/1000;
CZapitChannel* chan;
t_channel_id chid = create_channel_id64(service_id, original_network_id, transport_stream_id,
satellitePosition, freq, url);
/* FIXME to load old cable settings with new cable "positions" started from 0xF00 */
if(!url && (bUser || CFEManager::getInstance()->cableOnly()))
chan = CServiceManager::getInstance()->FindChannelFuzzy(chid, satellitePosition, freq);
else
chan = CServiceManager::getInstance()->FindChannel(chid);
if (chan != NULL) {
DBG("%04x %04x %04x %s\n", transport_stream_id, original_network_id, service_id, xmlGetAttribute(channel_node, "n"));
if(bUser && !(uname.empty()))
chan->setUserName(uname);
if(!bUser)
chan->pname = (char *) newBouquet->Name.c_str();
chan->bLocked = clock;
chan->bUseCI = newBouquet->bUseCI;
//remapping epg_id
t_channel_id new_epgid = reMapEpgID(chan->getChannelID());
if(new_epgid)
chan->setEPGid(new_epgid);
std::string new_epgxml = reMapEpgXML(chan->getChannelID());
if(!new_epgxml.empty()) {
char buf[100];
snprintf(buf, sizeof(buf), "%llx", chan->getChannelID() & 0xFFFFFFFFFFFFULL);
chan->setEPGmap("#" + new_epgxml + "=" + buf);
}
newBouquet->addService(chan);
} else if (bUser) {
if (url) {
chid = create_channel_id64(0, 0, 0, 0, 0, url);
chan = new CZapitChannel(name2.c_str(), chid, url, NULL);
}
else
chan = new CZapitChannel(name2, CREATE_CHANNEL_ID64, 1 /*service_type*/,
satellitePosition, freq);
CServiceManager::getInstance()->AddChannel(chan);
chan->flags = CZapitChannel::NOT_FOUND;
chan->bLocked = clock;
if(!(uname.empty()))
chan->setUserName(uname);
newBouquet->addService(chan);
CServiceManager::getInstance()->SetServicesChanged(false);
}
channel_node = xmlNextNode(channel_node);
if(!bUser) {
/* set satellite position for provider bouquets.
reset position to 0, if position not match - means mixed bouquet */
if (newBouquet->satellitePosition == INVALID_SAT_POSITION)
newBouquet->satellitePosition = satellitePosition;
else if (newBouquet->satellitePosition != satellitePosition)
newBouquet->satellitePosition = 0;
}
}
if(!bUser)
newBouquet->sortBouquet();
search = xmlNextNode(search);
}
INFO("total: %d bouquets", (int)Bouquets.size());
}
xmlFreeDoc(parser);
}
void CBouquetManager::loadBouquets(bool ignoreBouquetFile)
{
TIMER_START();
clearAll();
readEPGMapping();
if (ignoreBouquetFile == false) {
parseBouquetsXml(BOUQUETS_XML, false);
sortBouquets();
}
CNeutrinoApp::getInstance()->g_settings_xmltv_xml_auto_clear();
loadWebtv();
loadWebradio();
parseBouquetsXml(UBOUQUETS_XML, true);
renumServices();
CServiceManager::getInstance()->SetCIFilter();
if(!EpgIDMapping.empty()){
EpgIDMapping.clear();
}
if(!EpgXMLMapping.empty()){
EpgXMLMapping.clear();
}
LogoStart();
TIMER_STOP("[zapit] bouquet loading took");
}
void CBouquetManager::renumChannels(ZapitChannelList &list, int & counter, char * pname)
{
for(zapit_list_it_t it = list.begin(); it != list.end(); it++) {
if(!(*it)->number)
(*it)->number = counter++;
if(!(*it)->pname && pname)
(*it)->pname = pname;
if ((*it)->pname)
(*it)->has_bouquet = true;
}
}
void CBouquetManager::makeRemainingChannelsBouquet(void)
{
ZapitChannelList unusedChannels;
//FIXME services loaded before config.
//bool tomake = CZapit::getInstance()->makeRemainingChannelsBouquet();
/* reset channel number and has_bouquet flag */
CServiceManager::getInstance()->ResetChannelNumbers();
//int i = 1, j = 1;
int i = CServiceManager::getInstance()->GetMaxNumber(false);
int j = CServiceManager::getInstance()->GetMaxNumber(true);
/* FIXME temp debug */
printf("############## CBouquetManager::makeRemainingChannelsBouquet: numbers start at: tv %d radio %d ############\n", i, j);
for (std::vector<CZapitBouquet*>::const_iterator it = Bouquets.begin(); it != Bouquets.end(); ++it) {
renumChannels((*it)->tvChannels, i, (*it)->bUser ? NULL : (char *) (*it)->Name.c_str());
renumChannels((*it)->radioChannels, j, (*it)->bUser ? NULL : (char *) (*it)->Name.c_str());
}
if(/*!tomake ||*/ CServiceManager::getInstance()->GetAllUnusedChannels(unusedChannels) == false)
return;
sort(unusedChannels.begin(), unusedChannels.end(), CmpChannelByChName());
// TODO: use locales
if (remainChannels == NULL)
remainChannels = addBouquet(Bouquets.empty() ? DEFAULT_BQ_NAME_ALL : DEFAULT_BQ_NAME_OTHER, false); // UTF-8 encoded
remainChannels->bOther = true;
remainChannels->bName = g_Locale->getText(LOCALE_BOUQUETNAME_OTHER);
for (ZapitChannelList::const_iterator it = unusedChannels.begin(); it != unusedChannels.end(); ++it) {
remainChannels->addService(*it);
}
renumChannels(remainChannels->tvChannels, i);
renumChannels(remainChannels->radioChannels, j);
}
void CBouquetManager::renumServices()
{
#if 0
if(remainChannels)
deleteBouquet(remainChannels);
remainChannels = NULL;
#endif
if(remainChannels) {
remainChannels->tvChannels.clear();
remainChannels->radioChannels.clear();
}
makeRemainingChannelsBouquet();
}
CZapitBouquet* CBouquetManager::addBouquet(const std::string & name, bool ub, bool myfav, bool to_begin)
{
CZapitBouquet* newBouquet = new CZapitBouquet(myfav ? DEFAULT_BQ_NAME_FAV : name);
newBouquet->bUser = ub;
newBouquet->bFav = myfav;
if (newBouquet->bFav)
newBouquet->bName = g_Locale->getText(LOCALE_FAVORITES_BOUQUETNAME);
else
newBouquet->bName = name;
newBouquet->satellitePosition = INVALID_SAT_POSITION;
//printf("CBouquetManager::addBouquet: %s, user %s\n", name.c_str(), ub ? "YES" : "NO");
if(ub) {
BouquetList::iterator it;
if (to_begin) {
it = Bouquets.begin();
} else {
for(it = Bouquets.begin(); it != Bouquets.end(); ++it)
if(!(*it)->bUser)
break;
}
Bouquets.insert(it, newBouquet);
} else
Bouquets.push_back(newBouquet);
return newBouquet;
}
void CBouquetManager::deleteBouquet(const unsigned int id)
{
if (id < Bouquets.size() && Bouquets[id] != remainChannels)
deleteBouquet(Bouquets[id]);
}
void CBouquetManager::deleteBouquet(const CZapitBouquet* bouquet)
{
if (bouquet != NULL) {
BouquetList::iterator it = find(Bouquets.begin(), Bouquets.end(), bouquet);
if (it != Bouquets.end()) {
if ((*it)->bLocked) {
ZapitChannelList *channels = &(*it)->tvChannels;
for(unsigned int i = 0; i < channels->size(); i++)
((*channels)[i])->bLockCount--;
channels = &(*it)->radioChannels;
for(unsigned int i = 0; i < channels->size(); i++)
((*channels)[i])->bLockCount--;
}
Bouquets.erase(it);
delete bouquet;
}
}
}
void CBouquetManager::setBouquetLock(const unsigned int id, bool state)
{
if (id < Bouquets.size())
setBouquetLock(Bouquets[id], state);
}
void CBouquetManager::setBouquetLock(CZapitBouquet* bouquet, bool state)
{
bouquet->bLocked = state;
int add = bouquet->bLocked * 2 - 1;
ZapitChannelList *channels = &bouquet->tvChannels;
for(unsigned int i = 0; i < channels->size(); i++)
((*channels)[i])->bLockCount += add;
channels = &bouquet->radioChannels;
for(unsigned int i = 0; i < channels->size(); i++)
((*channels)[i])->bLockCount += add;
}
#if 0
int str_compare_withoutspace(char const *s1, char const *s2)
{
int cmp_result = 0;
while(isspace(*s1)) ++s1;
while(isspace(*s2)) ++s2;
while(!cmp_result && *s1++ && *s2++){
while(isspace(*s1)) ++s1;
while(isspace(*s2)) ++s2;
cmp_result = tolower(*s1) - tolower(*s2);
}
return cmp_result;
}
#endif
// -- Find Bouquet-Name, if BQ exists (2002-04-02 rasc)
// -- Return: Bouqet-ID (found: 0..n) or -1 (Bouquet does not exist)
int CBouquetManager::existsBouquet(char const * const name, bool ignore_user)
{
for (unsigned int i = 0; i < Bouquets.size(); i++) {
if ((!ignore_user || !Bouquets[i]->bUser) && (Bouquets[i]->Name == name))
{
return (int)i;
}
#if 0
else if (strcasecmp(Bouquets[i]->Name.c_str(), name)==0)
{
int lower1 = 0, lower2 = 0;
int upper1 = 0 ,upper2 = 0;
std::string str2 = name;
size_t pos=0;
size_t pos2 = Bouquets[i]->Name.find("] ");
if(pos != std::string::npos){
pos += pos2;
}
while (Bouquets[i]->Name[pos]){
if(islower(Bouquets[i]->Name[pos])){
++lower1;
}
if(isupper(Bouquets[i]->Name[pos])){
++upper1;
}
if(islower(str2[pos])){
++lower2;
}
if(isupper(str2[pos])){
++upper2;
}
pos++;
}
if ( ( upper2 && (lower1 < lower2)) || (lower2==0 && upper1==0 && upper2==lower1) ){
Bouquets[i]->Name = str2;
}
return (int)i;
}else if(!(str_compare_withoutspace(Bouquets[i]->Name.c_str(), name)) )
{
if(strlen(name) > Bouquets[i]->Name.length()){
Bouquets[i]->Name = name;
}
return (int)i;
}
#endif
}
return -1;
}
int CBouquetManager::existsUBouquet(char const * const name, bool myfav)
{
unsigned int i;
for (i = 0; i < Bouquets.size(); i++) {
if(myfav) {
if (Bouquets[i]->bFav)
return (int)i;
}
else if (Bouquets[i]->bUser && (Bouquets[i]->Name == name))
return (int)i;
else if (Bouquets[i]->bUser && (Bouquets[i]->bName == name))
return (int)i;
}
return -1;
}
// -- Check if channel exists in BQ (2002-04-05 rasc)
// -- Return: True/false
bool CBouquetManager::existsChannelInBouquet( unsigned int bq_id, const t_channel_id channel_id)
{
bool status = false;
CZapitChannel *ch = NULL;
if (bq_id <= Bouquets.size()) {
// query TV-Channels && Radio channels
ch = Bouquets[bq_id]->getChannelByChannelID(channel_id, 0);
if (ch) status = true;
}
return status;
}
void CBouquetManager::moveBouquet(const unsigned int oldId, const unsigned int newId)
{
if ((oldId < Bouquets.size()) && (newId < Bouquets.size())) {
BouquetList::iterator it = Bouquets.begin();
advance(it, oldId);
CZapitBouquet* tmp = *it;
Bouquets.erase(it);
it = Bouquets.begin();
advance(it, newId);
Bouquets.insert(it, tmp);
}
}
void CBouquetManager::clearAll(bool user)
{
LogoStop();
LogoList.clear();
BouquetList tmplist;
for (unsigned int i =0; i < Bouquets.size(); i++) {
if (user || !Bouquets[i]->bUser)
delete Bouquets[i];
else
tmplist.push_back(Bouquets[i]);
}
Bouquets.clear();
if (!user)
Bouquets = tmplist;
remainChannels = NULL;
}
void CBouquetManager::deletePosition(t_satellite_position satellitePosition)
{
BouquetList tmplist;
for (unsigned int i =0; i < Bouquets.size(); i++) {
if (satellitePosition == Bouquets[i]->satellitePosition) {
printf("CBouquetManager::deletePosition: delete [%s]\n", Bouquets[i]->Name.c_str());
delete Bouquets[i];
} else
tmplist.push_back(Bouquets[i]);
}
Bouquets = tmplist;
}
CZapitBouquet* CBouquetManager::addBouquetIfNotExist(const std::string &name)
{
CZapitBouquet* bouquet = NULL;
int bouquetId = existsBouquet(name.c_str(), true);
if (bouquetId == -1)
bouquet = addBouquet(name, false);
else
bouquet = Bouquets[bouquetId];
return bouquet;
}
void CBouquetManager::loadWebtv()
{
loadWebchannels(MODE_WEBTV);
}
void CBouquetManager::loadWebradio()
{
loadWebchannels(MODE_WEBRADIO);
}
void CBouquetManager::loadWebchannels(int mode)
{
std::list<std::string> *webchannels_xml = (mode == MODE_WEBTV) ? CZapit::getInstance()->GetWebTVXML() : CZapit::getInstance()->GetWebRadioXML();
if (!webchannels_xml)
return;
for (std::list<std::string>::iterator it = webchannels_xml->begin(); it != webchannels_xml->end(); ++it)
{
std::string filename = (*it);
std::string extension = getFileExt(filename);
std::string tmp_name = randomFile(extension, LOGODIR_TMP);
bool remove_tmp = false;
if (filename.compare(0, 1, "/") == 0)
tmp_name = filename;
else
{
if (::downloadUrl(filename, tmp_name))
remove_tmp = true;
}
if (!access(tmp_name.c_str(), R_OK))
{
INFO("Loading %s from %s ...", (mode == MODE_WEBTV) ? "webtv" : "webradio", filename.c_str());
// check for extension
bool xml = false;
bool m3u = false;
bool e2tv = false;
if (strcasecmp("xml", extension.c_str()) == 0)
xml = true;
if ((strcasecmp("m3u", extension.c_str()) == 0) || (strcasecmp("m3u8", extension.c_str()) == 0))
m3u = true;
if (strcasecmp("tv", extension.c_str()) == 0)
e2tv = true;
if (xml)
{
xmlDocPtr parser = parseXmlFile(tmp_name.c_str());
if (parser == NULL)
continue;
xmlNodePtr l0 = xmlDocGetRootElement(parser);
xmlNodePtr l1 = xmlChildrenNode(l0);
if (l1)
{
CZapitBouquet* pbouquet = NULL;
const char *prov = xmlGetAttribute(l0, "name");
if (!prov)
prov = (mode == MODE_WEBTV) ? "WebTV" : "WebRadio";
pbouquet = addBouquetIfNotExist(prov);
if (mode == MODE_WEBTV)
pbouquet->bWebtv = true;
else
pbouquet->bWebradio = true;
while ((xmlGetNextOccurence(l1, (mode == MODE_WEBTV) ? "webtv" : "webradio")))
{
const char *title = xmlGetAttribute(l1, "title");
const char *url = xmlGetAttribute(l1, "url");
const char *desc = xmlGetAttribute(l1, "description");
const char *genre = xmlGetAttribute(l1, "genre");
const char *epgid = xmlGetAttribute(l1, "epgid");
const char *xmltv = xmlGetAttribute(l1, "xmltv");
const char *epgmap = xmlGetAttribute(l1, "epgmap");
const char *alogo = xmlGetAttribute(l1, "logo");
const char *script = xmlGetAttribute(l1, "script");
if(alogo && !strlen(alogo))
{
alogo = NULL;//skip 0 len logo
}
t_channel_id epg_id = 0;
if (epgid)
{
if (strcmp(epgid, "auto") == 0 && title)
{
CZapitChannel * channel = CServiceManager::getInstance()->FindChannelByPattern(title);
if (channel && !IS_WEBCHAN(channel->getChannelID()))
{
epg_id = channel->getChannelID();
INFO("* auto epg_id found for %s: " PRINTF_CHANNEL_ID_TYPE, title, epg_id);
}
}
else
epg_id = strtoull(epgid, NULL, 16);
}
CZapitBouquet* gbouquet = pbouquet;
if (genre)
{
std::string bname = prov ? std::string(std::string(prov) + " ") + genre : genre;
gbouquet = addBouquetIfNotExist(bname);
if (mode == MODE_WEBTV)
gbouquet->bWebtv = true;
else
gbouquet->bWebradio = true;
}
if (title && url)
{
t_channel_id chid = create_channel_id64(0, 0, 0, 0, 0, url);
if (epg_id == 0) epg_id = chid;
CZapitChannel * channel = new CZapitChannel(title, chid, url, desc, epg_id, script, mode);
CServiceManager::getInstance()->AddChannel(channel);
//remapping epg_id
t_channel_id new_epgid = reMapEpgID(chid);
if(new_epgid)
channel->setEPGid(new_epgid);
if (xmltv)
{
CNeutrinoApp::getInstance()->g_settings_xmltv_xml_auto_pushback(std::string(xmltv));
}
char buf[100];
snprintf(buf, sizeof(buf), "%llx", chid & 0xFFFFFFFFFFFFULL);
std::string new_epgxml = reMapEpgXML(chid);
if(!new_epgxml.empty()) {
channel->setEPGmap("#" + new_epgxml + "=" + buf);
}
// local epgmap overrides global epgmap
if (epgmap)
{
std::string new_epgmap(epgmap);
if(!new_epgmap.empty())
channel->setEPGmap("#" + new_epgmap + "=" + buf);
}
std::string helper = "alternate_logos";
if (alogo && !g_PicViewer->GetLogoName(chid, std::string(title), helper))
{
channel->setAlternateLogo(std::string(alogo));
LogoList.push_back(chid);
}
channel->flags = CZapitChannel::UPDATED;
if (gbouquet)
gbouquet->addService(channel);
}
l1 = xmlNextNode(l1);
}
}
xmlFreeDoc(parser);
}
else if (m3u)
{
std::ifstream infile;
char cLine[1024];
std::string epg_url = "";
std::string title = "";
std::string prefix = "";
std::string group = "";
std::string desc = "";
std::string epgid = "";
std::string alogo = "";
std::string script = "";
CZapitBouquet* pbouquet = NULL;
infile.open(tmp_name.c_str(), std::ifstream::in);
while (infile.good())
{
infile.getline(cLine, sizeof(cLine));
// remove CR
if(cLine[strlen(cLine) - 1] == '\r')
cLine[strlen(cLine) - 1] = 0;
std::string strLine = cLine;
if (strLine.empty())
continue;
if (strLine.find(M3U_START_MARKER) != std::string::npos)
{
epg_url = "";
epg_url = ReadMarkerValue(strLine, TVG_URL_MARKER);
if (epg_url.empty())
epg_url = ReadMarkerValue(strLine, X_TVG_URL_MARKER);
//printf("tvg-url: %s\n", epg_url.c_str());
if (!epg_url.empty())
{
if (epg_url.find_first_of(',') != std::string::npos)
{
std::vector<std::string> epg_list = ::split(epg_url, ',');
for (std::vector<std::string>::iterator it_epg = epg_list.begin(); it_epg != epg_list.end(); it_epg++)
CNeutrinoApp::getInstance()->g_settings_xmltv_xml_auto_pushback((*it_epg));
}
else
CNeutrinoApp::getInstance()->g_settings_xmltv_xml_auto_pushback(epg_url);
}
}
if (strLine.find(M3U_INFO_MARKER) != std::string::npos)
{
int fPos = strLine.find_last_of('"') != std::string::npos ? strLine.find_last_of('"') : 0;
int iColon = (int)strLine.find_first_of(':');
int iComma = (int)strLine.find_first_of(',',fPos);
title = "";
prefix = "";
group = "";
desc = "";
epgid = "";
alogo = "";
script = "";
if (iColon >= 0 && iComma >= 0 && iComma > iColon)
{
iComma++;
iColon++;
title = strLine.substr(iComma);
std::string strInfoLine = strLine.substr(iColon, --iComma - iColon);
prefix = ReadMarkerValue(strInfoLine, GROUP_PREFIX_MARKER);
group = ReadMarkerValue(strInfoLine, GROUP_NAME_MARKER);
desc = ReadMarkerValue(strInfoLine, TVG_NAME_MARKER);
epgid = ReadMarkerValue(strInfoLine, TVG_ID_MARKER);
alogo = ReadMarkerValue(strInfoLine, TVG_LOGO_MARKER);
script = ReadMarkerValue(strInfoLine, TVG_SCRIPT_MARKER);
}
pbouquet = addBouquetIfNotExist((mode == MODE_WEBTV) ? "WebTV" : "WebRadio");
if (mode == MODE_WEBTV)
pbouquet->bWebtv = true;
else
pbouquet->bWebradio = true;
}
else if (strLine[0] != '#')
{
char *url = NULL;
if ((url = strstr(cLine, "http://")) || (url = strstr(cLine, "https://")) || (url = strstr(cLine, "rtmp://")) || (url = strstr(cLine, "rtsp://")) || (url = strstr(cLine, "rtp://")) || (url = strstr(cLine, "mmsh://")) )
{
if (url != NULL)
{
if (desc.empty())
desc = "m3u stream";
CZapitBouquet* gbouquet = pbouquet;
if (!group.empty())
{
std::string bname = prefix;
if (bname.compare("") == 0)
{
bname = (mode == MODE_WEBTV) ? "WebTV" : "WebRadio";
bname += ": " + group;
}
else if (bname.compare("none") == 0)
bname = group;
else
bname += " " + group;
gbouquet = addBouquetIfNotExist(bname);
if (mode == MODE_WEBTV)
gbouquet->bWebtv = true;
else
gbouquet->bWebradio = true;
}
t_channel_id chid = create_channel_id64(0, 0, 0, 0, 0, url);
CZapitChannel * channel = new CZapitChannel(title.c_str(), chid, url, desc.c_str(), chid, script.c_str(), mode);
CServiceManager::getInstance()->AddChannel(channel);
if (!epgid.empty()) {
char buf[100];
snprintf(buf, sizeof(buf), "%llx", chid & 0xFFFFFFFFFFFFULL);
// keep the tvg-id for later epg injection
channel->setEPGmap("#" + epgid + "=" + buf);
}
//remapping epg_id
t_channel_id new_epgid = reMapEpgID(chid);
if(new_epgid)
channel->setEPGid(new_epgid);
std::string new_epgxml = reMapEpgXML(chid);
if(!new_epgxml.empty()) {
char buf[100];
snprintf(buf, sizeof(buf), "%llx", chid & 0xFFFFFFFFFFFFULL);
channel->setEPGmap("#" + new_epgxml + "=" + buf);
}
std::string helper = "alternate_logos";
if (!alogo.empty() && !g_PicViewer->GetLogoName(chid, title, helper))
{
channel->setAlternateLogo(alogo);
LogoList.push_back(chid);
}
channel->flags = CZapitChannel::UPDATED;
if (gbouquet)
gbouquet->addService(channel);
}
}
}
}
infile.close();
}
else if (e2tv)
{
FILE * f = fopen(tmp_name.c_str(), "r");
std::string title;
std::string URL;
std::string url;
std::string desc;
std::string group;
t_channel_id epg_id = 0;
CZapitBouquet* pbouquet = NULL;
if(f != NULL)
{
while(true)
{
char line[1024];
if (!fgets(line, 1024, f))
break;
size_t len = strlen(line);
if (len < 2)
// Lines with less than one char aren't meaningful
continue;
// strip newline
line[--len] = 0;
// strip carriage return (when found)
if (line[len - 1] == '\r')
line[len - 1 ] = 0;
if (strncmp(line, "#NAME", 5) == 0)
{
group = line + 6;
}
else if (strncmp(line, "#SERVICE", 8) == 0)
{
char *url2 = NULL;
u_int service;
u_int i1,i2,i3,i4,satpos;
sscanf (line,"#SERVICE %X:0:%X:%X:%X:%X:%X:0:0:0:%m[^\n]s",&service,&i1,&i2,&i3,&i4,&satpos,&url2);
if (url2 == NULL)
{
url.clear();
continue;
}
url = url2;
free(url2);
t_channel_id tmpchid = (((t_channel_id)i3) << 32) | (((t_channel_id)i4) << 16) | (t_channel_id)i2;
CZapitChannel * tmp_channel = CServiceManager::getInstance()->FindChannel48(tmpchid);
if (tmp_channel)
{
epg_id = tmp_channel->getChannelID();
//printf("e2 chan: %s\n",tmp_channel->getName().c_str());
}
}
else if (strncmp(line, "#DESCRIPTION", 12) == 0)
{
int offs = line[12] == ':' ? 14 : 13;
title = line + offs;
desc = "e2 stream";
pbouquet = addBouquetIfNotExist((mode == MODE_WEBTV) ? "WebTV" : "WebRadio");
if (mode == MODE_WEBTV)
pbouquet->bWebtv = true;
else
pbouquet->bWebradio = true;
CZapitBouquet* gbouquet = pbouquet;
if (!group.empty())
{
std::string bname = (mode == MODE_WEBTV) ? "WebTV" : "WebRadio";
bname += ": " + group;
gbouquet = addBouquetIfNotExist(bname);
if (mode == MODE_WEBTV)
gbouquet->bWebtv = true;
else
gbouquet->bWebradio = true;
}
if (!url.empty())
{
t_channel_id chid = create_channel_id64(0, 0, 0, 0, 0, ::decodeUrl(url).c_str());
CZapitChannel * channel = new CZapitChannel(title.c_str(), chid, ::decodeUrl(url).c_str(), desc.c_str(), epg_id ? epg_id : chid, NULL, mode);
CServiceManager::getInstance()->AddChannel(channel);
//remapping epg_id
t_channel_id new_epgid = reMapEpgID(chid);
if(new_epgid)
channel->setEPGid(new_epgid);
std::string new_epgxml = reMapEpgXML(chid);
if(!new_epgxml.empty()) {
char buf[100];
snprintf(buf, sizeof(buf), "%llx", chid & 0xFFFFFFFFFFFFULL);
channel->setEPGmap("#" + new_epgxml + "=" + buf);
}
channel->flags = CZapitChannel::UPDATED;
if (gbouquet)
gbouquet->addService(channel);
}
}
}
fclose(f);
}
}
}
if (remove_tmp)
remove(tmp_name.c_str());
}
}
bool CBouquetManager::LogoStart()
{
if (logo_running)
return false;
if (LogoList.size() == 0)
return false;
logo_running = true;
return (OpenThreads::Thread::start() == 0);
}
bool CBouquetManager::LogoStop()
{
if (!logo_running)
return false;
logo_running = false;
return (OpenThreads::Thread::join() == 0);
}
void CBouquetManager::run()
{
set_threadname(__func__);
//printf(">>>>>> LogoThread [%s] started...\n",__func__);
CZapitChannel *cc = NULL;
std::string ologo;
std::string nlogo;
t_channel_id chid = 0;
std::list<t_channel_id>::iterator it = LogoList.begin();
while (logo_running && it != LogoList.end())
{
chid = (*it);
cc = CServiceManager::getInstance()->FindChannel(chid);
if (logo_running && cc)
ologo = cc->getAlternateLogo();
else
break;
cc = CServiceManager::getInstance()->FindChannel(chid);
if (logo_running && cc)
nlogo = downloadUrlToLogo(ologo, LOGODIR_TMP, chid);
else
break;
cc = CServiceManager::getInstance()->FindChannel(chid);
if (logo_running && cc)
cc->setAlternateLogo(nlogo);
else
break;
it++;
}
LogoList.clear();
logo_running = false;
//printf(">>>>>>> LogoThread [%s] stopped...\n",__func__);
}
CBouquetManager::ChannelIterator::ChannelIterator(CBouquetManager* owner, const bool TV)
{
Owner = owner;
tv = TV;
if (Owner->Bouquets.empty())
c = -2;
else {
b = 0;
c = -1;
(*this)++;
}
}
CBouquetManager::ChannelIterator CBouquetManager::ChannelIterator::operator ++(int)
{
if (c != -2) // we can add if it's not the end marker
{
c++;
if ((unsigned int) c >= getBouquet()->size()) {
for (b++; b < Owner->Bouquets.size(); b++)
if ( !getBouquet()->empty() ) {
c = 0;
goto end;
}
c = -2;
}
}
end:
return(*this);
}
CZapitChannel* CBouquetManager::ChannelIterator::operator *()
{
return (*getBouquet())[c]; // returns junk if we are an end marker !!
}
CBouquetManager::ChannelIterator CBouquetManager::ChannelIterator::FindChannelNr(const unsigned int channel)
{
c = channel;
for (b = 0; b < Owner->Bouquets.size(); b++)
if (getBouquet()->size() > (unsigned int)c)
goto end;
else
c -= getBouquet()->size();
c = -2;
end:
return (*this);
}
#if 0
int CBouquetManager::ChannelIterator::getLowestChannelNumberWithChannelID(const t_channel_id channel_id)
{
int i = 0;
for (b = 0; b < Owner->Bouquets.size(); b++)
for (c = 0; (unsigned int) c < getBouquet()->size(); c++, i++)
if ((**this)->getChannelID() == channel_id)
return (**this)->number -1;
//return i;
return -1; // not found
}
#endif
int CBouquetManager::ChannelIterator::getNrofFirstChannelofBouquet(const unsigned int bouquet_nr)
{
if (bouquet_nr >= Owner->Bouquets.size())
return -1; // not found
int i = 0;
for (b = 0; b < bouquet_nr; b++)
i += getBouquet()->size();
return i;
}
t_channel_id CBouquetManager::reMapEpgID(t_channel_id channelid)
{
if(!EpgIDMapping.empty()){
std::map<t_channel_id, t_channel_id>::iterator it = EpgIDMapping.find(channelid);
if ( it != EpgIDMapping.end() )
return it->second;
}
return 0;
}
std::string CBouquetManager::reMapEpgXML(t_channel_id channelid)
{
if(!EpgXMLMapping.empty()){
std::map<t_channel_id, std::string>::iterator it = EpgXMLMapping.find(channelid);
if ( it != EpgXMLMapping.end() ){
INFO("mapping: %012" PRIx64 " to %s", channelid, it->second.c_str());
return it->second;
}
}
return "";
}
void CBouquetManager::readEPGMapping()
{
if(!EpgIDMapping.empty())
EpgIDMapping.clear();
if(!EpgXMLMapping.empty())
EpgXMLMapping.clear();
std::list<std::string> epgmap_dirs;
epgmap_dirs.push_back(ZAPITDIR);
epgmap_dirs.push_back(WEBTVDIR);
epgmap_dirs.push_back(WEBTVDIR_VAR);
std::list<std::string> epgmaps;
for (std::list<std::string>::iterator it = epgmap_dirs.begin(); it != epgmap_dirs.end(); ++it)
{
DIR *dp;
struct dirent *d;
if ((dp = opendir((*it).c_str())) == NULL)
continue;
while ((d = readdir(dp)) != NULL)
{
std::string f = d->d_name;
if ((f.compare("epgmap.xml") == 0) || (f.find(".epgmap") != std::string::npos))
epgmaps.push_back((*it) + "/" + f);
}
closedir(dp);
}
for (std::list<std::string>::iterator it = epgmaps.begin(); it != epgmaps.end(); ++it)
{
INFO("read %s", (*it).c_str());
xmlDocPtr epgmap_parser = parseXmlFile((*it).c_str());
if (epgmap_parser != NULL)
{
xmlNodePtr epgmap = xmlDocGetRootElement(epgmap_parser);
if (epgmap)
epgmap = xmlChildrenNode(epgmap);
while (epgmap)
{
const char *channelid = xmlGetAttribute(epgmap, "channel_id");
const char *epgid = xmlGetAttribute(epgmap, "new_epg_id");
const char *xmlepg = xmlGetData(epgmap); // returns empty string, not NULL if nothing found
t_channel_id channel_id = 0;
t_channel_id epg_id = 0;
if (channelid)
channel_id = strtoull(channelid, NULL, 16);
if (epgid)
epg_id = strtoull(epgid, NULL, 16);
if (channel_id && epg_id)
EpgIDMapping[channel_id]=epg_id;
if (channel_id && ((xmlepg != NULL) && (xmlepg[0] != '\0')))
EpgXMLMapping[channel_id]=xmlepg;
epgmap = xmlNextNode(epgmap);
}
}
xmlFreeDoc(epgmap_parser);
}
}
void CBouquetManager::convert_E2_EPGMapping(std::string mapfile_in, std::string mapfile_out)
{
FILE * outfile = NULL;
xmlDocPtr epgmap_parser = parseXmlFile(mapfile_in.c_str());
if (epgmap_parser != NULL)
{
outfile = fopen(mapfile_out.c_str(), "w");
xmlNodePtr epgmap = xmlDocGetRootElement(epgmap_parser);
if(epgmap)
epgmap = xmlChildrenNode(epgmap);
fprintf(outfile,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<zapit>\n");
while (epgmap) {
const char *e2_channelid = xmlGetData(epgmap);
const char *xmlepg = xmlGetAttribute(epgmap, "id");
if (e2_channelid[0] != '\0') {
u_int sid = 0,tsid = 0,onid = 0,sat = 0;
sscanf(e2_channelid,"1:0:1:%X:%X:%X:%X0000:0:0:0:", &sid, &tsid, &onid, &sat);
t_channel_id short_channel_id = create_channel_id(sid,onid,tsid);
CZapitChannel * cc = CServiceManager::getInstance()->FindChannel48(short_channel_id);
if (cc) {
if(xmlepg){
fprintf(outfile,"\t<filter channel_id=\"%012" PRIx64 "\" >%s</filter> --%s\n",cc->getChannelID(), xmlepg, cc->getName().c_str());
}
}
}
epgmap = xmlNextNode(epgmap);
}
fprintf(outfile, "</zapit>\n");
fclose(outfile);
}
xmlFreeDoc(epgmap_parser);
}
void CBouquetManager::dump_EPGMapping(std::string mapfile_out)
{
FILE * outfile = NULL;
CBouquetManager::ChannelIterator cit = g_bouquetManager->tvChannelsBegin();
outfile = fopen(mapfile_out.c_str(), "w");
fprintf(outfile,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<zapit>\n");
for (; !(cit.EndOfChannels()); cit++)
{
if ((*cit)->getChannelID() != (*cit)->getEpgID())
fprintf(outfile,"\t<filter channel_id=\"%012" PRIx64 "\" new_epg_id=\"%012" PRIx64 "\" /> --%s\n",(*cit)->getChannelID(), (*cit)->getEpgID(), (*cit)->getName().c_str());
std::string tvg_id = (*cit)->getEPGmap();
if (tvg_id.empty())
continue;
tvg_id = tvg_id.substr(1,tvg_id.find_first_of("=")-1);
fprintf(outfile,"\t<filter channel_id=\"%012" PRIx64 "\" >%s</filter> --%s\n",(*cit)->getChannelID(), tvg_id.c_str(), (*cit)->getName().c_str());
}
fprintf(outfile, "</zapit>\n");
fclose(outfile);
}
std::string CBouquetManager::ReadMarkerValue(std::string strLine, const char* strMarkerName)
{
if (strLine.find(strMarkerName) != std::string::npos)
{
strLine = strLine.substr(strLine.find(strMarkerName));
strLine = strLine.substr(strLine.find_first_of('"')+1);
strLine = strLine.substr(0,strLine.find_first_of('"'));
return strLine;
}
return std::string("");
}