vdr-plugin-skindesigner/views/displaymenudetailview.c

930 lines
42 KiB
C
Raw Normal View History

2014-09-27 09:25:14 +02:00
#include "displaymenudetailview.h"
#include "../libcore/helpers.h"
#include "../services/scraper2vdr.h"
#include "../services/epgsearch.h"
cDisplayMenuDetailView::cDisplayMenuDetailView(cTemplateView *tmplDetailView) : cView(tmplDetailView) {
event = NULL;
recording = NULL;
text = NULL;
detailViewInit = true;
currentTmplTab = NULL;
tabView = NULL;
}
cDisplayMenuDetailView::~cDisplayMenuDetailView() {
CancelSave();
if (tabView)
delete tabView;
}
void cDisplayMenuDetailView::Clear(void) {
ClearViewElement(veDetailHeader);
ClearViewElement(veScrollbar);
ClearViewElement(veTabLabels);
}
void cDisplayMenuDetailView::Render(void) {
if (detailViewInit) {
DrawHeader();
DoFlush();
SetTokens();
InitTabs();
currentTmplTab = *atIt;
detailViewInit = false;
}
if (!tabView) {
tabView = new cDisplayMenuTabView(currentTmplTab);
tabView->SetTokens(&intTokens, &stringTokens, &loopTokens);
tabView->CreateTab();
tabView->Start();
}
DrawScrollbar();
DrawTabLabels();
}
void cDisplayMenuDetailView::KeyLeft(void) {
if (activeTabs.size() > 1) {
currentTmplTab = GetPrevTab();
delete tabView;
tabView = NULL;
Render();
DoFlush();
} else {
bool scrolled = tabView->KeyLeft();
if (scrolled) {
DrawScrollbar();
DoFlush();
}
}
}
void cDisplayMenuDetailView::KeyRight(void) {
if (activeTabs.size() > 1) {
currentTmplTab = GetNextTab();
delete tabView;
tabView = NULL;
Render();
DoFlush();
} else {
bool scrolled = tabView->KeyRight();
if (scrolled) {
DrawScrollbar();
DoFlush();
}
}
}
void cDisplayMenuDetailView::KeyUp(void) {
if (!tabView)
return;
bool scrolled = tabView->KeyUp();
if (scrolled) {
DrawScrollbar();
DoFlush();
}
}
void cDisplayMenuDetailView::KeyDown(void) {
if (!tabView)
return;
bool scrolled = tabView->KeyDown();
if (scrolled) {
DrawScrollbar();
DoFlush();
}
}
void cDisplayMenuDetailView::SetTokens(void) {
if (event) {
stringTokens.insert(pair<string,string>("title", event->Title() ? event->Title() : ""));
stringTokens.insert(pair<string,string>("shorttext", event->ShortText() ? event->ShortText() : ""));
stringTokens.insert(pair<string,string>("description", event->Description() ? event->Description() : ""));
stringTokens.insert(pair<string,string>("start", *(event->GetTimeString())));
stringTokens.insert(pair<string,string>("stop", *(event->GetEndTimeString())));
stringTokens.insert(pair<string,string>("day", *WeekDayName(event->StartTime())));
stringTokens.insert(pair<string,string>("date", *ShortDateString(event->StartTime())));
stringTokens.insert(pair<string,string>("channelid", *(event->ChannelID().ToString())));
bool isRunning = false;
time_t now = time(NULL);
if ((now >= event->StartTime()) && (now <= event->EndTime()))
isRunning = true;
intTokens.insert(pair<string,int>("running", isRunning));
if (isRunning) {
intTokens.insert(pair<string,int>("elapsed", (now - event->StartTime())/60));
} else {
intTokens.insert(pair<string,int>("elapsed", 0));
}
intTokens.insert(pair<string,int>("duration", event->Duration() / 60));
vector< map< string, string > > reruns;
bool hasReruns = LoadReruns(&reruns);
loopTokens.insert(pair<string, vector< map< string, string > > >("reruns", reruns));
intTokens.insert(pair<string,int>("hasreruns", hasReruns));
SetScraperTokens();
SetEpgPictures(event->EventID());
} else if (recording) {
string name = recording->Name() ? recording->Name() : "";
stringTokens.insert(pair<string,string>("name", name));
const cRecordingInfo *info = recording->Info();
if (info) {
stringTokens.insert(pair<string,string>("shorttext", info->ShortText() ? info->ShortText() : ""));
stringTokens.insert(pair<string,string>("description", info->Description() ? info->Description() : ""));
const cEvent *event = info->GetEvent();
if (event) {
string recDate = *(event->GetDateString());
string recTime = *(event->GetTimeString());
if (recDate.find("1970") != string::npos) {
time_t start = recording->Start();
recDate = *DateString(start);
recTime = *TimeString(start);
}
int duration = event->Duration() / 60;
int recDuration = recording->LengthInSeconds();
recDuration = (recDuration>0)?(recDuration / 60):0;
stringTokens.insert(pair<string,string>("date", recDate.c_str()));
stringTokens.insert(pair<string,string>("time", recTime.c_str()));
intTokens.insert(pair<string,int>("duration", recDuration));
intTokens.insert(pair<string,int>("durationevent", duration));
}
} else {
stringTokens.insert(pair<string,string>("shorttext", ""));
stringTokens.insert(pair<string,string>("description", ""));
int recDuration = recording->LengthInSeconds();
recDuration = (recDuration>0)?(recDuration / 60):0;
stringTokens.insert(pair<string,string>("date", ""));
stringTokens.insert(pair<string,string>("time", ""));
intTokens.insert(pair<string,int>("duration", recDuration));
intTokens.insert(pair<string,int>("durationevent", 0));
}
LoadRecordingInformation();
SetScraperTokens();
SetRecordingImages(recording->FileName());
} else if (text) {
stringTokens.insert(pair<string,string>("text", text));
} else {
intTokens.insert(pair<string,int>("running", false));
intTokens.insert(pair<string,int>("hasreruns", false));
}
}
void cDisplayMenuDetailView::SetScraperTokens(void) {
static cPlugin *pScraper = GetScraperPlugin();
if (!pScraper || (!event && !recording)) {
intTokens.insert(pair<string,int>("ismovie", false));
intTokens.insert(pair<string,int>("isseries", false));
return;
}
ScraperGetEventType getType;
getType.event = event;
getType.recording = recording;
if (!pScraper->Service("GetEventType", &getType)) {
intTokens.insert(pair<string,int>("ismovie", false));
intTokens.insert(pair<string,int>("isseries", false));
return;
}
if (getType.type == tMovie) {
cMovie movie;
movie.movieId = getType.movieId;
pScraper->Service("GetMovie", &movie);
intTokens.insert(pair<string,int>("ismovie", true));
intTokens.insert(pair<string,int>("isseries", false));
stringTokens.insert(pair<string,string>("movietitle", movie.title));
stringTokens.insert(pair<string,string>("movieoriginalTitle", movie.originalTitle));
stringTokens.insert(pair<string,string>("movietagline", movie.tagline));
stringTokens.insert(pair<string,string>("movieoverview", movie.overview));
stringTokens.insert(pair<string,string>("moviegenres", movie.genres));
stringTokens.insert(pair<string,string>("moviehomepage", movie.homepage));
stringTokens.insert(pair<string,string>("moviereleasedate", movie.releaseDate));
stringstream pop;
pop << movie.popularity;
stringTokens.insert(pair<string,string>("moviepopularity", pop.str()));
stringstream vote;
vote << movie.voteAverage;
stringTokens.insert(pair<string,string>("movievoteaverage", pop.str()));
stringTokens.insert(pair<string,string>("posterpath", movie.poster.path));
stringTokens.insert(pair<string,string>("fanartpath", movie.fanart.path));
stringTokens.insert(pair<string,string>("collectionposterpath", movie.collectionPoster.path));
stringTokens.insert(pair<string,string>("collectionfanartpath", movie.collectionFanart.path));
intTokens.insert(pair<string,int>("movieadult", movie.adult));
intTokens.insert(pair<string,int>("moviebudget", movie.budget));
intTokens.insert(pair<string,int>("movierevenue", movie.revenue));
intTokens.insert(pair<string,int>("movieruntime", movie.runtime));
intTokens.insert(pair<string,int>("posterwidth", movie.poster.width));
intTokens.insert(pair<string,int>("posterheight", movie.poster.height));
intTokens.insert(pair<string,int>("fanartwidth", movie.fanart.width));
intTokens.insert(pair<string,int>("fanartheight", movie.fanart.height));
intTokens.insert(pair<string,int>("collectionposterwidth", movie.collectionPoster.width));
intTokens.insert(pair<string,int>("collectionposterheight", movie.collectionPoster.height));
intTokens.insert(pair<string,int>("collectionfanartwidth", movie.collectionFanart.width));
intTokens.insert(pair<string,int>("collectionfanartheight", movie.collectionFanart.height));
vector< map< string, string > > actors;
for (vector<cActor>::iterator act = movie.actors.begin(); act != movie.actors.end(); act++) {
map< string, string > actor;
actor.insert(pair<string, string>("actors[name]", (*act).name));
actor.insert(pair<string, string>("actors[role]", (*act).role));
actor.insert(pair<string, string>("actors[thumb]", (*act).actorThumb.path));
stringstream actWidth, actHeight;
actWidth << (*act).actorThumb.width;
actHeight << (*act).actorThumb.height;
actor.insert(pair<string, string>("actors[thumbwidth]", actWidth.str()));
actor.insert(pair<string, string>("actors[thumbheight]", actHeight.str()));
actors.push_back(actor);
}
loopTokens.insert(pair<string, vector< map< string, string > > >("actors", actors));
} else if (getType.type == tSeries) {
cSeries series;
series.seriesId = getType.seriesId;
series.episodeId = getType.episodeId;
pScraper->Service("GetSeries", &series);
intTokens.insert(pair<string,int>("ismovie", false));
intTokens.insert(pair<string,int>("isseries", true));
//Series Basics
stringTokens.insert(pair<string,string>("seriesname", series.name));
stringTokens.insert(pair<string,string>("seriesoverview", series.overview));
stringTokens.insert(pair<string,string>("seriesfirstaired", series.firstAired));
stringTokens.insert(pair<string,string>("seriesnetwork", series.network));
stringTokens.insert(pair<string,string>("seriesgenre", series.genre));
stringstream rating;
rating << series.rating;
stringTokens.insert(pair<string,string>("seriesrating", rating.str()));
stringTokens.insert(pair<string,string>("seriesstatus", series.status));
//Episode Information
intTokens.insert(pair<string,int>("episodenumber", series.episode.number));
intTokens.insert(pair<string,int>("episodeseason", series.episode.season));
stringTokens.insert(pair<string,string>("episodetitle", series.episode.name));
stringTokens.insert(pair<string,string>("episodefirstaired", series.episode.firstAired));
stringTokens.insert(pair<string,string>("episodegueststars", series.episode.guestStars));
stringTokens.insert(pair<string,string>("episodeoverview", series.episode.overview));
stringstream eprating;
eprating << series.episode.rating;
stringTokens.insert(pair<string,string>("episoderating", eprating.str()));
intTokens.insert(pair<string,int>("episodeimagewidth", series.episode.episodeImage.width));
intTokens.insert(pair<string,int>("episodeimageheight", series.episode.episodeImage.height));
stringTokens.insert(pair<string,string>("episodeimagepath", series.episode.episodeImage.path));
//Seasonposter
intTokens.insert(pair<string,int>("seasonposterwidth", series.seasonPoster.width));
intTokens.insert(pair<string,int>("seasonposterheight", series.seasonPoster.height));
stringTokens.insert(pair<string,string>("seasonposterpath", series.seasonPoster.path));
//Posters
int current = 1;
for(vector<cTvMedia>::iterator poster = series.posters.begin(); poster != series.posters.end(); poster++) {
stringstream labelWidth, labelHeight, labelPath;
labelWidth << "seriesposter" << current << "width";
labelHeight << "seriesposter" << current << "height";
labelPath << "seriesposter" << current << "path";
intTokens.insert(pair<string,int>(labelWidth.str(), (*poster).width));
intTokens.insert(pair<string,int>(labelHeight.str(), (*poster).height));
stringTokens.insert(pair<string,string>(labelPath.str(), (*poster).path));
current++;
}
if (current < 3) {
for (; current < 4; current++) {
stringstream labelWidth, labelHeight, labelPath;
labelWidth << "seriesposter" << current << "width";
labelHeight << "seriesposter" << current << "height";
labelPath << "seriesposter" << current << "path";
intTokens.insert(pair<string,int>(labelWidth.str(), 0));
intTokens.insert(pair<string,int>(labelHeight.str(), 0));
stringTokens.insert(pair<string,string>(labelPath.str(), ""));
}
}
//Banners
current = 1;
for(vector<cTvMedia>::iterator banner = series.banners.begin(); banner != series.banners.end(); banner++) {
stringstream labelWidth, labelHeight, labelPath;
labelWidth << "seriesbanner" << current << "width";
labelHeight << "seriesbanner" << current << "height";
labelPath << "seriesbanner" << current << "path";
intTokens.insert(pair<string,int>(labelWidth.str(), (*banner).width));
intTokens.insert(pair<string,int>(labelHeight.str(), (*banner).height));
stringTokens.insert(pair<string,string>(labelPath.str(), (*banner).path));
current++;
}
if (current < 3) {
for (; current < 4; current++) {
stringstream labelWidth, labelHeight, labelPath;
labelWidth << "seriesbanner" << current << "width";
labelHeight << "seriesbanner" << current << "height";
labelPath << "seriesbanner" << current << "path";
intTokens.insert(pair<string,int>(labelWidth.str(), 0));
intTokens.insert(pair<string,int>(labelHeight.str(), 0));
stringTokens.insert(pair<string,string>(labelPath.str(), ""));
}
}
//Fanarts
current = 1;
for(vector<cTvMedia>::iterator fanart = series.fanarts.begin(); fanart != series.fanarts.end(); fanart++) {
stringstream labelWidth, labelHeight, labelPath;
labelWidth << "seriesfanart" << current << "width";
labelHeight << "seriesfanart" << current << "height";
labelPath << "seriesfanart" << current << "path";
intTokens.insert(pair<string,int>(labelWidth.str(), (*fanart).width));
intTokens.insert(pair<string,int>(labelHeight.str(), (*fanart).height));
stringTokens.insert(pair<string,string>(labelPath.str(), (*fanart).path));
current++;
}
if (current < 3) {
for (; current < 4; current++) {
stringstream labelWidth, labelHeight, labelPath;
labelWidth << "seriesfanart" << current << "width";
labelHeight << "seriesfanart" << current << "height";
labelPath << "seriesfanart" << current << "path";
intTokens.insert(pair<string,int>(labelWidth.str(), 0));
intTokens.insert(pair<string,int>(labelHeight.str(), 0));
stringTokens.insert(pair<string,string>(labelPath.str(), ""));
}
}
//Actors
vector< map< string, string > > actors;
for (vector<cActor>::iterator act = series.actors.begin(); act != series.actors.end(); act++) {
map< string, string > actor;
actor.insert(pair<string, string>("actors[name]", (*act).name));
actor.insert(pair<string, string>("actors[role]", (*act).role));
actor.insert(pair<string, string>("actors[thumb]", (*act).actorThumb.path));
stringstream actWidth, actHeight;
actWidth << (*act).actorThumb.width;
actHeight << (*act).actorThumb.height;
actor.insert(pair<string, string>("actors[thumbwidth]", actWidth.str()));
actor.insert(pair<string, string>("actors[thumbheight]", actHeight.str()));
actors.push_back(actor);
}
loopTokens.insert(pair<string, vector< map< string, string > > >("actors", actors));
} else {
intTokens.insert(pair<string,int>("ismovie", false));
intTokens.insert(pair<string,int>("isseries", false));
}
}
void cDisplayMenuDetailView::InitTabs(void) {
tmplView->InitViewTabIterator();
cTemplateViewTab *tmplTab = NULL;
while(tmplTab = tmplView->GetNextViewTab()) {
tmplTab->ParseDynamicParameters(&intTokens, true);
tmplTab->ClearDynamicFunctionParameters();
tmplTab->ParseDynamicFunctionParameters(&stringTokens, &intTokens);
if (tmplTab->DoExecute()) {
activeTabs.push_back(tmplTab);
}
}
atIt = activeTabs.begin();
}
bool cDisplayMenuDetailView::LoadReruns(vector< map< string, string > > *reruns) {
if (!event)
return false;
cPlugin *epgSearchPlugin = cPluginManager::GetPlugin("epgsearch");
if (!epgSearchPlugin)
return false;
if (isempty(event->Title()))
return false;
int maxNumReruns = 10;
Epgsearch_searchresults_v1_0 data;
string strQuery = event->Title();
data.useSubTitle = true;
data.query = (char *)strQuery.c_str();
data.mode = 0;
data.channelNr = 0;
data.useTitle = true;
data.useDescription = false;
bool foundRerun = false;
if (epgSearchPlugin->Service("Epgsearch-searchresults-v1.0", &data)) {
cList<Epgsearch_searchresults_v1_0::cServiceSearchResult>* list = data.pResultList;
if (list && (list->Count() > 1)) {
foundRerun = true;
int i = 0;
for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r = list->First(); r && i < maxNumReruns; r = list->Next(r)) {
if ((event->ChannelID() == r->event->ChannelID()) && (event->StartTime() == r->event->StartTime()))
continue;
i++;
map< string, string > rerun;
rerun.insert(pair<string, string>("reruns[title]", r->event->Title() ? r->event->Title() : ""));
rerun.insert(pair<string, string>("reruns[shorttext]", r->event->ShortText() ? r->event->ShortText() : ""));
rerun.insert(pair<string, string>("reruns[start]", *(r->event->GetTimeString())));
rerun.insert(pair<string, string>("reruns[start]", *(r->event->GetTimeString())));
rerun.insert(pair<string, string>("reruns[stop]", *(r->event->GetEndTimeString())));
rerun.insert(pair<string, string>("reruns[date]", *ShortDateString(r->event->StartTime())));
rerun.insert(pair<string, string>("reruns[day]", *WeekDayName(r->event->StartTime())));
string channelID = *(r->event->ChannelID().ToString());
rerun.insert(pair<string, string>("reruns[channelid]", channelID));
bool logoExists = imgCache->LogoExists(channelID);
rerun.insert(pair<string, string>("reruns[channellogoexists]", logoExists ? "1" : "0"));
cChannel *channel = Channels.GetByChannelID(r->event->ChannelID(), true, true);
if (channel) {
stringstream channelNumber;
channelNumber << channel->Number();
rerun.insert(pair<string, string>("reruns[channelname]", channel->ShortName(true)));
rerun.insert(pair<string, string>("reruns[channelnumber]", channelNumber.str()));
} else {
rerun.insert(pair<string, string>("reruns[channelname]", ""));
rerun.insert(pair<string, string>("reruns[channelnumber]", ""));
}
reruns->push_back(rerun);
}
delete list;
}
}
return foundRerun;
}
void cDisplayMenuDetailView::LoadRecordingInformation(void) {
const cRecordingInfo *Info = recording->Info();
if (!Info)
return;
unsigned long long nRecSize = -1;
unsigned long long nFileSize[1000];
nFileSize[0] = 0;
int i = 0;
struct stat filebuf;
cString filename;
int rc = 0;
do {
if (recording->IsPesRecording())
filename = cString::sprintf("%s/%03d.vdr", recording->FileName(), ++i);
else
filename = cString::sprintf("%s/%05d.ts", recording->FileName(), ++i);
rc = stat(filename, &filebuf);
if (rc == 0)
nFileSize[i] = nFileSize[i-1] + filebuf.st_size;
else
if (ENOENT != errno) {
nRecSize = -1;
}
} while (i <= 999 && !rc);
nRecSize = nFileSize[i-1];
cMarks marks;
bool fHasMarks = marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && marks.Count();
cIndexFile *index = new cIndexFile(recording->FileName(), false, recording->IsPesRecording());
int nCutLength = 0;
long nCutInFrame = 0;
unsigned long long nRecSizeCut = nRecSize < 0 ? -1 : 0;
unsigned long long nCutInOffset = 0;
if (fHasMarks && index) {
uint16_t FileNumber;
off_t FileOffset;
bool fCutIn = true;
cMark *mark = marks.First();
while (mark) {
int pos = mark->Position();
index->Get(pos, &FileNumber, &FileOffset); //TODO: will disc spin up?
if (fCutIn) {
nCutInFrame = pos;
fCutIn = false;
if (nRecSize >= 0)
nCutInOffset = nFileSize[FileNumber-1] + FileOffset;
} else {
nCutLength += pos - nCutInFrame;
fCutIn = true;
if (nRecSize >= 0)
nRecSizeCut += nFileSize[FileNumber-1] + FileOffset - nCutInOffset;
}
cMark *nextmark = marks.Next(mark);
mark = nextmark;
}
if (!fCutIn) {
nCutLength += index->Last() - nCutInFrame;
index->Get(index->Last() - 1, &FileNumber, &FileOffset);
if (nRecSize >= 0)
nRecSizeCut += nFileSize[FileNumber-1] + FileOffset - nCutInOffset;
}
}
if (nRecSize < 0) {
if ((nRecSize = ReadSizeVdr(recording->FileName())) < 0) {
nRecSize = DirSizeMB(recording->FileName());
}
}
if (nRecSize >= 0) {
cString strRecSize = "";
cString strRecSizeCut = "";
if (fHasMarks) {
if (nRecSize > MEGABYTE(1023)) {
strRecSize = cString::sprintf("%.2f GB", (float)nRecSize / MEGABYTE(1024));
strRecSizeCut = cString::sprintf("%.2f GB", (float)nRecSizeCut / MEGABYTE(1024));
} else {
strRecSize = cString::sprintf("%lld MB", nRecSize / MEGABYTE(1));
strRecSizeCut = cString::sprintf("%lld MB", nRecSizeCut / MEGABYTE(1));
}
} else {
if (nRecSize > MEGABYTE(1023)) {
strRecSize = cString::sprintf("%.2f GB", (float)nRecSize / MEGABYTE(1024));
strRecSizeCut = strRecSize;
} else {
strRecSize = cString::sprintf("%lld MB", nRecSize / MEGABYTE(1));
strRecSizeCut = strRecSize;
}
}
stringTokens.insert(pair<string,string>("recordingsize", *strRecSize));
stringTokens.insert(pair<string,string>("recordingsizecutted", *strRecSizeCut));
} else {
stringTokens.insert(pair<string,string>("recordingsize", ""));
stringTokens.insert(pair<string,string>("recordingsizecutted", ""));
}
cChannel *channel = Channels.GetByChannelID(Info->ChannelID());
if (channel) {
stringTokens.insert(pair<string,string>("recchannelname", channel->Name()));
intTokens.insert(pair<string,int>("recchannelnumber", channel->Number()));
}
if (index) {
int nLastIndex = index->Last();
if (nLastIndex) {
string strLength = *IndexToHMSF(nLastIndex, false, recording->FramesPerSecond());
string strLengthCutted = "";
if (fHasMarks) {
strLengthCutted = *IndexToHMSF(nCutLength, false, recording->FramesPerSecond());
} else {
strLengthCutted = strLength;
}
string strBitrate = *cString::sprintf("%.2f MBit/s", (float)nRecSize / nLastIndex * recording->FramesPerSecond() * 8 / MEGABYTE(1));
stringTokens.insert(pair<string,string>("recordinglength", strLength));
stringTokens.insert(pair<string,string>("recordinglengthcutted", strLengthCutted));
stringTokens.insert(pair<string,string>("recordingbitrate", strBitrate));
}
delete index;
}
string recFormat = recording->IsPesRecording() ? "PES" : "TS";
stringTokens.insert(pair<string,string>("recordingformat", recFormat));
bool searchTimerFound = false;
if (Info) {
const char *aux = NULL;
aux = Info->Aux();
if (aux) {
string strAux = aux;
string auxEpgsearch = StripXmlTag(strAux, "epgsearch");
if (!auxEpgsearch.empty()) {
string searchTimer = StripXmlTag(auxEpgsearch, "searchtimer");
if (!searchTimer.empty()) {
stringTokens.insert(pair<string,string>("searchtimer", searchTimer));
searchTimerFound = true;
}
}
}
}
if (!searchTimerFound)
stringTokens.insert(pair<string,string>("searchtimer", "n.a."));
}
string cDisplayMenuDetailView::StripXmlTag(string &Line, const char *Tag) {
// set the search strings
stringstream strStart, strStop;
strStart << "<" << Tag << ">";
strStop << "</" << Tag << ">";
// find the strings
string::size_type locStart = Line.find(strStart.str());
string::size_type locStop = Line.find(strStop.str());
if (locStart == string::npos || locStop == string::npos)
return "";
// extract relevant text
int pos = locStart + strStart.str().size();
int len = locStop - pos;
return len < 0 ? "" : Line.substr(pos, len);
}
int cDisplayMenuDetailView::ReadSizeVdr(const char *strPath) {
int dirSize = -1;
char buffer[20];
char *strFilename = NULL;
if (-1 != asprintf(&strFilename, "%s/size.vdr", strPath)) {
struct stat st;
if (stat(strFilename, &st) == 0) {
int fd = open(strFilename, O_RDONLY);
if (fd >= 0) {
if (safe_read(fd, &buffer, sizeof(buffer)) >= 0) {
dirSize = atoi(buffer);
}
close(fd);
}
}
free(strFilename);
}
return dirSize;
}
void cDisplayMenuDetailView::SetEpgPictures(int eventId) {
for (int i=0; i<3; i++) {
stringstream picName;
picName << eventId << "_" << i;
bool epgPicAvailable = FileExists(*config.epgImagePath, picName.str(), "jpg");
stringstream available;
stringstream path;
available << "epgpic" << i+1 << "avaialble";
path << "epgpic" << i+1 << "path";
if (epgPicAvailable) {
intTokens.insert(pair<string,int>(available.str(), true));
stringTokens.insert(pair<string,string>(path.str(), *cString::sprintf("%s%s.jpg", *config.epgImagePath, picName.str().c_str())));
} else {
intTokens.insert(pair<string,int>(available.str(), false));
stringTokens.insert(pair<string,string>(path.str(), ""));
}
}
}
void cDisplayMenuDetailView::SetRecordingImages(const char *recPath) {
if (!recPath) {
intTokens.insert(pair<string,int>("recimg1avaialble", false));
intTokens.insert(pair<string,int>("recimg2avaialble", false));
intTokens.insert(pair<string,int>("recimg3avaialble", false));
stringTokens.insert(pair<string,string>("recimg1path", ""));
stringTokens.insert(pair<string,string>("recimg2path", ""));
stringTokens.insert(pair<string,string>("recimg3path", ""));
return;
}
string path = recPath;
DIR *dirHandle;
struct dirent *dirEntry;
dirHandle = opendir(recPath);
if (!dirHandle) {
intTokens.insert(pair<string,int>("recimg1avaialble", false));
intTokens.insert(pair<string,int>("recimg2avaialble", false));
intTokens.insert(pair<string,int>("recimg3avaialble", false));
stringTokens.insert(pair<string,string>("recimg1path", ""));
stringTokens.insert(pair<string,string>("recimg2path", ""));
stringTokens.insert(pair<string,string>("recimg3path", ""));
return;
}
int picsFound = 0;
while ( 0 != (dirEntry = readdir(dirHandle))) {
if (endswith(dirEntry->d_name, "jpg")) {
string fileName = dirEntry->d_name;
stringstream available;
available << "recimg" << picsFound+1 << "avaialble";
stringstream path;
path << "recimg" << picsFound+1 << "path";
intTokens.insert(pair<string,int>(available.str(), true));
stringTokens.insert(pair<string,string>(path.str(), *cString::sprintf("%s/%s", recPath, fileName.c_str())));
picsFound++;
}
if (picsFound == 3) {
break;
}
}
for (int i=picsFound; i<3; i++) {
stringstream available;
available << "recimg" << i+1 << "avaialble";
stringstream path;
path << "recimg" << i+1 << "path";
intTokens.insert(pair<string,int>(available.str(), false));
stringTokens.insert(pair<string,string>(path.str(), ""));
}
closedir(dirHandle);
}
void cDisplayMenuDetailView::DrawHeader(void) {
map < string, string > headerStringTokens;
map < string, int > headerIntTokens;
if (event || recording) {
static cPlugin *pScraper = GetScraperPlugin();
if (!pScraper) {
headerIntTokens.insert(pair<string,int>("ismovie", false));
headerIntTokens.insert(pair<string,int>("isseries", false));
headerIntTokens.insert(pair<string,int>("posteravailable", false));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
} else {
ScraperGetEventType getType;
getType.event = event;
getType.recording = recording;
if (!pScraper->Service("GetEventType", &getType)) {
headerIntTokens.insert(pair<string,int>("ismovie", false));
headerIntTokens.insert(pair<string,int>("isseries", false));
headerIntTokens.insert(pair<string,int>("posteravailable", false));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
} else {
if (getType.type == tMovie) {
cMovie movie;
movie.movieId = getType.movieId;
pScraper->Service("GetMovie", &movie);
headerIntTokens.insert(pair<string,int>("ismovie", true));
headerIntTokens.insert(pair<string,int>("isseries", false));
headerIntTokens.insert(pair<string,int>("posteravailable", true));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
headerStringTokens.insert(pair<string,string>("posterpath", movie.poster.path));
headerIntTokens.insert(pair<string,int>("posterwidth", movie.poster.width));
headerIntTokens.insert(pair<string,int>("posterheight", movie.poster.height));
} else if (getType.type == tSeries) {
cSeries series;
series.seriesId = getType.seriesId;
series.episodeId = getType.episodeId;
pScraper->Service("GetSeries", &series);
headerIntTokens.insert(pair<string,int>("ismovie", false));
headerIntTokens.insert(pair<string,int>("isseries", true));
vector<cTvMedia>::iterator poster = series.posters.begin();
if (poster != series.posters.end()) {
headerIntTokens.insert(pair<string,int>("posterwidth", (*poster).width));
headerIntTokens.insert(pair<string,int>("posterheight", (*poster).height));
headerStringTokens.insert(pair<string,string>("posterpath", (*poster).path));
headerIntTokens.insert(pair<string,int>("posteravailable", true));
} else {
headerIntTokens.insert(pair<string,int>("posterwidth", 0));
headerIntTokens.insert(pair<string,int>("posterheight", 0));
headerStringTokens.insert(pair<string,string>("posterpath", ""));
headerIntTokens.insert(pair<string,int>("posteravailable", false));
}
vector<cTvMedia>::iterator banner = series.banners.begin();
if (banner != series.banners.end()) {
headerIntTokens.insert(pair<string,int>("bannerwidth", (*banner).width));
headerIntTokens.insert(pair<string,int>("bannerheight", (*banner).height));
headerStringTokens.insert(pair<string,string>("bannerpath", (*banner).path));
headerIntTokens.insert(pair<string,int>("banneravailable", true));
} else {
headerIntTokens.insert(pair<string,int>("bannerwidth", 0));
headerIntTokens.insert(pair<string,int>("bannerheight", 0));
headerStringTokens.insert(pair<string,string>("bannerpath", ""));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
}
} else {
headerIntTokens.insert(pair<string,int>("ismovie", false));
headerIntTokens.insert(pair<string,int>("isseries", false));
headerIntTokens.insert(pair<string,int>("posteravailable", false));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
}
}
}
}
if (event) {
headerStringTokens.insert(pair<string,string>("title", event->Title() ? event->Title() : ""));
headerStringTokens.insert(pair<string,string>("shorttext", event->ShortText() ? event->ShortText() : ""));
headerStringTokens.insert(pair<string,string>("start", *(event->GetTimeString())));
headerStringTokens.insert(pair<string,string>("stop", *(event->GetEndTimeString())));
headerStringTokens.insert(pair<string,string>("day", *WeekDayName(event->StartTime())));
headerStringTokens.insert(pair<string,string>("date", *ShortDateString(event->StartTime())));
headerStringTokens.insert(pair<string,string>("channelid", *(event->ChannelID().ToString())));
bool isRunning = false;
time_t now = time(NULL);
if ((now >= event->StartTime()) && (now <= event->EndTime()))
isRunning = true;
headerIntTokens.insert(pair<string,int>("running", isRunning));
if (isRunning) {
headerIntTokens.insert(pair<string,int>("elapsed", (now - event->StartTime())/60));
} else {
headerIntTokens.insert(pair<string,int>("elapsed", 0));
}
headerIntTokens.insert(pair<string,int>("duration", event->Duration() / 60));
stringstream epgImageName;
epgImageName << event->EventID();
bool epgPicAvailable = FileExists(*config.epgImagePath, epgImageName.str(), "jpg");
if (epgPicAvailable) {
headerIntTokens.insert(pair<string,int>("epgpicavailable", true));
headerStringTokens.insert(pair<string,string>("epgpicpath", *cString::sprintf("%s%s.jpg", *config.epgImagePath, epgImageName.str().c_str())));
} else {
epgImageName << "_0";
epgPicAvailable = FileExists(*config.epgImagePath, epgImageName.str(), "jpg");
if (epgPicAvailable) {
headerIntTokens.insert(pair<string,int>("epgpicavailable", true));
headerStringTokens.insert(pair<string,string>("epgpicpath", *cString::sprintf("%s%s.jpg", *config.epgImagePath, epgImageName.str().c_str())));
} else {
headerIntTokens.insert(pair<string,int>("epgpicavailable", false));
headerStringTokens.insert(pair<string,string>("epgpicpath", ""));
}
}
DrawViewElement(veDetailHeader, &headerStringTokens, &headerIntTokens);
} else if (recording) {
string name = recording->Name() ? recording->Name() : "";
headerStringTokens.insert(pair<string,string>("name", name));
const cRecordingInfo *info = recording->Info();
if (info) {
headerStringTokens.insert(pair<string,string>("shorttext", info->ShortText() ? info->ShortText() : ""));
const cEvent *event = info->GetEvent();
if (event) {
string recDate = *(event->GetDateString());
string recTime = *(event->GetTimeString());
if (recDate.find("1970") != string::npos) {
time_t start = recording->Start();
recDate = *DateString(start);
recTime = *TimeString(start);
}
int duration = event->Duration() / 60;
int recDuration = recording->LengthInSeconds();
recDuration = (recDuration>0)?(recDuration / 60):0;
headerStringTokens.insert(pair<string,string>("date", recDate.c_str()));
headerStringTokens.insert(pair<string,string>("time", recTime.c_str()));
headerIntTokens.insert(pair<string,int>("duration", recDuration));
headerIntTokens.insert(pair<string,int>("durationevent", duration));
}
} else {
headerStringTokens.insert(pair<string,string>("shorttext", ""));
int recDuration = recording->LengthInSeconds();
recDuration = (recDuration>0)?(recDuration / 60):0;
headerStringTokens.insert(pair<string,string>("date", ""));
headerStringTokens.insert(pair<string,string>("time", ""));
headerIntTokens.insert(pair<string,int>("duration", recDuration));
headerIntTokens.insert(pair<string,int>("durationevent", 0));
}
string recImage = "";
string path = recording->FileName() ? recording->FileName() : "";
string extension = ".jpg";
if (FirstFileInFolder(path, extension, recImage)) {
headerIntTokens.insert(pair<string,int>("recimgavailable", true));
headerStringTokens.insert(pair<string,string>("recimgpath", *cString::sprintf("%s/%s", path.c_str(), recImage.c_str())));
} else {
headerIntTokens.insert(pair<string,int>("recimgavailable", false));
headerStringTokens.insert(pair<string,string>("recimgpath", ""));
}
DrawViewElement(veDetailHeader, &headerStringTokens, &headerIntTokens);
}
}
void cDisplayMenuDetailView::DrawScrollbar(void) {
map < string, string > scrollbarStringTokens;
map < string, int > scrollbarIntTokens;
int barTop = 0;
int barHeight = 0;
tabView->GetScrollbarPosition(barTop, barHeight);
scrollbarIntTokens.insert(pair<string,int>("height", barHeight));
scrollbarIntTokens.insert(pair<string,int>("offset", barTop));
ClearViewElement(veScrollbar);
DrawViewElement(veScrollbar, &scrollbarStringTokens, &scrollbarIntTokens);
}
void cDisplayMenuDetailView::DrawTabLabels(void) {
if (!ViewElementImplemented(veTabLabels)) {
return;
}
map < string, string > labelStringTokens;
map < string, int > labelIntTokens;
map < string, vector< map< string, string > > > labelLoopTokens;
vector< map< string, string > > tabLabels;
for (list<cTemplateViewTab*>::iterator it = activeTabs.begin(); it != activeTabs.end(); it++) {
cTemplateViewTab *tab = *it;
map< string, string > tabLabel;
tabLabel.insert(pair< string, string >("tabs[title]", tab->GetName()));
if (tab == currentTmplTab) {
tabLabel.insert(pair< string, string >("tabs[current]", "1"));
} else {
tabLabel.insert(pair< string, string >("tabs[current]", "0"));
}
tabLabels.push_back(tabLabel);
}
labelLoopTokens.insert(pair< string, vector< map< string, string > > >("tabs", tabLabels));
ClearViewElement(veTabLabels);
DrawViewElement(veTabLabels, &labelStringTokens, &labelIntTokens, &labelLoopTokens);
}
cTemplateViewTab *cDisplayMenuDetailView::GetPrevTab(void) {
if (atIt == activeTabs.begin()) {
atIt = activeTabs.end();
}
atIt--;
return *atIt;
}
cTemplateViewTab *cDisplayMenuDetailView::GetNextTab(void) {
atIt++;
if (atIt == activeTabs.end()) {
atIt = activeTabs.begin();
}
return *atIt;
}