summaryrefslogtreecommitdiff
path: root/common.c
diff options
context:
space:
mode:
authorAndreas Brugger <brougs78@gmx.net>2009-06-06 01:29:22 +0200
committerThomas Günther <tom@toms-cafe.de>2009-06-06 01:29:22 +0200
commit60cd7db51838bb076312fd10e08bca0f4a005f82 (patch)
tree2ce8a57369abbd1ac1fed4a0d6527140808fbc3c /common.c
parent5ace1ef884772e4a15d58839074785b89412c8ee (diff)
parentac64ce03ec6b5766691ff2da3af6f51ed800792a (diff)
downloadvdr-plugin-text2skin-60cd7db51838bb076312fd10e08bca0f4a005f82.tar.gz
vdr-plugin-text2skin-60cd7db51838bb076312fd10e08bca0f4a005f82.tar.bz2
Added brougs78-extensions (thanks to Andreas Brugger / references #39)
- added tokens for the next 3 timers: CurrentEventsTitle[123], CurrentEventsStartDateTime[123], CurrentEventsStopDateTime[123], CurrentEventsChannelNumber[123], CurrentEventsChannelName[123], CurrentEventsIsRecording[123] - added audio- and video-tokens: PresentLanguageCode, PresentLanguageDescription, PresentVideoAR and implemented the missing code for the Language-token - added tokens for replay: ReplayName, ReplayDateTime, ReplayShortText, ReplayDescription, ReplayLanguageCode, ReplayLanguageDescription, ReplayVideoAR - additional recording-tokens: RecordingVideoAR, RecordingSize - added a reset for scrolling text (configurable) - added recording-tokens: RecordingLength, RecordingCuttedLength - added tokens: OsdWidth, OsdHeight - switched the search-order for the fonts to priorise the skin-folder (this avoids error-messages in the log) - added the possibility to have a scrollbar in every menu - not fully implemented yet (to position in menu-lists is not necessarily correct, if there are more items with the same osd-text) - added a configuration option for showing the scrollbar in the menus - added token TimerConflicts using the service interface of the epgsearch plugin "Epgsearch-lastconflictinfo-v1.0" - added a test-feature to search for reruns of a program and add the information to the extended epg-info (trigger DEVELOPMENT_FEATURES). This uses a service interface of the epgsearch plugin "Epgsearch-searchresults-v1.0" - the extended epg-info and the recording-info are extended by AUX-Infos (configurable) there is also an option to strip known tags - the tab-widths are scaled for taking into account that different TT-Fonts have a different width than the default font from VDR - added tokens for signal-info: FrontendSTR, FrontendSNR, FrontendHasLock, FrontendHasSignal - added token PresentEventID for EPG-images - added tokens for recordings: RecordingFilename, RecordingPriority, RecordingLifetime - set EditableWidth. This is important for plugins like 'rotor' or 'extrecmenu'
Diffstat (limited to 'common.c')
-rw-r--r--common.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/common.c b/common.c
index 785e74a..728dedb 100644
--- a/common.c
+++ b/common.c
@@ -3,7 +3,13 @@
*/
#include "common.h"
+#include <sstream>
#include <vdr/plugin.h>
+#include <vdr/device.h>
+#include <sys/ioctl.h>
+#include <linux/dvb/frontend.h>
+
+#define FRONTEND_DEVICE "/dev/dvb/adapter%d/frontend%d"
const std::string &SkinPath(void)
{
@@ -69,6 +75,14 @@ const char *ChannelShortName(const cChannel *Channel, int Number)
return buffer;
}
+
+const char *EventType(uint Number)
+{
+ static char buffer[25];
+ buffer[0] = '\0';
+ snprintf(buffer, sizeof(buffer), "%d", Number);
+ return buffer;
+}
/*
const char *ChannelBouquet(const cChannel *Channel, int Number) {
static char buffer[256];
@@ -115,6 +129,271 @@ const cRecording *GetRecordingByName(const char *Name)
return NULL;
}
+const cRecording *GetRecordingByFileName(const char *FileName)
+{
+ return (FileName) ? Recordings.GetByName(FileName) : NULL;
+}
+
+int GetFrontendSTR(void)
+{
+ uint16_t value = 0;
+ char *dev = NULL;
+
+ asprintf(&dev, FRONTEND_DEVICE, cDevice::ActualDevice()->CardIndex(), 0);
+ int fe = open(dev, O_RDONLY | O_NONBLOCK);
+ free(dev);
+ if (fe >= 0) {
+ CHECK(ioctl(fe, FE_READ_SIGNAL_STRENGTH, &value));
+ close(fe);
+ }
+ return value / 655;
+}
+
+int GetFrontendSNR(void)
+{
+ uint16_t value = 0;
+ char *dev = NULL;
+
+ asprintf(&dev, FRONTEND_DEVICE, cDevice::ActualDevice()->CardIndex(), 0);
+ int fe = open(dev, O_RDONLY | O_NONBLOCK);
+ free(dev);
+ if (fe >= 0) {
+ CHECK(ioctl(fe, FE_READ_SNR, &value));
+ close(fe);
+ }
+ return value / 655;
+}
+
+bool GetFrontendHasLock(void)
+{
+ uint16_t value = 0;
+ char *dev = NULL;
+
+ asprintf(&dev, FRONTEND_DEVICE, cDevice::ActualDevice()->CardIndex(), 0);
+ int fe = open(dev, O_RDONLY | O_NONBLOCK);
+ free(dev);
+ if (fe >= 0) {
+ CHECK(ioctl(fe, FE_READ_STATUS, &value));
+ close(fe);
+ }
+ return value & FE_HAS_LOCK;
+}
+
+bool GetFrontendHasSignal(void)
+{
+ uint16_t value = 0;
+ char *dev = NULL;
+
+ asprintf(&dev, FRONTEND_DEVICE, cDevice::ActualDevice()->CardIndex(), 0);
+ int fe = open(dev, O_RDONLY | O_NONBLOCK);
+ free(dev);
+ if (fe >= 0) {
+ CHECK(ioctl(fe, FE_READ_STATUS, &value));
+ close(fe);
+ }
+ return value & FE_HAS_SIGNAL;
+}
+
+std::string AddExtInfoToDescription(const char *Title, const char *ShortText, const char *Description, const char *Aux, bool StripAux)
+{
+ // max. width so lines don't get wrapped
+ #define MAX_CHARS 50
+
+ // prepare the description
+ std::stringstream desc("");
+
+ if (!isempty(Description)) {
+ // it seems that sometimes the description ends with a newline
+ // and sometimes it does not
+ std::string buf(Description);
+ while (!buf.empty() && buf[buf.size() - 1] == '\n') buf.erase(buf.size() - 1);
+ desc << buf << "\n"; // keep one newline
+ }
+
+#ifdef DEVELOPMENT_FEATURES
+ // try to find a rerun of the show using epgsearch-service
+ if (!isempty(Title)) {
+ Epgsearch_searchresults_v1_0 data;
+ data.query = strdup(Title);
+ data.mode = 0;
+ data.channelNr = 0;
+ data.useTitle = true;
+ data.useSubTitle = false;
+ data.useDescription = false;
+ if (cPluginManager::CallFirstService("Epgsearch-searchresults-v1.0", &data)) {
+ cList<Epgsearch_searchresults_v1_0::cServiceSearchResult>* list = data.pResultList;
+ if (list) {
+ // die aktuelle Sendung wird noch als WH angezeigt !!!
+ if (!desc.str().empty()) desc << "\n";
+ desc << tr("RERUNS OF THIS SHOW") << ":\n";
+ int i = 0;
+ for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r =
+ list->First(); r && i < 5; r = list->Next(r)) {
+ i++;
+ std::stringstream buf;
+ buf << " - ";
+ buf << *DayDateTime(r->event->StartTime());
+ buf << ": " << r->event->Title();
+ if (!isempty(r->event->ShortText())) buf << "~" << r->event->ShortText();
+ desc << FitToWidth(buf, MAX_CHARS) << "\n";
+ }
+ delete list;
+ }
+ }
+ }
+#endif // DEVELOPMENT_FEATURES
+
+ // Add the AUX-Info of the Recording
+ if (Aux) {
+ if (StripAux) {
+ std::string auxRaw(Aux);
+ std::string auxEpgsearch = StripXmlTag(auxRaw, "epgsearch");
+ if (!auxEpgsearch.empty()) {
+ if (!desc.str().empty())
+ desc << "\n";
+ desc << tr("AUXILIARY INFOS") << ":\n";
+ std::stringstream buf;
+ buf << " - " << tr("Search timer") << ": " << StripXmlTag(auxRaw, "Search timer");
+ desc << FitToWidth(buf, MAX_CHARS) << "\n";
+ }
+ }
+ else {
+ if (!desc.str().empty())
+ desc << "\n";
+ desc << tr("AUXILIARY INFOS") << ":\n";
+ desc << Aux << "\n";
+ }
+ }
+
+ return desc.str();
+}
+
+int GetRecordingSize(const char *FileName)
+#if VDRVERSNUM >= 10338
+// use VDR's routine
+{
+ const cRecording *rec = GetRecordingByFileName(FileName);
+ return (rec) ? DirSizeMB(FileName) : 0;
+}
+#else
+// use our own approach
+{
+ if (FileName != NULL) {
+ bool bRet = false;
+ long long size = 0;
+ int nFiles;
+ struct stat fileinfo; // Holds file information structure
+ char *cmd = NULL;
+#if VDRVERSNUM >= 10318
+ cReadLine reader;
+#endif
+ asprintf(&cmd, "find '%s' -follow -type f -name '*.*'|sort ", FileName);
+
+ FILE *p = popen(cmd, "r");
+ int ret = 0;
+ if (p) {
+ char *s;
+
+#if VDRVERSNUM >= 10318
+ while ((s = reader.Read(p)) != NULL) {
+#else
+ while ((s = readline(p)) != NULL) {
+#endif
+ if ((ret=stat(s, &fileinfo)) != -1) {
+ size += (long long)fileinfo.st_size;
+ nFiles++;
+ }
+ }
+
+ bRet = true;
+ }
+
+ pclose(p);
+ delete cmd;
+
+ return (int)(size / 1024 / 1024); // [MB]
+ }
+ else
+ return 0;
+}
+#endif
+
+int GetRecordingLength(const char *FileName)
+{
+ // based on the enAIO-Patch for VDR
+ #define INDEXFILESUFFIX "/index.vdr"
+
+ struct tIndex { int offset; uchar type; uchar number; short reserved; };
+ tIndex *index;
+ char RecLength[21];
+ char *filename = NULL;
+ int last = -1;
+ index = NULL;
+ if (FileName) {
+ filename = MALLOC(char, strlen(FileName) + strlen(INDEXFILESUFFIX) + 1);
+ if (filename) {
+ strcpy(filename, FileName);
+ char *pFileExt = filename + strlen(filename);
+ strcpy(pFileExt, INDEXFILESUFFIX);
+ int delta = 0;
+ if (access(filename, R_OK) == 0) {
+ struct stat buf;
+ if (stat(filename, &buf) == 0) {
+ delta = buf.st_size % sizeof(tIndex);
+ if (delta) {
+ delta = sizeof(tIndex) - delta;
+ esyslog("ERROR: invalid file size (%ld) in '%s'", (long)buf.st_size, filename);
+ }
+ last = (buf.st_size + delta) / sizeof(tIndex) - 1;
+ char hour[2], min[3];
+#if VDRVERSNUM >= 10318
+ snprintf(RecLength, sizeof(RecLength), "%s", *IndexToHMSF(last, true));
+#else
+ snprintf(RecLength, sizeof(RecLength), "%s", IndexToHMSF(last, true));
+#endif
+ snprintf(hour, sizeof(hour), "%c", RecLength[0]);
+ snprintf(min, sizeof(min), "%c%c", RecLength[2], RecLength[3]);
+ return (atoi(hour) * 60) + atoi(min);
+ }
+ }
+ free(filename);
+ }
+ }
+
+ return 0;
+}
+
+int GetRecordingCuttedLength(const char *FileName)
+{
+ cMarks marks;
+ double length = 0;
+ int totalLength = GetRecordingLength(FileName);
+ const double diffIFrame = FRAMESPERSEC / 2; // approx. 1/2 sec.
+
+ marks.Load(FileName);
+
+ if (marks.Count()) {
+ int start = 1; // first frame
+ bool isStart = true;
+
+ for (cMark *m = marks.First(); m; m = marks.GetNext(m->position)) {
+ if (isStart)
+ start = m->position;
+ else
+ length += (double)(m->position - start + 1 + diffIFrame) / (FRAMESPERSEC * 60); // [min]
+
+ isStart = !isStart;
+ }
+
+ // if there is no end-mark the last segment goes to the end of the rec.
+ if (!isStart)
+ length += totalLength - (double)(start - 1 - diffIFrame) / (FRAMESPERSEC * 60); // [min]
+ }
+
+ // just to avoid, that the cutted length is bigger than the total length
+ return (int)length > totalLength ? totalLength : (int)length;
+}
+
cxType TimeType(time_t Time, const std::string &Format)
{
static char result[1000];
@@ -263,3 +542,40 @@ void SkipQuotes(std::string &Value) {
else
esyslog("ERROR: text2skin: missing closing %c", quote);
}
+
+std::string FitToWidth(std::string &Line, uint Width)
+{
+ std::string buf(Line);
+ if (buf.size() > Width) {
+ buf.erase(Width - 3);
+ buf.append("...");
+ }
+ return buf;
+}
+
+std::string FitToWidth(std::stringstream &Line, uint Width)
+{
+ std::string buf(Line.str());
+ if (buf.size() > Width) {
+ buf.erase(Width - 3);
+ buf.append("...");
+ }
+ return buf;
+}
+
+std::string StripXmlTag(std::string &Line, const char *Tag)
+{
+ // set the search strings
+ std::stringstream strStart, strStop;
+ strStart << "<" << Tag << ">";
+ strStop << "</" << Tag << ">";
+ // find the strings
+ std::string::size_type locStart = Line.find(strStart.str());
+ std::string::size_type locStop = Line.find(strStop.str());
+ if (locStart == std::string::npos || locStop == std::string::npos)
+ return "";
+ // extract relevant text
+ int pos = locStart + strStart.str().size();
+ int len = locStop - pos;
+ return len < 0 ? "" : Line.substr(pos, len);
+}