diff -ruNp vdr-1.6.0-2/channels.c vdr-1.6.0-2-extensions/channels.c --- vdr-1.6.0-2/channels.c 2008-03-05 17:42:50.000000000 +0100 +++ vdr-1.6.0-2-extensions/channels.c 2009-04-09 20:48:26.000000000 +0200 @@ -13,6 +13,9 @@ #include "device.h" #include "epg.h" #include "timers.h" +#ifdef USE_STREAMDEVEXT +#include "status.h" +#endif /* STREAMDEVEXT */ // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' // format characters in order to allow any number of blanks after a numeric @@ -51,6 +54,9 @@ const tChannelParameterMap CoderateValue const tChannelParameterMap ModulationValues[] = { { 0, QPSK }, +#ifdef USE_ATSC + { 8, VSB_8 }, +#endif /* ATSC */ { 16, QAM_16 }, { 32, QAM_32 }, { 64, QAM_64 }, @@ -166,6 +172,9 @@ cChannel::cChannel(void) shortName = strdup(""); provider = strdup(""); portalName = strdup(""); +#ifdef USE_PLUGINPARAM + pluginParam = strdup(""); +#endif /* PLUGINPARAM */ memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__); inversion = INVERSION_AUTO; bandwidth = BANDWIDTH_AUTO; @@ -187,6 +196,9 @@ cChannel::cChannel(const cChannel &Chann shortName = NULL; provider = NULL; portalName = NULL; +#ifdef USE_PLUGINPARAM + pluginParam = NULL; +#endif /* PLUGINPARAM */ schedule = NULL; linkChannels = NULL; refChannel = NULL; @@ -215,6 +227,9 @@ cChannel::~cChannel() free(shortName); free(provider); free(portalName); +#ifdef USE_PLUGINPARAM + free(pluginParam); +#endif /* PLUGINPARAM */ } cChannel& cChannel::operator= (const cChannel &Channel) @@ -223,6 +238,9 @@ cChannel& cChannel::operator= (const cCh shortName = strcpyrealloc(shortName, Channel.shortName); provider = strcpyrealloc(provider, Channel.provider); portalName = strcpyrealloc(portalName, Channel.portalName); +#ifdef USE_PLUGINPARAM + pluginParam = strcpyrealloc(pluginParam, Channel.pluginParam); +#endif /* PLUGINPARAM */ memcpy(&__BeginData__, &Channel.__BeginData__, (char *)&Channel.__EndData__ - (char *)&Channel.__BeginData__); return *this; } @@ -280,9 +298,30 @@ void cChannel::CopyTransponderData(const transmission = Channel->transmission; guard = Channel->guard; hierarchy = Channel->hierarchy; +#ifdef USE_PLUGINPARAM + if (IsPlug()) pluginParam = strcpyrealloc(pluginParam, Channel->pluginParam); +#endif /* PLUGINPARAM */ } } +#ifdef USE_PLUGINPARAM +bool cChannel::SetPlugTransponderData(int Source, int Frequency, const char *PluginParam) +{ + if (source != Source || frequency != Frequency || (strcmp(pluginParam, PluginParam) != 0)) { + if (Number()) { + dsyslog("changing transponder data of channel %d from %s:%d:%s to %s:%d:%s", Number(), *cSource::ToString(source), frequency, pluginParam, *cSource::ToString(Source), Frequency, PluginParam); + modification |= CHANNELMOD_TRANSP; + Channels.SetModified(); + } + source = Source; + frequency = Frequency; + pluginParam = strcpyrealloc(pluginParam, PluginParam); + schedule = NULL; + } + return true; +} +#endif /* PLUGINPARAM */ + bool cChannel::SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH) { // Workarounds for broadcaster stupidity: @@ -382,6 +421,9 @@ void cChannel::SetName(const char *Name, if (nn || ns || np) { if (Number()) { dsyslog("changing name of channel %d from '%s,%s;%s' to '%s,%s;%s'", Number(), name, shortName, provider, Name, ShortName, Provider); +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(this, scMod); +#endif /* STREAMDEVEXT */ modification |= CHANNELMOD_NAME; Channels.SetModified(); } @@ -407,6 +449,20 @@ void cChannel::SetPortalName(const char } } +#ifdef USE_PLUGINPARAM +void cChannel::SetPluginParam(const char *PluginParam) +{ + if (!isempty(PluginParam) && strcmp(pluginParam, PluginParam) != 0) { + if (Number()) { + dsyslog("changing plugin parameters of channel %d from '%s' to '%s'", Number(), pluginParam, PluginParam); + modification |= CHANNELMOD_TRANSP; + Channels.SetModified(); + } + pluginParam = strcpyrealloc(pluginParam, PluginParam); + } +} +#endif /* PLUGINPARAM */ + #define STRDIFF 0x01 #define VALDIFF 0x02 @@ -593,7 +649,11 @@ cString cChannel::ParametersToString(voi if (isdigit(type)) type = 'S'; #define ST(s) if (strchr(s, type)) +#ifdef USE_PLUGINPARAM + char buffer[256]; +#else char buffer[64]; +#endif /* PLUGINPARAM */ char *q = buffer; *q = 0; ST(" S ") q += sprintf(q, "%c", polarization); @@ -605,6 +665,9 @@ cString cChannel::ParametersToString(voi ST(" T") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues)); ST(" T") q += PrintParameter(q, 'G', MapToUser(guard, GuardValues)); ST(" T") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues)); +#ifdef USE_PLUGINPARAM + ST("P ") snprintf(buffer, sizeof(buffer), "%s", pluginParam); +#endif /* PLUGINPARAM */ return buffer; } @@ -626,7 +689,11 @@ static const char *ParseParameter(const bool cChannel::StringToParameters(const char *s) { +#ifdef USE_PLUGINPARAM + while (s && *s && !IsPlug()) { +#else while (s && *s) { +#endif /* PLUGINPARAM */ switch (toupper(*s)) { case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break; case 'C': s = ParseParameter(s, coderateH, CoderateValues); break; @@ -736,7 +803,11 @@ bool cChannel::Parse(const char *s) dpids[0] = 0; ok = false; if (parambuf && sourcebuf && vpidbuf && apidbuf) { +#ifdef USE_PLUGINPARAM + ok = ((source = cSource::FromString(sourcebuf)) >= 0) && StringToParameters(parambuf); +#else ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0; +#endif /* PLUGINPARAM */ char *p = strchr(vpidbuf, '+'); if (p) @@ -827,6 +898,9 @@ bool cChannel::Parse(const char *s) shortName = strcpyrealloc(shortName, p); } name = strcpyrealloc(name, namebuf); +#ifdef USE_PLUGINPARAM + if (IsPlug()) pluginParam = strcpyrealloc(pluginParam, parambuf); +#endif /* PLUGINPARAM */ free(parambuf); free(sourcebuf); @@ -1072,6 +1146,9 @@ cChannel *cChannels::NewChannel(const cC NewChannel->SetName(Name, ShortName, Provider); Add(NewChannel); ReNumber(); +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(NewChannel, scAdd); +#endif /* STREAMDEVEXT */ return NewChannel; } return NULL; diff -ruNp vdr-1.6.0-2/channels.h vdr-1.6.0-2-extensions/channels.h --- vdr-1.6.0-2/channels.h 2008-02-08 14:48:31.000000000 +0100 +++ vdr-1.6.0-2-extensions/channels.h 2009-04-09 20:48:26.000000000 +0200 @@ -114,6 +114,9 @@ private: char *shortName; char *provider; char *portalName; +#ifdef USE_PLUGINPARAM + char *pluginParam; +#endif /* PLUGINPARAM */ int __BeginData__; int frequency; // MHz int source; @@ -165,6 +168,9 @@ public: int Frequency(void) const { return frequency; } ///< Returns the actual frequency, as given in 'channels.conf' int Transponder(void) const; ///< Returns the transponder frequency in MHz, plus the polarization in case of sat static int Transponder(int Frequency, char Polarization); ///< builds the transponder from the given Frequency and Polarization +#ifdef USE_PLUGINPARAM + const char *PluginParam(void) const { return pluginParam; } +#endif /* PLUGINPARAM */ int Source(void) const { return source; } int Srate(void) const { return srate; } int Vpid(void) const { return vpid; } @@ -199,6 +205,9 @@ public: int Hierarchy(void) const { return hierarchy; } const cLinkChannels* LinkChannels(void) const { return linkChannels; } const cChannel *RefChannel(void) const { return refChannel; } +#ifdef USE_PLUGINPARAM + bool IsPlug(void) const { return cSource::IsPlug(source); } +#endif /* PLUGINPARAM */ bool IsCable(void) const { return cSource::IsCable(source); } bool IsSat(void) const { return cSource::IsSat(source); } bool IsTerr(void) const { return cSource::IsTerr(source); } @@ -206,12 +215,18 @@ public: bool HasTimer(void) const; int Modification(int Mask = CHANNELMOD_ALL); void CopyTransponderData(const cChannel *Channel); +#ifdef USE_PLUGINPARAM + bool SetPlugTransponderData(int Source, int Frequency, const char *PluginParam); +#endif /* PLUGINPARAM */ bool SetSatTransponderData(int Source, int Frequency, char Polarization, int Srate, int CoderateH); bool SetCableTransponderData(int Source, int Frequency, int Modulation, int Srate, int CoderateH); bool SetTerrTransponderData(int Source, int Frequency, int Bandwidth, int Modulation, int Hierarchy, int CodeRateH, int CodeRateL, int Guard, int Transmission); void SetId(int Nid, int Tid, int Sid, int Rid = 0); void SetName(const char *Name, const char *ShortName, const char *Provider); void SetPortalName(const char *PortalName); +#ifdef USE_PLUGINPARAM + void SetPluginParam(const char *PluginParam); +#endif /* PLUGINPARAM */ void SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid); void SetCaIds(const int *CaIds); // list must be zero-terminated void SetCaDescriptors(int Level); diff -ruNp vdr-1.6.0-2/config.c vdr-1.6.0-2-extensions/config.c --- vdr-1.6.0-2/config.c 2008-02-17 14:39:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/config.c 2009-04-09 20:48:26.000000000 +0200 @@ -15,6 +15,9 @@ #include "interface.h" #include "plugin.h" #include "recording.h" +#ifdef USE_SOURCECAPS +#include "sources.h" +#endif /* SOURCECAPS */ // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' // format characters in order to allow any number of blanks after a numeric @@ -28,18 +31,32 @@ cCommand::cCommand(void) { title = command = NULL; confirm = false; +#ifdef USE_CMDSUBMENU + nIndent = 0; + childs = NULL; +#endif /* CMDSUBMENU */ } cCommand::~cCommand() { free(title); free(command); +#ifdef USE_CMDSUBMENU + delete childs; +#endif /* CMDSUBMENU */ } bool cCommand::Parse(const char *s) { const char *p = strchr(s, ':'); if (p) { +#ifdef USE_CMDSUBMENU + nIndent = 0; + while (*s == '-') { + nIndent++; + s++; + } +#endif /* CMDSUBMENU */ int l = p - s; if (l > 0) { title = MALLOC(char, l + 1); @@ -85,6 +102,20 @@ const char *cCommand::Execute(const char return result; } +#ifdef USE_CMDSUBMENU +int cCommand::getChildCount(void) +{ + return childs ? childs->Count() : 0; +} + +void cCommand::addChild(cCommand *newChild) +{ + if (!childs) + childs = new cCommands(); + childs->AddConfig(newChild); +} +#endif /* CMDSUBMENU */ + // --- cSVDRPhost ------------------------------------------------------------ cSVDRPhost::cSVDRPhost(void) @@ -125,6 +156,26 @@ bool cSVDRPhost::Accepts(in_addr_t Addre cCommands Commands; cCommands RecordingCommands; +#ifdef USE_TIMERCMD +cCommands TimerCommands; +#endif /* TIMERCMD */ + +#ifdef USE_CMDSUBMENU +void cCommands::AddConfig(cCommand *Object) +{ + if (!Object) + return; + //isyslog ("Indent %d %s\n", Object->getIndent(), Object->Title()); + for (int index = Count() - 1; index >= 0; index--) { + cCommand *parent = Get(index); + if (parent->getIndent() < Object->getIndent()) { + parent->addChild(Object); + return; + } + } + cConfig::Add(Object); +} +#endif /* CMDSUBMENU */ // --- cSVDRPhosts ----------------------------------------------------------- @@ -216,6 +267,12 @@ cSetup::cSetup(void) strcpy(OSDLanguage, ""); // default is taken from environment strcpy(OSDSkin, "sttng"); strcpy(OSDTheme, "default"); +#ifdef USE_WAREAGLEICON + WarEagleIcons = 1; +#endif /* WAREAGLEICON */ +#ifdef USE_VALIDINPUT + ShowValidInput = 0; +#endif /* VALIDINPUT */ PrimaryDVB = 1; ShowInfoOnChSwitch = 1; TimeoutRequChInfo = 1; @@ -260,6 +317,18 @@ cSetup::cSetup(void) VideoFormat = 0; UpdateChannels = 5; UseDolbyDigital = 1; +#ifdef USE_DOLBYINREC + UseDolbyInRecordings = 1; +#endif /* DOLBYINREC */ +#ifdef USE_DVBSETUP + DolbyTransferFix = 1; + ChannelBlocker = 0; + ChannelBlockerMode = 0; + ChannelBlockerList = strdup(""); +#endif /* DVBSETUP */ +#ifdef USE_SYNCEARLY + UseSyncEarlyPatch = 0; +#endif /* SYNCEARLY */ ChannelInfoPos = 0; ChannelInfoTime = 5; OSDLeft = 54; @@ -276,24 +345,143 @@ cSetup::cSetup(void) FontSmlSize = 18; FontFixSize = 20; MaxVideoFileSize = MAXVIDEOFILESIZE; +#ifdef USE_HARDLINKCUTTER + MaxRecordingSize = DEFAULTRECORDINGSIZE; +#endif /* HARDLINKCUTTER */ SplitEditedFiles = 0; +#ifdef USE_HARDLINKCUTTER + HardLinkCutter = 0; +#endif /* HARDLINKCUTTER */ +#ifdef USE_DELTIMESHIFTREC + DelTimeshiftRec = 0; +#endif /* DELTIMESHIFTREC */ MinEventTimeout = 30; MinUserInactivity = 300; NextWakeupTime = 0; MultiSpeedMode = 0; ShowReplayMode = 0; +#ifdef USE_DDEPGENTRY + DoubleEpgTimeDelta = 15; + DoubleEpgAction = 0; + MixEpgAction = 0; + DisableVPS = 0; +#endif /* DDEPGENTRY */ ResumeID = 0; +#ifdef USE_JUMPPLAY + JumpPlay = 0; + PlayJump = 0; + PauseLastMark = 0; + ReloadMarks = 0; +#endif /* JUMPPLAY */ +#ifdef USE_SOURCECAPS + memset(SourceCaps, 0, sizeof SourceCaps); + SourceCapsSet = false; +#endif /* SOURCECAPS */ CurrentChannel = -1; CurrentVolume = MAXVOLUME; CurrentDolby = 0; InitialChannel = 0; InitialVolume = -1; +#ifdef USE_VOLCTRL + LRVolumeControl = 0; + LRChannelGroups = 1; + LRForwardRewind = 1; +#endif /* VOLCTRL */ EmergencyExit = 1; +#ifdef USE_NOEPG + noEPGMode = 0; + noEPGList = strdup(""); +#endif /* NOEPG */ +#ifdef USE_LIRCSETTINGS + LircRepeatDelay = 350; + LircRepeatFreq = 100; + LircRepeatTimeout = 500; +#endif /* LIRCSETTINGS */ +#ifdef USE_LIEMIEXT + ShowRecDate = 1; + ShowRecTime = 1; + ShowRecLength = 0; + ShowProgressBar = 0; + MenuCmdPosition = 0; + JumpSeconds = 60; + JumpSecondsSlow = 10; + ShowTimerStop = 1; + MainMenuTitle = 0; + strcpy(CustomMainMenuTitle, "Video Disk Recorder"); +#endif /* LIEMIEXT */ +#ifdef USE_SORTRECORDS + RecordingsSortMode = 0; + RecordingsSortDirsFirst = 0; +#endif /* SORTRECORDS */ +#ifdef USE_CUTTERQUEUE + CutterAutoDelete = 0; +#endif /* CUTTERQUEUE */ +#ifdef USE_CUTTIME + CutTime = 1; +#endif /* CUTTIME */ +#ifdef USE_LIVEBUFFER + LiveBuffer = false; + KeepPaused = false; + LiveBufferSize = 100; + InRAM = false; + MemBufSize = 5; + ExtendBuffer = false; +#endif /* LIVEBUFFER */ +#ifdef USE_DVDARCHIVE + DvdDisplayMode = 1; + DvdDisplayZeros = 1; + DvdTrayMode = 0; + DvdSpeedLimit = 0; +#endif /* DVDARCHIVE */ +#ifdef USE_SOFTOSD + UseSoftOsd = 0; + SoftOsdRate = 50; + SoftOsdFadeinSteps = 6; + SoftOsdFadeoutSteps = 16; + SoftOsdPaletteOnly = 0; +#endif /* SOFTOSD */ +#ifdef USE_LNBSHARE + VerboseLNBlog = 0; + for (int i = 0; i < MAXDEVICES; i++) CardUsesLNBnr[i] = i + 1; +#endif /* LNBSHARE */ +#ifdef USE_DVLVIDPREFER + UseVidPrefer = 0; // default = disabled + nVidPrefer = 1; + for (int zz = 1; zz < DVLVIDPREFER_MAX; zz++) { + VidPreferPrio[ zz ] = 50; + VidPreferSize[ zz ] = 100; + } + VidPreferSize[ 0 ] = 800; + VidPreferPrio[ 0 ] = 50; +#endif /* DVLVIDPREFER */ +#ifdef USE_DVLFRIENDLYFNAMES + UseFriendlyFNames = 0; // default = disabled +#endif /* DVLFRIENDLYFNAMES */ +} + +#if defined (USE_DVBSETUP) || defined (USE_NOEPG) +cSetup::~cSetup() +{ +#ifdef USE_DVBSETUP + free(ChannelBlockerList); +#endif /* DVBSETUP */ +#ifdef USE_NOEPG + free(noEPGList); +#endif /* NOEPG */ } +#endif /* DVBSETUP + NOEPG */ cSetup& cSetup::operator= (const cSetup &s) { memcpy(&__BeginData__, &s.__BeginData__, (char *)&s.__EndData__ - (char *)&s.__BeginData__); +#ifdef USE_DVBSETUP + free(ChannelBlockerList); + ChannelBlockerList = strdup(s.ChannelBlockerList); +#endif /* DVBSETUP */ +#ifdef USE_NOEPG + free(noEPGList); + noEPGList = strdup(s.noEPGList); +#endif /* NOEPG */ return *this; } @@ -384,11 +572,62 @@ bool cSetup::ParseLanguages(const char * return true; } +#ifdef USE_SOURCECAPS +void cSetup::StoreSourceCaps(const char *Name) +{ + cSetupLine *l; + while ((l = Get(Name)) != NULL) + Del(l); + + for (int i = 0; i < MAXDEVICES; i++) { + char buffer[MAXSOURCECAPS*8]={0,}, *q = buffer; + int j = 0; + while (SourceCaps[i][j] && j < MAXSOURCECAPS) { + if (j==0) + q += snprintf(buffer, sizeof(buffer), "%i ", i+1); + q += snprintf(q, sizeof(buffer) - (q-buffer), "%s ", *cSource::ToString(SourceCaps[i][j++])); + } + if (*buffer) + Store(Name, buffer, NULL, true); + } +} + +bool cSetup::ParseSourceCaps(const char *Value) +{ + char *p; + int d = strtol(Value, &p, 10)-1, i = 0; + while (p < Value+strlen(Value)) { + if (*p==0) return true; + if (isblank(*p)) ++p; + if (isalpha(*p)) { + int source = cSource::FromString(p); + if (source != cSource::stNone) { + SourceCaps[d][i++] = source; + SourceCapsSet = true; + } + else + return false; + while (!isblank(*p) && *p) + ++p; + if (i>MAXSOURCECAPS) + return false; + } + } + return true; +} +#endif /* SOURCECAPS */ + bool cSetup::Parse(const char *Name, const char *Value) { if (!strcasecmp(Name, "OSDLanguage")) { strn0cpy(OSDLanguage, Value, sizeof(OSDLanguage)); I18nSetLocale(OSDLanguage); } else if (!strcasecmp(Name, "OSDSkin")) Utf8Strn0Cpy(OSDSkin, Value, MaxSkinName); else if (!strcasecmp(Name, "OSDTheme")) Utf8Strn0Cpy(OSDTheme, Value, MaxThemeName); +#ifdef USE_WAREAGLEICON + else if (!strcasecmp(Name, "WarEagleIcons")) WarEagleIcons = atoi(Value); +#endif /* WAREAGLEICON */ +#ifdef USE_VALIDINPUT + else if (!strcasecmp(Name, "ShowValidInput")) ShowValidInput = atoi(Value); +#endif /* VALIDINPUT */ else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value); else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value); else if (!strcasecmp(Name, "TimeoutRequChInfo")) TimeoutRequChInfo = atoi(Value); @@ -433,6 +672,21 @@ bool cSetup::Parse(const char *Name, con else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value); else if (!strcasecmp(Name, "UpdateChannels")) UpdateChannels = atoi(Value); else if (!strcasecmp(Name, "UseDolbyDigital")) UseDolbyDigital = atoi(Value); +#ifdef USE_DOLBYINREC + else if (!strcasecmp(Name, "UseDolbyInRecordings")) UseDolbyInRecordings = atoi(Value); +#endif /* DOLBYINREC */ +#ifdef USE_DVBSETUP + else if (!strcasecmp(Name, "DolbyTransferFix")) DolbyTransferFix = atoi(Value); + else if (!strcasecmp(Name, "ChannelBlocker")) ChannelBlocker = atoi(Value); + else if (!strcasecmp(Name, "ChannelBlockerMode")) ChannelBlockerMode = atoi(Value); + else if (!strcasecmp(Name, "ChannelBlockerList")) { + free(ChannelBlockerList); + ChannelBlockerList = strdup(Value ? Value : ""); + } +#endif /* DVBSETUP */ +#ifdef USE_SYNCEARLY + else if (!strcasecmp(Name, "UseSyncEarlyPatch")) UseSyncEarlyPatch = atoi(Value); +#endif /* SYNCEARLY */ else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value); else if (!strcasecmp(Name, "ChannelInfoTime")) ChannelInfoTime = atoi(Value); else if (!strcasecmp(Name, "OSDLeft")) OSDLeft = atoi(Value); @@ -449,21 +703,152 @@ bool cSetup::Parse(const char *Name, con else if (!strcasecmp(Name, "FontSmlSize")) FontSmlSize = atoi(Value); else if (!strcasecmp(Name, "FontFixSize")) FontFixSize = atoi(Value); else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value); +#ifdef USE_HARDLINKCUTTER + else if (!strcasecmp(Name, "MaxRecordingSize")) MaxRecordingSize = atoi(Value); +#endif /* HARDLINKCUTTER */ else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); +#ifdef USE_HARDLINKCUTTER + else if (!strcasecmp(Name, "HardLinkCutter")) HardLinkCutter = atoi(Value); +#endif /* HARDLINKCUTTER */ +#ifdef USE_DELTIMESHIFTREC + else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value); +#endif /* DELTIMESHIFTREC */ else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); else if (!strcasecmp(Name, "NextWakeupTime")) NextWakeupTime = atoi(Value); else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); +#ifdef USE_DDEPGENTRY + else if (!strcasecmp(Name, "DoubleEpgTimeDelta")) DoubleEpgTimeDelta = atoi(Value); + else if (!strcasecmp(Name, "DoubleEpgAction")) DoubleEpgAction = atoi(Value); + else if (!strcasecmp(Name, "MixEpgAction")) MixEpgAction = atoi(Value); + else if (!strcasecmp(Name, "DisableVPS")) DisableVPS = atoi(Value); +#endif /* DDEPGENTRY */ else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value); +#ifdef USE_JUMPPLAY + else if (!strcasecmp(Name, "JumpPlay")) JumpPlay = atoi(Value); + else if (!strcasecmp(Name, "PlayJump")) PlayJump = atoi(Value); + else if (!strcasecmp(Name, "PauseLastMark")) PauseLastMark = atoi(Value); + else if (!strcasecmp(Name, "ReloadMarks")) ReloadMarks = atoi(Value); +#endif /* JUMPPLAY */ +#ifdef USE_SOURCECAPS + else if (!strcasecmp(Name, "SourceCaps")) return ParseSourceCaps(Value); +#endif /* SOURCECAPS */ else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); else if (!strcasecmp(Name, "CurrentDolby")) CurrentDolby = atoi(Value); else if (!strcasecmp(Name, "InitialChannel")) InitialChannel = atoi(Value); else if (!strcasecmp(Name, "InitialVolume")) InitialVolume = atoi(Value); +#ifdef USE_VOLCTRL + else if (!strcasecmp(Name, "LRVolumeControl")) LRVolumeControl = atoi(Value); + else if (!strcasecmp(Name, "LRChannelGroups")) LRChannelGroups = atoi(Value); + else if (!strcasecmp(Name, "LRForwardRewind")) LRForwardRewind = atoi(Value); +#endif /* VOLCTRL */ else if (!strcasecmp(Name, "EmergencyExit")) EmergencyExit = atoi(Value); +#ifdef USE_NOEPG + else if (!strcasecmp(Name, "noEPGMode")) noEPGMode = atoi(Value); + else if (!strcasecmp(Name, "noEPGList")) { + free(noEPGList); + noEPGList = strdup(Value ? Value : ""); + } +#endif /* NOEPG */ +#ifdef USE_LIRCSETTINGS + else if (!strcasecmp(Name, "LircRepeatDelay")) LircRepeatDelay = atoi(Value); + else if (!strcasecmp(Name, "LircRepeatFreq")) LircRepeatFreq = atoi(Value); + else if (!strcasecmp(Name, "LircRepeatTimeout")) LircRepeatTimeout = atoi(Value); +#endif /* LIRCSETTINGS */ +#ifdef USE_LIEMIEXT + else if (!strcasecmp(Name, "ShowRecDate")) ShowRecDate = atoi(Value); + else if (!strcasecmp(Name, "ShowRecTime")) ShowRecTime = atoi(Value); + else if (!strcasecmp(Name, "ShowRecLength")) ShowRecLength = atoi(Value); + else if (!strcasecmp(Name, "ShowProgressBar")) ShowProgressBar = atoi(Value); + else if (!strcasecmp(Name, "MenuCmdPosition")) MenuCmdPosition = atoi(Value); + else if (!strcasecmp(Name, "JumpSeconds")) JumpSeconds = atoi(Value); + else if (!strcasecmp(Name, "JumpSecondsSlow")) JumpSecondsSlow = atoi(Value); + else if (!strcasecmp(Name, "ShowTimerStop")) ShowTimerStop = atoi(Value); + else if (!strcasecmp(Name, "MainMenuTitle")) MainMenuTitle = atoi(Value); + else if (!strcasecmp(Name, "CustomMainMenuTitle")) Utf8Strn0Cpy(CustomMainMenuTitle, Value, MaxTitleName); +#endif /* LIEMIEXT */ +#ifdef USE_SORTRECORDS + else if (!strcasecmp(Name, "RecordingsSortMode")) RecordingsSortMode = atoi(Value); + else if (!strcasecmp(Name, "RecordingsSortDirsFirst")) RecordingsSortDirsFirst = atoi(Value); +#endif /* SORTRECORDS */ +#ifdef USE_CUTTERQUEUE + else if (!strcasecmp(Name, "CutterAutoDelete")) CutterAutoDelete = atoi(Value); +#endif /* CUTTERQUEUE */ +#ifdef USE_CUTTIME + else if (!strcasecmp(Name, "CutTime")) CutTime = atoi(Value); +#endif /* CUTTIME */ +#ifdef USE_LIVEBUFFER + else if (!strcasecmp(Name, "LiveBuffer")) LiveBuffer = atoi(Value); + else if (!strcasecmp(Name, "KeepPaused")) KeepPaused = atoi(Value); + else if (!strcasecmp(Name, "LiveBufferSize")) LiveBufferSize = atoi(Value); + else if (!strcasecmp(Name, "InRAM")) InRAM = atoi(Value); + else if (!strcasecmp(Name, "MemBufSize")) MemBufSize = atoi(Value); + else if (!strcasecmp(Name, "ExtendBuffer")) ExtendBuffer = atoi(Value); +#endif /* LIVEBUFFER */ +#ifdef USE_DVDARCHIVE + else if (!strcasecmp(Name, "DvdDisplayMode")) DvdDisplayMode = atoi(Value); + else if (!strcasecmp(Name, "DvdDisplayZeros")) DvdDisplayZeros = atoi(Value); + else if (!strcasecmp(Name, "DvdTrayMode")) DvdTrayMode = atoi(Value); + else if (!strcasecmp(Name, "DvdSpeedLimit")) DvdSpeedLimit = atoi(Value); +#endif /* DVDARCHIVE */ +#ifdef USE_SOFTOSD + else if (!strcasecmp(Name, "UseSoftOsd")) UseSoftOsd = atoi(Value); + else if (!strcasecmp(Name, "SoftOsdRate")) SoftOsdRate = atoi(Value); + else if (!strcasecmp(Name, "SoftOsdFadeinSteps")) SoftOsdFadeinSteps = atoi(Value); + else if (!strcasecmp(Name, "SoftOsdFadeoutSteps")) SoftOsdFadeoutSteps = atoi(Value); + else if (!strcasecmp(Name, "SoftOsdPaletteOnly")) SoftOsdPaletteOnly = atoi(Value); +#endif /* SOFTOSD */ +#ifdef USE_DVLVIDPREFER + else if (strcasecmp(Name, "UseVidPrefer") == 0) UseVidPrefer = atoi(Value); + else if (strcasecmp(Name, "nVidPrefer") == 0) nVidPrefer = atoi(Value); + else if (strstr(Name, "VidPrefer") == Name) { + char *x = (char *)&Name[ strlen(Name) - 1 ]; + int vN; + + if (isdigit(*x) != 0) { + while (isdigit(*x) != 0) + x--; + x++; + } + + vN = atoi(x); + if (vN < DVLVIDPREFER_MAX) { + if (strstr(Name, "VidPreferPrio") == Name) { + VidPreferPrio[ vN ] = atoi(Value); + if (VidPreferPrio[ vN ] > 99) + VidPreferPrio[ vN ] = 99; + } + else if (strstr(Name, "VidPreferSize") == Name) { + VidPreferSize[ vN ] = atoi(Value); + } + else + return false; + } + } +#endif /* DVLVIDPREFER */ +#ifdef USE_DVLFRIENDLYFNAMES + else if (strcasecmp(Name, "UseFriendlyFNames") == 0) UseFriendlyFNames = atoi(Value); +#endif /* DVLFRIENDLYFNAMES */ else +#ifdef USE_LNBSHARE + if (!strcasecmp(Name, "VerboseLNBlog")) VerboseLNBlog = atoi(Value); + else { + char tmp[20]; + bool result = false; + for (int i = 1; i <= MAXDEVICES; i++) { + sprintf(tmp, "Card%dusesLNBnr", i); + if (!strcasecmp(Name, tmp)) { + CardUsesLNBnr[i - 1] = atoi(Value); + result = true; + } + } + return result; + } +#else return false; +#endif /* LNBSHARE */ return true; } @@ -472,6 +857,12 @@ bool cSetup::Save(void) Store("OSDLanguage", OSDLanguage); Store("OSDSkin", OSDSkin); Store("OSDTheme", OSDTheme); +#ifdef USE_WAREAGLEICON + Store("WarEagleIcons", WarEagleIcons); +#endif /* WAREAGLEICON */ +#ifdef USE_VALIDINPUT + Store("ShowValidInput", ShowValidInput); +#endif /* VALIDINPUT */ Store("PrimaryDVB", PrimaryDVB); Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch); Store("TimeoutRequChInfo", TimeoutRequChInfo); @@ -516,6 +907,18 @@ bool cSetup::Save(void) Store("VideoFormat", VideoFormat); Store("UpdateChannels", UpdateChannels); Store("UseDolbyDigital", UseDolbyDigital); +#ifdef USE_DOLBYINREC + Store("UseDolbyInRecordings", UseDolbyInRecordings); +#endif /* DOLBYINREC */ +#ifdef USE_DVBSETUP + Store("DolbyTransferFix", DolbyTransferFix); + Store("ChannelBlocker", ChannelBlocker); + Store("ChannelBlockerMode", ChannelBlockerMode); + Store("ChannelBlockerList", ChannelBlockerList); +#endif /* DVBSETUP */ +#ifdef USE_SYNCEARLY + Store("UseSyncEarlyPatch", UseSyncEarlyPatch); +#endif /* SYNCEARLY */ Store("ChannelInfoPos", ChannelInfoPos); Store("ChannelInfoTime", ChannelInfoTime); Store("OSDLeft", OSDLeft); @@ -532,25 +935,164 @@ bool cSetup::Save(void) Store("FontSmlSize", FontSmlSize); Store("FontFixSize", FontFixSize); Store("MaxVideoFileSize", MaxVideoFileSize); +#ifdef USE_HARDLINKCUTTER + Store("MaxRecordingSize", MaxRecordingSize); +#endif /* HARDLINKCUTTER */ Store("SplitEditedFiles", SplitEditedFiles); +#ifdef USE_HARDLINKCUTTER + Store("HardLinkCutter", HardLinkCutter); +#endif /* HARDLINKCUTTER */ +#ifdef USE_DELTIMESHIFTREC + Store("DelTimeshiftRec", DelTimeshiftRec); +#endif /* DELTIMESHIFTREC */ Store("MinEventTimeout", MinEventTimeout); Store("MinUserInactivity", MinUserInactivity); Store("NextWakeupTime", NextWakeupTime); +#ifdef USE_DDEPGENTRY + Store("DoubleEpgAction", DoubleEpgAction); + Store("MixEpgAction", MixEpgAction); + Store("DisableVPS", DisableVPS); + Store("DoubleEpgTimeDelta", DoubleEpgTimeDelta); +#endif /* DDEPGENTRY */ Store("MultiSpeedMode", MultiSpeedMode); Store("ShowReplayMode", ShowReplayMode); Store("ResumeID", ResumeID); +#ifdef USE_JUMPPLAY + Store("JumpPlay", JumpPlay); + Store("PlayJump", PlayJump); + Store("PauseLastMark", PauseLastMark); + Store("ReloadMarks", ReloadMarks); +#endif /* JUMPPLAY */ +#ifdef USE_SOURCECAPS + if (SourceCapsSet) StoreSourceCaps("SourceCaps"); +#endif /* SOURCECAPS */ Store("CurrentChannel", CurrentChannel); Store("CurrentVolume", CurrentVolume); Store("CurrentDolby", CurrentDolby); Store("InitialChannel", InitialChannel); Store("InitialVolume", InitialVolume); +#ifdef USE_VOLCTRL + Store("LRVolumeControl", LRVolumeControl); + Store("LRChannelGroups", LRChannelGroups); + Store("LRForwardRewind", LRForwardRewind); +#endif /* VOLCTRL */ Store("EmergencyExit", EmergencyExit); +#ifdef USE_NOEPG + Store("noEPGMode", noEPGMode); + Store("noEPGList", noEPGList); +#endif /* NOEPG */ +#ifdef USE_LIRCSETTINGS + Store("LircRepeatDelay", LircRepeatDelay); + Store("LircRepeatFreq", LircRepeatFreq); + Store("LircRepeatTimeout", LircRepeatTimeout); +#endif /* LIRCSETTINGS */ +#ifdef USE_LIEMIEXT + Store("ShowRecDate", ShowRecDate); + Store("ShowRecTime", ShowRecTime); + Store("ShowRecLength", ShowRecLength); + Store("ShowProgressBar", ShowProgressBar); + Store("MenuCmdPosition", MenuCmdPosition); + Store("JumpSeconds", JumpSeconds); + Store("JumpSecondsSlow", JumpSecondsSlow); + Store("ShowTimerStop", ShowTimerStop); + Store("MainMenuTitle", MainMenuTitle); + Store("CustomMainMenuTitle",CustomMainMenuTitle); +#endif /* LIEMIEXT */ +#ifdef USE_SORTRECORDS + Store("RecordingsSortMode", RecordingsSortMode); + Store("RecordingsSortDirsFirst", RecordingsSortDirsFirst); +#endif /* SORTRECORDS */ +#ifdef USE_CUTTERQUEUE + Store("CutterAutoDelete", CutterAutoDelete); +#endif /* CUTTERQUEUE */ +#ifdef USE_CUTTIME + Store("CutTime", CutTime); +#endif /* CUTTIME */ +#ifdef USE_LIVEBUFFER + Store("LiveBuffer", LiveBuffer); + Store("KeepPaused", KeepPaused); + Store("LiveBufferSize", LiveBufferSize); + Store("InRAM", InRAM); + Store("MemBufSize", MemBufSize); + Store("ExtendBuffer", ExtendBuffer); +#endif /* LIVEBUFFER */ +#ifdef USE_DVDARCHIVE + Store("DvdDisplayMode", DvdDisplayMode); + Store("DvdDisplayZeros", DvdDisplayZeros); + Store("DvdTrayMode", DvdTrayMode); + Store("DvdSpeedLimit", DvdSpeedLimit); +#endif /* DVDARCHIVE */ +#ifdef USE_SOFTOSD + Store("UseSoftOsd", UseSoftOsd); + Store("SoftOsdRate", SoftOsdRate); + Store("SoftOsdFadeinSteps", SoftOsdFadeinSteps); + Store("SoftOsdFadeoutSteps", SoftOsdFadeoutSteps); + Store("SoftOsdPaletteOnly", SoftOsdPaletteOnly); +#endif /* SOFTOSD */ +#ifdef USE_LNBSHARE + Store("VerboseLNBlog", VerboseLNBlog); + char tmp[20]; + if (cDevice::NumDevices() > 1) { + for (int i = 1; i <= cDevice::NumDevices(); i++) { + sprintf(tmp, "Card%dusesLNBnr", i); + Store(tmp, CardUsesLNBnr[i - 1]); + } + } +#endif /* LNBSHARE */ +#ifdef USE_DVLVIDPREFER + Store ("UseVidPrefer", UseVidPrefer); + Store ("nVidPrefer", nVidPrefer); + + char vidBuf[32]; + for (int zz = 0; zz < nVidPrefer; zz++) { + sprintf(vidBuf, "VidPreferPrio%d", zz); + Store (vidBuf, VidPreferPrio[zz]); + sprintf(vidBuf, "VidPreferSize%d", zz); + Store (vidBuf, VidPreferSize[zz]); + } +#endif /* DVLVIDPREFER */ +#ifdef USE_DVLFRIENDLYFNAMES + Store ("UseFriendlyFNames", UseFriendlyFNames); +#endif /* DVLFRIENDLYFNAMES */ Sort(); if (cConfig::Save()) { isyslog("saved setup to %s", FileName()); +#ifdef USE_DVDARCHIVE + if (DvdDisplayMode >= 1) ::Recordings.Load(); +#endif /* DVDARCHIVE */ return true; } return false; } + +#ifdef USE_CMDRECCMDI18N +bool LoadCommandsI18n(cCommands & cmds, const char *FileName, bool AllowComments, bool MustExist) +{ + + bool bRet = true; + bool bLoadDefault = (bool)strcmp(Setup.OSDLanguage,"en_US"); + if (bLoadDefault) { + // attempt to load a translated file + char *FullPath = NULL; + asprintf(&FullPath, "%s.%s", FileName, Setup.OSDLanguage); + if (!cmds.Load((FullPath), AllowComments, true)) { + // require to exist, just to be able to log + // fallback + bLoadDefault = false; + esyslog("Failed to load translated '%s' for language (%s)", FullPath, Setup.OSDLanguage); + esyslog("Falling back to default '%s' (if any)", FileName); + } + free(FullPath); + } + if (!bLoadDefault) { + // let's do it the normal way + bRet = cmds.Load(FileName, AllowComments, MustExist); + } + // return status only for the default commands file + return bRet; +} + +#endif /* CMDRECCMDI18N */ + diff -ruNp vdr-1.6.0-2/config.h vdr-1.6.0-2-extensions/config.h --- vdr-1.6.0-2/config.h 2008-09-11 13:29:43.000000000 +0200 +++ vdr-1.6.0-2-extensions/config.h 2009-04-09 20:48:26.000000000 +0200 @@ -36,23 +36,74 @@ // plugins to work with newer versions of the core VDR as long as no // VDR header files have changed. +#define VDREXTENSIONS 70 + +#ifdef USE_JUMPPLAY +#define JUMPPLAYVERSNUM 100 +#endif /* JUMPPLAY */ + +#ifdef USE_LIEMIEXT +#define LIEMIKUUTIO 121 +#define MAXMAINMENUTITLE 4 +#define MaxTitleName 64 +#endif /* LIEMIEXT */ + +#ifdef USE_CMDSUBMENU +#define CMDSUBMENUVERSNUM 7 +#endif /* CMDSUBMENU */ + +#ifdef USE_MAINMENUHOOKS +#define MAINMENUHOOKSVERSNUM 1.0 +#endif /* MAINMENUHOOKS */ + +#ifdef USE_PINPLUGIN +#define PIN_PLUGIN_PATCH 120 +#endif /* PINPLUGIN */ + +#ifdef USE_PLUGINPARAM +#define PLUGINPARAMPATCHVERSNUM 1 +#endif /* PLUGINPARAM */ + #define MAXPRIORITY 99 #define MAXLIFETIME 99 +#ifdef USE_DVLVIDPREFER +#define DVLVIDPREFER_MAX 12 +#endif /* DVLVIDPREFER */ + #define MINOSDWIDTH 480 #define MAXOSDWIDTH 672 #define MINOSDHEIGHT 324 #define MAXOSDHEIGHT 567 +#ifdef USE_SOURCECAPS +#define MAXDEVICES 16 // the maximum number of devices in the system +#define MAXSOURCECAPS 128 // the maximum number of different sources per device +#endif /* SOURCECAPS */ + +#ifdef USE_LNBSHARE +#ifndef MAXDEVICES +#define MAXDEVICES 16 // the maximum number of devices in the system +#endif +#endif /* LNBSHARE */ + #define MaxFileName 256 #define MaxSkinName 16 #define MaxThemeName 16 +#ifdef USE_CMDSUBMENU +class cCommands; +#endif /* CMDSUBMENU */ + class cCommand : public cListObject { private: char *title; char *command; bool confirm; +#ifdef USE_CMDSUBMENU + int nIndent; + cCommands *childs; +#endif /* CMDSUBMENU */ static char *result; public: cCommand(void); @@ -61,6 +112,14 @@ public: const char *Title(void) { return title; } bool Confirm(void) { return confirm; } const char *Execute(const char *Parameters = NULL); +#ifdef USE_CMDSUBMENU + int getIndent(void) { return nIndent; } + void setIndent(int nNewIndent) { nIndent = nNewIndent; } + cCommands *getChilds(void) { return childs; } + int getChildCount(void); + bool hasChilds(void) { return getChildCount() > 0; } + void addChild(cCommand *newChild); +#endif /* CMDSUBMENU */ }; typedef uint32_t in_addr_t; //XXX from /usr/include/netinet/in.h (apparently this is not defined on systems with glibc < 2.2) @@ -88,6 +147,9 @@ private: public: cConfig(void) { fileName = NULL; } virtual ~cConfig() { free(fileName); } +#ifdef USE_CMDSUBMENU + virtual void AddConfig(T *Object) { cList::Add(Object); } +#endif /* CMDSUBMENU */ const char *FileName(void) { return fileName; } bool Load(const char *FileName = NULL, bool AllowComments = false, bool MustExist = false) { @@ -117,7 +179,11 @@ public: if (!isempty(s)) { T *l = new T; if (l->Parse(s)) +#ifdef USE_CMDSUBMENU + AddConfig(l); +#else Add(l); +#endif /* CMDSUBMENU */ else { esyslog("ERROR: error in %s, line %d", fileName, line); delete l; @@ -159,7 +225,14 @@ public: } }; +#ifdef USE_CMDSUBMENU +class cCommands : public cConfig { +public: + virtual void AddConfig(cCommand *Object); + }; +#else class cCommands : public cConfig {}; +#endif /* CMDSUBMENU */ class cSVDRPhosts : public cConfig { public: @@ -168,6 +241,9 @@ public: extern cCommands Commands; extern cCommands RecordingCommands; +#ifdef USE_TIMERCMD +extern cCommands TimerCommands; +#endif /* TIMERCMD */ extern cSVDRPhosts SVDRPhosts; class cSetupLine : public cListObject { @@ -193,6 +269,10 @@ private: void StoreLanguages(const char *Name, int *Values); bool ParseLanguages(const char *Value, int *Values); bool Parse(const char *Name, const char *Value); +#ifdef USE_SOURCECAPS + void StoreSourceCaps(const char *Name); + bool ParseSourceCaps(const char *Value); +#endif /* SOURCECAPS */ cSetupLine *Get(const char *Name, const char *Plugin = NULL); void Store(const char *Name, const char *Value, const char *Plugin = NULL, bool AllowMultiple = false); void Store(const char *Name, int Value, const char *Plugin = NULL); @@ -202,6 +282,12 @@ public: char OSDLanguage[I18N_MAX_LOCALE_LEN]; char OSDSkin[MaxSkinName]; char OSDTheme[MaxThemeName]; +#ifdef USE_WAREAGLEICON + int WarEagleIcons; +#endif /* WAREAGLEICON */ +#ifdef USE_VALIDINPUT + int ShowValidInput; +#endif /* VALIDINPUT */ int PrimaryDVB; int ShowInfoOnChSwitch; int TimeoutRequChInfo; @@ -242,6 +328,17 @@ public: int VideoFormat; int UpdateChannels; int UseDolbyDigital; +#ifdef USE_DOLBYINREC + int UseDolbyInRecordings; +#endif /* DOLBYINREC */ +#ifdef USE_DVBSETUP + int DolbyTransferFix; + int ChannelBlocker; + int ChannelBlockerMode; +#endif /* DVBSETUP */ +#ifdef USE_SYNCEARLY + int UseSyncEarlyPatch; +#endif /* SYNCEARLY */ int ChannelInfoPos; int ChannelInfoTime; int OSDLeft, OSDTop, OSDWidth, OSDHeight; @@ -255,20 +352,119 @@ public: int FontSmlSize; int FontFixSize; int MaxVideoFileSize; +#ifdef USE_HARDLINKCUTTER + int MaxRecordingSize; +#endif /* HARDLINKCUTTER */ int SplitEditedFiles; +#ifdef USE_HARDLINKCUTTER + int HardLinkCutter; +#endif /* HARDLINKCUTTER */ +#ifdef USE_DELTIMESHIFTREC + int DelTimeshiftRec; +#endif /* DELTIMESHIFTREC */ int MinEventTimeout, MinUserInactivity; time_t NextWakeupTime; int MultiSpeedMode; int ShowReplayMode; +#ifdef USE_DDEPGENTRY + int DoubleEpgTimeDelta; + int DoubleEpgAction; + int MixEpgAction; + int DisableVPS; +#endif /* DDEPGENTRY */ int ResumeID; +#ifdef USE_JUMPPLAY + int JumpPlay; + int PlayJump; + int PauseLastMark; + int ReloadMarks; +#endif /* JUMPPLAY */ +#ifdef USE_SOURCECAPS + int SourceCaps[MAXDEVICES][MAXSOURCECAPS]; + bool SourceCapsSet; +#endif /* SOURCECAPS */ int CurrentChannel; int CurrentVolume; int CurrentDolby; int InitialChannel; int InitialVolume; +#ifdef USE_VOLCTRL + int LRVolumeControl; + int LRChannelGroups; + int LRForwardRewind; +#endif /* VOLCTRL */ int EmergencyExit; +#ifdef USE_NOEPG + int noEPGMode; +#endif /* NOEPG */ +#ifdef USE_LIRCSETTINGS + int LircRepeatDelay; + int LircRepeatFreq; + int LircRepeatTimeout; +#endif /* LIRCSETTINGS */ +#ifdef USE_LIEMIEXT + int ShowRecDate, ShowRecTime, ShowRecLength, ShowProgressBar, MenuCmdPosition; + int JumpSeconds; + int JumpSecondsSlow; + int ShowTimerStop; + int MainMenuTitle; + char CustomMainMenuTitle[MaxTitleName]; +#endif /* LIEMIEXT */ +#ifdef USE_SORTRECORDS + int RecordingsSortMode; + int RecordingsSortDirsFirst; +#endif /* SORTRECORDS */ +#ifdef USE_CUTTERQUEUE + int CutterAutoDelete; +#endif /* CUTTERQUEUE */ +#ifdef USE_CUTTIME + int CutTime; +#endif /* CUTTIME */ +#ifdef USE_LIVEBUFFER + int LiveBuffer; + int KeepPaused; + int LiveBufferSize; + int InRAM; + int MemBufSize; + int ExtendBuffer; +#endif /* LIVEBUFFER */ +#ifdef USE_DVDARCHIVE + int DvdDisplayMode; + int DvdDisplayZeros; + int DvdTrayMode; + int DvdSpeedLimit; +#endif /* DVDARCHIVE */ +#ifdef USE_SOFTOSD + int UseSoftOsd; + int SoftOsdRate; + int SoftOsdFadeinSteps; + int SoftOsdFadeoutSteps; + int SoftOsdPaletteOnly; +#endif /* SOFTOSD */ +#ifdef USE_LNBSHARE + int VerboseLNBlog; + int CardUsesLNBnr[MAXDEVICES]; +#endif /* LNBSHARE */ +#ifdef USE_DVLVIDPREFER + int UseVidPrefer; // 0 = VDR's default, 1 = use + int nVidPrefer; + int VidPreferPrio[DVLVIDPREFER_MAX]; + int VidPreferSize[DVLVIDPREFER_MAX]; +#endif /* DVLVIDPREFER */ +#ifdef USE_DVLFRIENDLYFNAMES + int UseFriendlyFNames; +#endif /* DVLFRIENDLYFNAMES */ int __EndData__; +#ifdef USE_DVBSETUP + char *ChannelBlockerList; +#endif /* DVBSETUP */ +#ifdef USE_NOEPG + char *noEPGList; // pointer not to be flat-copied +#endif /* NOEPG */ cSetup(void); +#if defined (USE_DVBSETUP) || defined (USE_NOEPG) + ~cSetup(); +#endif /* DVBSETUP + NOEPG */ cSetup& operator= (const cSetup &s); bool Load(const char *FileName); bool Save(void); @@ -276,4 +472,8 @@ public: extern cSetup Setup; +#ifdef USE_CMDRECCMDI18N +bool LoadCommandsI18n(cCommands & cmds, const char *FileName = NULL, bool AllowComments = false, bool MustExist = false); +#endif /* CMDRECCMDI18N */ + #endif //__CONFIG_H diff -ruNp vdr-1.6.0-2/cutter.c vdr-1.6.0-2-extensions/cutter.c --- vdr-1.6.0-2/cutter.c 2008-01-13 13:22:21.000000000 +0100 +++ vdr-1.6.0-2-extensions/cutter.c 2009-04-09 20:48:26.000000000 +0200 @@ -15,6 +15,19 @@ // --- cCuttingThread -------------------------------------------------------- +#ifdef USE_CUTTERLIMIT +#ifndef CUTTER_MAX_BANDWIDTH +# define CUTTER_MAX_BANDWIDTH MEGABYTE(10) // 10 MB/s +#endif +#ifndef CUTTER_REL_BANDWIDTH +# define CUTTER_REL_BANDWIDTH 75 // % +#endif +#ifndef CUTTER_PRIORITY +# define CUTTER_PRIORITY sched_get_priority_min(SCHED_OTHER) +#endif +#define CUTTER_TIMESLICE 100 // ms +#endif /* CUTTERLIMIT */ + class cCuttingThread : public cThread { private: const char *error; @@ -60,6 +73,22 @@ cCuttingThread::~cCuttingThread() void cCuttingThread::Action(void) { +#ifdef USE_CUTTERLIMIT +#ifdef USE_HARDLINKCUTTER + if (!Setup.HardLinkCutter) +#endif /* HARDLINKCUTTER */ + { + sched_param tmp; + tmp.sched_priority = CUTTER_PRIORITY; + if (!pthread_setschedparam(pthread_self(), SCHED_OTHER, &tmp)) + printf("cCuttingThread::Action: cant set priority\n"); + } + + int bytes = 0; + int __attribute__((unused)) burst_size = CUTTER_MAX_BANDWIDTH * CUTTER_TIMESLICE / 1000; // max bytes/timeslice + cTimeMs __attribute__((unused)) t; +#endif /* CUTTERLIMIT */ + cMark *Mark = fromMarks.First(); if (Mark) { fromFile = fromFileName->Open(); @@ -71,6 +100,9 @@ void cCuttingThread::Action(void) Mark = fromMarks.Next(Mark); int FileSize = 0; int CurrentFileNumber = 0; +#ifdef USE_HARDLINKCUTTER + bool SkipThisSourceFile = false; +#endif /* HARDLINKCUTTER */ int LastIFrame = 0; toMarks.Add(0); toMarks.Save(); @@ -88,12 +120,99 @@ void cCuttingThread::Action(void) // Read one frame: +#ifndef USE_HARDLINKCUTTER if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { if (FileNumber != CurrentFileNumber) { fromFile = fromFileName->SetOffset(FileNumber, FileOffset); fromFile->SetReadAhead(MEGABYTE(20)); CurrentFileNumber = FileNumber; } +#else + if (!fromIndex->Get(Index++, &FileNumber, &FileOffset, &PictureType, &Length)) { + error = "index"; + break; + } + + if (FileNumber != CurrentFileNumber) { + fromFile = fromFileName->SetOffset(FileNumber, FileOffset); + fromFile->SetReadAhead(MEGABYTE(20)); + CurrentFileNumber = FileNumber; + if (SkipThisSourceFile) { + // At end of fast forward: Always skip to next file + toFile = toFileName->NextFile(); + if (!toFile) { + error = "toFile 4"; + break; + } + FileSize = 0; + SkipThisSourceFile = false; + } + + + if (Setup.HardLinkCutter && FileOffset == 0) { + // We are at the beginning of a new source file. + // Do we need to copy the whole file? + + // if !Mark && LastMark, then we're past the last cut-out and continue to next I-frame + // if !Mark && !LastMark, then there's just a cut-in, but no cut-out + // if Mark, then we're between a cut-in and a cut-out + + uchar MarkFileNumber; + int MarkFileOffset; + // Get file number of next cut mark + if (!Mark && !LastMark + || Mark + && fromIndex->Get(Mark->position, &MarkFileNumber, &MarkFileOffset) + && (MarkFileNumber != CurrentFileNumber)) { + // The current source file will be copied completely. + // Start new output file unless we did that already + if (FileSize != 0) { + toFile = toFileName->NextFile(); + if (!toFile) { + error = "toFile 3"; + break; + } + FileSize = 0; + } + + // Safety check that file has zero size + struct stat buf; + if (stat(toFileName->Name(), &buf) == 0) { + if (buf.st_size != 0) { + esyslog("cCuttingThread: File %s exists and has nonzero size", toFileName->Name()); + error = "nonzero file exist"; + break; + } + } + else if (errno != ENOENT) { + esyslog("cCuttingThread: stat failed on %s", toFileName->Name()); + error = "stat"; + break; + } + + // Clean the existing 0-byte file + toFileName->Close(); + cString ActualToFileName(ReadLink(toFileName->Name()), true); + unlink(ActualToFileName); + unlink(toFileName->Name()); + + // Try to create a hard link + if (HardLinkVideoFile(fromFileName->Name(), toFileName->Name())) { + // Success. Skip all data transfer for this file + SkipThisSourceFile = true; + cutIn = false; + toFile = NULL; // was deleted by toFileName->Close() + } + else { + // Fallback: Re-open the file if necessary + toFile = toFileName->Open(); + } + } + } + } + + if (!SkipThisSourceFile) { +#endif /* HARDLINKCUTTER */ if (fromFile) { int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer)); if (len < 0) { @@ -110,6 +229,7 @@ void cCuttingThread::Action(void) break; } } +#ifndef USE_HARDLINKCUTTER else { // Error, unless we're past the last cut-in and there's no cut-out if (Mark || LastMark) @@ -117,12 +237,17 @@ void cCuttingThread::Action(void) break; } +#endif /* HARDLINKCUTTER */ // Write one frame: if (PictureType == I_FRAME) { // every file shall start with an I_FRAME if (LastMark) // edited version shall end before next I-frame break; +#ifndef USE_HARDLINKCUTTER if (FileSize > MEGABYTE(Setup.MaxVideoFileSize)) { +#else + if (!SkipThisSourceFile && FileSize > toFileName->MaxFileSize()) { +#endif /* HARDLINKCUTTER */ toFile = toFileName->NextFile(); if (!toFile) { error = "toFile 1"; @@ -132,12 +257,20 @@ void cCuttingThread::Action(void) } LastIFrame = 0; +#ifndef USE_HARDLINKCUTTER if (cutIn) { +#else + if (!SkipThisSourceFile && cutIn) { +#endif /* HARDLINKCUTTER */ cRemux::SetBrokenLink(buffer, Length); cutIn = false; } } +#ifndef USE_HARDLINKCUTTER if (toFile->Write(buffer, Length) < 0) { +#else + if (!SkipThisSourceFile && toFile->Write(buffer, Length) < 0) { +#endif /* HARDLINKCUTTER */ error = "safe_write"; break; } @@ -172,8 +305,44 @@ void cCuttingThread::Action(void) } } else +#ifndef USE_HARDLINKCUTTER LastMark = true; +#else + LastMark = true; // After last cut-out: Write on until next I-frame, then exit +#endif /* HARDLINKCUTTER */ + } +#ifdef USE_CUTTERLIMIT +#ifdef USE_HARDLINKCUTTER + if (!Setup.HardLinkCutter) { +#endif /* HARDLINKCUTTER */ + bytes += Length; + if (bytes >= burst_size) { + int elapsed = t.Elapsed(); + int sleep = 0; + +#if CUTTER_REL_BANDWIDTH > 0 && CUTTER_REL_BANDWIDTH < 100 + // stay under max. relative bandwidth + + sleep = (elapsed * 100 / CUTTER_REL_BANDWIDTH) - elapsed; + //if (sleep<=0 && elapsed<=2) sleep = 1; + //if (sleep) esyslog("cutter: relative bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); +#endif + // stay under max. absolute bandwidth + if (elapsed < CUTTER_TIMESLICE) { + sleep = max(CUTTER_TIMESLICE - elapsed, sleep); + //if (sleep) esyslog("cutter: absolute bandwidth limit, sleep %d ms (chunk %dk / %dms)", sleep, burst_size/1024, CUTTER_TIMESLICE); + } + + if (sleep>0) + cCondWait::SleepMs(sleep); + t.Set(); + bytes = 0; + } +#ifdef USE_HARDLINKCUTTER } +#endif /* HARDLINKCUTTER */ +#endif /* CUTTERLIMIT */ + } Recordings.TouchUpdate(); } @@ -183,18 +352,74 @@ void cCuttingThread::Action(void) // --- cCutter --------------------------------------------------------------- +#ifdef USE_CUTTERQUEUE +#define WAIT_BEFORE_NEXT_CUT (10*1000) // 10 seconds + +class cStringListObject : public cListObject { + public: + cStringListObject(const char *s) { str = strdup(s); } + ~cStringListObject() { free(str); } + + const char *Value() { return str; } + operator const char * () { return str; } + + private: + char *str; +}; +#endif /* CUTTERQUEUE */ + char *cCutter::editedVersionName = NULL; cCuttingThread *cCutter::cuttingThread = NULL; bool cCutter::error = false; bool cCutter::ended = false; +#ifdef USE_CUTTERQUEUE +cMutex *cCutter::cutterLock = new cMutex(); +static uint64_t /*cCutter::*/lastCuttingEndTime = 0; +static cList /**cCutter::*/cutterQueue /*= new cList*/; +#endif /* CUTTERQUEUE */ bool cCutter::Start(const char *FileName) { +#ifdef USE_CUTTERQUEUE + cMutexLock(cutterLock); + if (FileName) { + /* Add file to queue. + * If cutter is still active, next cutting will be started + * when vdr.c:main calls cCutter::Active and previous cutting has + * been stopped > 10 s before + */ + cutterQueue.Add(new cStringListObject(FileName)); + } + if (cuttingThread) + return true; + /* cut next file from queue */ + if (!(cutterQueue.First())) + return false; + FileName = cutterQueue.First()->Value(); +#endif /* CUTTERQUEUE */ if (!cuttingThread) { error = false; ended = false; cRecording Recording(FileName); +#ifdef USE_CUTTIME + if (Setup.CutTime) { + cMarks FromMarks; + FromMarks.Load(FileName); + cMark *First = FromMarks.First(); + if (First) Recording.SetStartTime(Recording.start + ((First->position / FRAMESPERSEC + 30) / 60) * 60); + } +#endif /* CUTTIME */ const char *evn = Recording.PrefixFileName('%'); +#ifdef USE_CUTTERQUEUE + if (!(Recordings.GetByName(FileName))) { + // Should _not_ remove any cutted recordings + // (original recording already deleted ?) + // so, just pop item from queue and return. + esyslog("can't cut non-existing recording %s", FileName); + cutterQueue.Del(cutterQueue.First()); + return true; // might be already queued recording + } +#endif /* CUTTERQUEUE */ if (evn && RemoveVideoFile(evn) && MakeDirs(evn, true)) { // XXX this can be removed once RenameVideoFile() follows symlinks (see videodir.c) // remove a possible deleted recording with the same name to avoid symlink mixups: @@ -220,6 +445,9 @@ bool cCutter::Start(const char *FileName void cCutter::Stop(void) { +#ifdef USE_CUTTERQUEUE + cMutexLock(cutterLock); +#endif /* CUTTERQUEUE */ bool Interrupted = cuttingThread && cuttingThread->Active(); const char *Error = cuttingThread ? cuttingThread->Error() : NULL; delete cuttingThread; @@ -231,11 +459,20 @@ void cCutter::Stop(void) esyslog("ERROR: '%s' during editing process", Error); RemoveVideoFile(editedVersionName); //XXX what if this file is currently being replayed? Recordings.DelByName(editedVersionName); +#ifdef USE_CUTTERQUEUE + cutterQueue.Del(cutterQueue.First()); +#endif /* CUTTERQUEUE */ } +#ifdef USE_CUTTERQUEUE + lastCuttingEndTime = cTimeMs::Now(); +#endif /* CUTTERQUEUE */ } bool cCutter::Active(void) { +#ifdef USE_CUTTERQUEUE + cMutexLock(cutterLock); +#endif /* CUTTERQUEUE */ if (cuttingThread) { if (cuttingThread->Active()) return true; @@ -246,12 +483,40 @@ bool cCutter::Active(void) free(editedVersionName); editedVersionName = NULL; ended = true; +#ifdef USE_CUTTERQUEUE + if (Setup.CutterAutoDelete) { + /* Remove original (if cutting was successful) */ + if (!error) { + cRecording *recording = Recordings.GetByName(*cutterQueue.First()); + if (!recording) + esyslog("ERROR: Can't found '%s' after editing process", cutterQueue.First()->Value()); + else { + if (recording->Delete()) + Recordings.DelByName(recording->FileName()); + else + esyslog("ERROR: Can't delete '%s' after editing process", cutterQueue.First()->Value()); + } + } + lastCuttingEndTime = cTimeMs::Now(); + } + cutterQueue.Del(cutterQueue.First()); +#endif /* CUTTERQUEUE */ + } +#ifdef USE_CUTTERQUEUE + if (!cuttingThread && cutterQueue.First()) { + /* start next cutting from queue*/ + if (cTimeMs::Now() > lastCuttingEndTime + WAIT_BEFORE_NEXT_CUT) + Start(NULL); } +#endif /* CUTTERQUEUE */ return false; } bool cCutter::Error(void) { +#ifdef USE_CUTTERQUEUE + cMutexLock(cutterLock); +#endif /* CUTTERQUEUE */ bool result = error; error = false; return result; @@ -259,6 +524,9 @@ bool cCutter::Error(void) bool cCutter::Ended(void) { +#ifdef USE_CUTTERQUEUE + cMutexLock(cutterLock); +#endif /* CUTTERQUEUE */ bool result = ended; ended = false; return result; diff -ruNp vdr-1.6.0-2/cutter.h vdr-1.6.0-2-extensions/cutter.h --- vdr-1.6.0-2/cutter.h 2002-06-22 12:03:15.000000000 +0200 +++ vdr-1.6.0-2-extensions/cutter.h 2009-04-09 20:48:26.000000000 +0200 @@ -11,6 +11,9 @@ #define __CUTTER_H class cCuttingThread; +#ifdef USE_CUTTERQUEUE +class cMutex; +#endif /* CUTTERQUEUE */ class cCutter { private: @@ -18,6 +21,9 @@ private: static cCuttingThread *cuttingThread; static bool error; static bool ended; +#ifdef USE_CUTTERQUEUE + static cMutex *cutterLock; +#endif /* CUTTERQUEUE */ public: static bool Start(const char *FileName); static void Stop(void); diff -ruNp vdr-1.6.0-2/device.c vdr-1.6.0-2-extensions/device.c --- vdr-1.6.0-2/device.c 2008-09-11 13:29:39.000000000 +0200 +++ vdr-1.6.0-2-extensions/device.c 2009-04-09 20:48:26.000000000 +0200 @@ -14,11 +14,22 @@ #include "audio.h" #include "channels.h" #include "i18n.h" +#ifdef USE_LIVEBUFFER +#include "livebuffer.h" +#endif /* LIVEBUFFER */ #include "player.h" #include "receiver.h" #include "status.h" #include "transfer.h" +#ifdef USE_LNBSHARE +#include "diseqc.h" +#endif /* LNBSHARE */ + +#ifdef USE_CHANNELSCAN +bool scanning_on_receiving_device = false; +#endif /* CHANNELSCAN */ + // --- cLiveSubtitle --------------------------------------------------------- #define LIVESUBTITLEBUFSIZE KILOBYTE(100) @@ -228,6 +239,12 @@ cDevice::cDevice(void) SetVideoFormat(Setup.VideoFormat); +#ifdef USE_LNBSHARE + LNBstate = -1; + LNBnr = Setup.CardUsesLNBnr[cardIndex]; + LNBsource = NULL; +#endif /* LNBSHARE */ + mute = false; volume = Setup.CurrentVolume; @@ -253,8 +270,15 @@ cDevice::cDevice(void) for (int i = 0; i < MAXRECEIVERS; i++) receiver[i] = NULL; +#ifdef USE_SOURCECAPS + if (numDevices < MAXDEVICES) { + device[numDevices++] = this; + SetSourceCaps(cardIndex); + } +#else if (numDevices < MAXDEVICES) device[numDevices++] = this; +#endif /* SOURCECAPS */ else esyslog("ERROR: too many devices!"); } @@ -290,6 +314,16 @@ void cDevice::SetUseDevice(int n) useDevice |= (1 << n); } +#ifdef USE_LNBSHARE +void cDevice::SetLNBnr(void) +{ + for (int i = 0; i < numDevices; i++) { + device[i]->LNBnr = Setup.CardUsesLNBnr[i]; + isyslog("LNB-sharing: setting device %d to use LNB %d", i, device[i]->LNBnr); + } +} +#endif /* LNBSHARE */ + int cDevice::NextCardIndex(int n) { if (n > 0) { @@ -350,6 +384,98 @@ cDevice *cDevice::ActualDevice(void) return d; } +#ifdef USE_LNBSHARE +cDevice *cDevice::GetBadDevice(const cChannel *Channel) +{ + if (!cSource::IsSat(Channel->Source())) + return NULL; + if (Setup.DiSEqC) { + cDiseqc *diseqc; + diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); + + for (int i = 0; i < numDevices; i++) { + if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { + if (Setup.VerboseLNBlog) + isyslog("LNB %d: Device check for channel %d on device %d. LNB or DiSEq conflict with device %d", LNBnr, Channel->Number(), this->DeviceNumber(), i); + return device[i]; + } + } + if (Setup.VerboseLNBlog) + isyslog("LNB %d: Device check for for channel %d on device %d. OK", LNBnr, Channel->Number(), this->DeviceNumber()); + } + else { + char requiredState; + + if (Channel->Frequency() >= Setup.LnbSLOF) + requiredState = 1 ; + else + requiredState = 0; + + if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') + requiredState += 2; + + for (int i = 0; i < numDevices; i++) { + if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { + if (Setup.VerboseLNBlog) + isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. Conflict with device %d, LNBstate %d", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate, i, device[i]->GetLNBconf()); + return device[i]; + } + } + if (Setup.VerboseLNBlog) + isyslog("LNB %d: Device check for channel %d, LNBstate %d on device %d, current LNBstate %d. No other devices affected", LNBnr, Channel->Number(), requiredState, this->DeviceNumber(), LNBstate); + } + return NULL; +} + +int cDevice::GetMaxBadPriority(const cChannel *Channel) +{ + if (!cSource::IsSat(Channel->Source())) return -2; + bool PrimaryIsBad = false; + int maxBadPriority = -2; + + if (Setup.DiSEqC) { + cDiseqc *diseqc; + diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); + + for (int i = 0; i < numDevices; i++) { + if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBsource() != (int*) diseqc) { + if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) + maxBadPriority = device[i]->Priority(); + if (i == ActualDevice()->CardIndex()) + PrimaryIsBad = true; + } + } + } + else { + char requiredState; + if (Channel->Frequency() >= Setup.LnbSLOF) + requiredState = 1 ; + else + requiredState = 0; + + if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') + requiredState += 2; + + for (int i = 0; i < numDevices; i++) { + if (this != device[i] && device[i]->GetLNBnr() == LNBnr && device[i]->GetLNBconf() != requiredState) { + if (device[i]->Receiving() && device[i]->Priority() > maxBadPriority) + maxBadPriority = device[i]->Priority(); + if (i == ActualDevice()->CardIndex()) + PrimaryIsBad = true; + } + } + } + + if (PrimaryIsBad && maxBadPriority == -2) + maxBadPriority = -1; + + if (Setup.VerboseLNBlog) + isyslog("LNB %d: Request for channel %d on device %d. MaxBadPriority is %d", LNBnr, Channel->Number(), this->DeviceNumber(), maxBadPriority); + + return maxBadPriority; +} +#endif /* LNBSHARE */ + cDevice *cDevice::GetDevice(int Index) { return (0 <= Index && Index < numDevices) ? device[Index] : NULL; @@ -384,6 +510,10 @@ cDevice *cDevice::GetDevice(const cChann cCamSlot *s = NULL; uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact +#ifdef USE_LNBSHARE + int badPriority; + uint imp2; +#endif /* LNBSHARE */ for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) { if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY) continue; // there is no CAM available in this slot @@ -408,6 +538,9 @@ cDevice *cDevice::GetDevice(const cChann imp <<= 1; imp |= LiveView ? !device[i]->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers imp <<= 1; imp |= !device[i]->Receiving() && (device[i] != cTransferControl::ReceiverDevice() || device[i]->IsPrimaryDevice()) || ndr; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode imp <<= 1; imp |= device[i]->Receiving(); // avoid devices that are receiving +#ifdef USE_LIVEBUFFER + imp <<= 2; imp |= cLiveBufferManager::Impact(device[i], Channel, LiveView); +#endif /* LIVEBUFFER */ imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device imp <<= 8; imp |= min(max(device[i]->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used) imp <<= 8; imp |= min(max((NumUsableSlots ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used) @@ -416,7 +549,31 @@ cDevice *cDevice::GetDevice(const cChann imp <<= 1; imp |= NumUsableSlots ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels imp <<= 1; imp |= device[i]->HasDecoder(); // avoid full featured cards imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel +#ifdef USE_LNBSHARE + badPriority = device[i]->GetMaxBadPriority(Channel); + if (badPriority >= Priority || (badPriority == -1 && Priority < Setup.PrimaryLimit)) { + // channel is not available for the requested prioity + imp = 0xFFFFFFFF; + } + else { + switch (badPriority) { + case -2: // not affected by LNB-sharing + imp2 = 0; + break; + case -1: // the primary device would need a channel switch + imp += 1 << 17; + imp2 = 0xFFFFFFFF | 1 << 17; + break; + default: // a device receiving with lower priority would need to be stopped + imp += badPriority << 8; + imp2 = 0xFFFFFFFF | badPriority << 8; + break; + } + } + if (imp < Impact && imp2 < Impact) { +#else if (imp < Impact) { +#endif /* LNBSHARE */ // This device has less impact than any previous one, so we take it. Impact = imp; d = device[i]; @@ -457,6 +614,18 @@ void cDevice::SetCamSlot(cCamSlot *CamSl camSlot = CamSlot; } +#ifdef USE_SOURCECAPS +void cDevice::SetSourceCaps(int Index) +{ + for (int d = 0; d < numDevices; d++) { + if (Index < 0 || Index == device[d]->CardIndex()) { + for (int i = 0; i < MAXSOURCECAPS; i++) + device[d]->sourceCaps[i] = Setup.SourceCaps[device[d]->CardIndex()][i]; + } + } +} +#endif /* SOURCECAPS */ + void cDevice::Shutdown(void) { primaryDevice = NULL; @@ -701,7 +870,11 @@ bool cDevice::ProvidesTransponder(const bool cDevice::ProvidesTransponderExclusively(const cChannel *Channel) const { for (int i = 0; i < numDevices; i++) { +#ifdef USE_LNBSHARE + if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel) && device[i]->GetLNBnr() != LNBnr) +#else if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel)) +#endif /* LNBSHARE */ return false; } return true; @@ -724,6 +897,24 @@ bool cDevice::MaySwitchTransponder(void) bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView) { +#ifdef USE_LNBSHARE + cDevice *tmpDevice; + if (this->GetMaxBadPriority(Channel) >= 0) { + Skins.Message(mtInfo, tr("Channel locked by LNB!")); + return false; + } + while ((tmpDevice = GetBadDevice(Channel)) != NULL) { + if (tmpDevice->IsPrimaryDevice() && LiveView) + tmpDevice->SwitchChannelForced(Channel, true); + else + tmpDevice->SwitchChannelForced(Channel, false); + } + return SwitchChannelForced(Channel, LiveView); +} + +bool cDevice::SwitchChannelForced(const cChannel *Channel, bool LiveView) +{ +#endif /* LNBSHARE */ if (LiveView) { isyslog("switching to channel %d", Channel->Number()); cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer @@ -753,7 +944,14 @@ bool cDevice::SwitchChannel(int Directio cChannel *channel; while ((channel = Channels.GetByNumber(n, Direction)) != NULL) { // try only channels which are currently available +#ifdef USE_PINPLUGIN + if (cStatus::MsgChannelProtected(0, channel) == false) +#endif /* PINPLUGIN */ +#ifdef USE_LNBSHARE + if (PrimaryDevice()->GetMaxBadPriority(channel) < 0 && (GetDevice(channel, 0, true))) +#else if (GetDevice(channel, 0, true)) +#endif /* LNBSHARE */ break; n = channel->Number() + Direction; } @@ -774,7 +972,18 @@ bool cDevice::SwitchChannel(int Directio eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) { +#ifdef USE_PINPLUGIN + // I hope 'LiveView = false' indicates a channel switch for recording, + // I really don't know, but it works ... + if (LiveView && cStatus::MsgChannelProtected(this, Channel) == true) + return scrNotAvailable; +#endif /* PINPLUGIN */ + +#ifdef USE_LIVEBUFFER + if (LiveView && !(Setup.LiveBuffer && dynamic_cast(player) != NULL)) { +#else if (LiveView) { +#endif /* LIVEBUFFER */ StopReplay(); DELETENULL(liveSubtitle); DELETENULL(dvbSubtitleConverter); @@ -784,15 +993,51 @@ eSetChannelResult cDevice::SetChannel(co bool NeedsTransferMode = Device != this; +#ifdef USE_LIVEBUFFER + if (LiveView && Setup.LiveBuffer) + NeedsTransferMode = true; +#endif /* LIVEBUFFER */ + eSetChannelResult Result = scrOk; +#ifdef USE_LNBSHARE + char requiredState; + if (Channel->Frequency() >= Setup.LnbSLOF) + requiredState = 1; + else + requiredState = 0; + + if (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') + requiredState += 2; + + if (Setup.VerboseLNBlog) + isyslog("LNB %d: Switching device %d to channel %d", LNBnr, this->DeviceNumber(), Channel->Number()); +#endif /* LNBSHARE */ + // If this DVB card can't receive this channel, let's see if we can // use the card that actually can receive it and transfer data from there: if (NeedsTransferMode) { if (Device && CanReplay()) { +#ifdef USE_LNBSHARE + if (Device->GetLNBnr() == LNBnr) { + if (LNBstate != requiredState || (Setup.DiSEqC && LNBsource != (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization())) ) { + if (IsPrimaryDevice()) + SetChannelDevice(Channel, true); + else + SetChannelDevice(Channel, false); + LNBstate = requiredState; + LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); + } + } +#endif /* LNBSHARE */ cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel if (Device->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! +#ifdef USE_LIVEBUFFER + if (Setup.LiveBuffer) + cLiveBufferManager::ChannelSwitch(Device,Channel); + else +#endif /* LIVEBUFFER */ cControl::Launch(new cTransferControl(Device, Channel->GetChannelID(), Channel->Vpid(), Channel->Apids(), Channel->Dpids(), Channel->Spids())); else Result = scrNoTransfer; @@ -808,6 +1053,10 @@ eSetChannelResult cDevice::SetChannel(co sectionHandler->SetStatus(false); sectionHandler->SetChannel(NULL); } +#ifdef USE_LNBSHARE + LNBstate = requiredState; + LNBsource = (int*) Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); +#endif /* LNBSHARE */ // Tell the camSlot about the channel switch and add all PIDs of this // channel to it, for possible later decryption: if (camSlot) @@ -840,7 +1089,11 @@ eSetChannelResult cDevice::SetChannel(co } for (int i = 0; i < MAXSPIDS; i++) SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i)); +#ifdef USE_SYNCEARLY + if ((Setup.UseSyncEarlyPatch && (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone)) || (!Setup.UseSyncEarlyPatch && !NeedsTransferMode)) +#else if (!NeedsTransferMode) +#endif /* SYNCEARLY */ EnsureAudioTrack(true); EnsureSubtitleTrack(); } @@ -1100,7 +1353,12 @@ void cDevice::EnsureSubtitleTrack(void) int LanguagePreference = INT_MAX; // higher than the maximum possible value for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) { const tTrackId *TrackId = GetTrack(eTrackType(i)); +#ifdef USE_LIEMIEXT + if (TrackId && TrackId->id && (I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference) || + ((i == ttSubtitleFirst + 8) && !(*TrackId->language) && (LanguagePreference == INT_MAX)))) +#else if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference)) +#endif /* LIEMIEXT */ PreferredTrack = eTrackType(i); } // Make sure we're set to an available subtitle track: @@ -1164,7 +1422,11 @@ bool cDevice::Replaying(void) const bool cDevice::Transferring(void) const { +#ifdef USE_LIVEBUFFER + return ActualDevice() != PrimaryDevice() || dynamic_cast(player) != NULL; // TODO +#else return ActualDevice() != PrimaryDevice(); +#endif /* LIVEBUFFER */ } bool cDevice::AttachPlayer(cPlayer *Player) @@ -1289,7 +1551,11 @@ pre_1_3_19_PrivateStreamDetected: w = PlaySubtitle(Start, d); break; case 0x80: // AC3 & DTS +#ifdef USE_DOLBYINREC + if (Setup.UseDolbyInRecordings) { +#else if (Setup.UseDolbyDigital) { +#endif /* DOLBYINREC */ SetAvailableTrack(ttDolby, SubStreamIndex, SubStreamId); if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) { w = PlayAudio(Start, d, SubStreamId); diff -ruNp vdr-1.6.0-2/device.h vdr-1.6.0-2-extensions/device.h --- vdr-1.6.0-2/device.h 2008-02-23 14:13:04.000000000 +0100 +++ vdr-1.6.0-2-extensions/device.h 2009-04-09 20:48:26.000000000 +0200 @@ -23,8 +23,13 @@ #include "spu.h" #include "thread.h" #include "tools.h" +#ifdef USE_ROTOR +#include +#endif /* ROTOR */ +#ifndef USE_SOURCECAPS #define MAXDEVICES 16 // the maximum number of devices in the system +#endif /* SOURCECAPS */ #define MAXPIDHANDLES 64 // the maximum number of different PIDs per device #define MAXRECEIVERS 16 // the maximum number of receivers per device #define MAXVOLUME 255 @@ -34,6 +39,10 @@ #define TS_SYNC_BYTE 0x47 #define PID_MASK_HI 0x1F +#ifdef USE_CHANNELSCAN +extern bool scanning_on_receiving_device; +#endif /* CHANNELSCAN */ + enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed }; enum ePlayMode { pmNone, // audio/video from decoder @@ -146,6 +155,35 @@ public: ///< this device/CAM combination will be skipped in the next call to ///< GetDevice(). ///< See also ProvidesChannel(). +#ifdef USE_SOURCECAPS + static void SetSourceCaps(int Index = -1); + ///< Sets the SourceCaps of the given device according to the Setup data. +#endif /* SOURCECAPS */ +#ifdef USE_LNBSHARE +private: + char LNBstate; // Current frequency band and polarization of the DVB-tuner +// cDiseqc *LNBsource; // can not #include "diseqc.h". A workaround follows: + int *LNBsource; // [DiSEqC] DiSEqC-Source + int LNBnr; // Number of LNB used +public: + char GetLNBconf(void) { return LNBstate; } + int *GetLNBsource(void) { return LNBsource; } + int GetLNBnr(void) { return LNBnr; } + static void SetLNBnr(void); + cDevice *GetBadDevice(const cChannel *Channel); + ///< Returns NULL if there is no device which uses the same LNB or if + ///< all of those devices are tuned to the same frequency band and + ///< polarization as of the requested channel. + ///< Otherwise returns the first device found. + int GetMaxBadPriority(const cChannel *Channel); + ///< Returns the highest priority of all receiving devices which use + ///< the same LNB and are tuned to a different frequency band or + ///< polarization as of the requested channel. + ///< Returns -1 if there are no such devices, but the primary device + ///< would be affected by switching to the requested channel. + ///< Returns -2 if there are no such devices and the primary device + ///< would not be affected by switching to the requested channel. +#endif /* LNBSHARE */ static void SetAvoidDevice(cDevice *Device) { avoidDevice = Device; } ///< Sets the given Device to be temporarily avoided in the next call to ///< GetDevice(const cChannel, int, bool). @@ -156,6 +194,9 @@ private: static int nextCardIndex; int cardIndex; protected: +#ifdef USE_SOURCECAPS + int sourceCaps[MAXSOURCECAPS]; +#endif /* SOURCECAPS */ cDevice(void); virtual ~cDevice(); virtual bool Ready(void); @@ -237,17 +278,30 @@ public: bool SwitchChannel(const cChannel *Channel, bool LiveView); ///< Switches the device to the given Channel, initiating transfer mode ///< if necessary. + +#ifdef USE_LNBSHARE + bool SwitchChannelForced(const cChannel *Channel, bool LiveView); + ///< Switches the device to the given channel, initiating transfer mode + ///< if necessary. Forces the switch without taking care of the LNB configuration. +#endif /* LNBSHARE */ + static bool SwitchChannel(int Direction); ///< Switches the primary device to the next available channel in the given ///< Direction (only the sign of Direction is evaluated, positive values ///< switch to higher channel numbers). private: +#ifndef USE_YAEPG eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); ///< Sets the device to the given channel (general setup). +#endif /* YAEPG */ protected: virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); ///< Sets the device to the given channel (actual physical setup). public: +#ifdef USE_YAEPG + eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); + ///< Sets the device to the given channel (general setup). +#endif /* YAEPG */ static int CurrentChannel(void) { return primaryDevice ? currentChannel : 0; } ///< Returns the number of the current channel on the primary device. static void SetCurrentChannel(const cChannel *Channel) { currentChannel = Channel ? Channel->Number() : 0; } @@ -265,6 +319,9 @@ public: virtual bool HasProgramme(void); ///< Returns true if the device is currently showing any programme to ///< the user, either through replaying or live. +#ifdef USE_ROTOR + virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd) { return false; } +#endif /* ROTOR */ // PID handle facilities diff -ruNp vdr-1.6.0-2/dvbdevice.c vdr-1.6.0-2-extensions/dvbdevice.c --- vdr-1.6.0-2/dvbdevice.c 2008-02-09 17:11:44.000000000 +0100 +++ vdr-1.6.0-2-extensions/dvbdevice.c 2009-04-09 20:48:26.000000000 +0200 @@ -71,6 +71,9 @@ static int DvbOpen(const char *Name, int class cDvbTuner : public cThread { private: enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked }; +#ifdef USE_ROTOR + bool SendDiseqc; +#endif /* ROTOR */ int fd_frontend; int cardIndex; int tuneTimeout; @@ -83,6 +86,9 @@ private: cMutex mutex; cCondVar locked; cCondVar newSet; +#ifdef USE_ROTOR + dvb_diseqc_master_cmd diseqc_cmd; +#endif /* ROTOR */ bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0); bool SetFrontend(void); virtual void Action(void); @@ -91,12 +97,18 @@ public: virtual ~cDvbTuner(); bool IsTunedTo(const cChannel *Channel) const; void Set(const cChannel *Channel, bool Tune); +#ifdef USE_ROTOR + bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); +#endif /* ROTOR */ bool Locked(int TimeoutMs = 0); }; cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType) { fd_frontend = Fd_Frontend; +#ifdef USE_ROTOR + SendDiseqc = false; +#endif /* ROTOR */ cardIndex = CardIndex; frontendType = FrontendType; tuneTimeout = 0; @@ -145,6 +157,19 @@ bool cDvbTuner::Locked(int TimeoutMs) return tunerStatus >= tsLocked; } +#ifdef USE_ROTOR +bool cDvbTuner::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) +{ + cMutexLock MutexLock(&mutex); + if (frontendType != FE_QPSK || SendDiseqc) + return false; + diseqc_cmd = cmd; + SendDiseqc = true; + newSet.Broadcast(); + return true; +} +#endif /* ROTOR */ + bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs) { if (TimeoutMs) { @@ -210,6 +235,9 @@ bool cDvbTuner::SetFrontend(void) } } diseqcCommands = diseqc->Commands(); +#ifdef USE_DVBSETUP + isyslog("Sent DISEQC command: %s", diseqcCommands); +#endif /* DVBSETUP */ } frequency -= diseqc->Lof(); } @@ -258,6 +286,20 @@ bool cDvbTuner::SetFrontend(void) lockTimeout = DVBC_LOCK_TIMEOUT; } break; +#ifdef USE_ATSC + case FE_ATSC: { // ATSC + + // Frequency and symbol rate: + + Frontend.frequency = FrequencyToHz(channel.Frequency()); + Frontend.inversion = fe_spectral_inversion_t(channel.Inversion()); + Frontend.u.vsb.modulation = fe_modulation_t(channel.Modulation()); + + tuneTimeout = DVBC_TUNE_TIMEOUT; + lockTimeout = DVBC_LOCK_TIMEOUT; + } + break; +#endif /* ATSC */ case FE_OFDM: { // DVB-T // Frequency and OFDM paramaters: @@ -297,6 +339,12 @@ void cDvbTuner::Action(void) if (GetFrontendStatus(NewStatus, 10)) Status = NewStatus; cMutexLock MutexLock(&mutex); +#ifdef USE_ROTOR + if (SendDiseqc) { + CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &diseqc_cmd)); + SendDiseqc = false; + } +#endif /* ROTOR */ switch (tunerStatus) { case tsIdle: break; @@ -419,6 +467,11 @@ cDvbDevice::cDvbDevice(int n) if (fd_frontend >= 0) { dvb_frontend_info feinfo; if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) { +#ifdef USE_DVBSETUP + if (Setup.ChannelBlockerMode == 4) + frontendType = n == Setup.PrimaryDVB - 1 ? frontendType : feinfo.type; + else +#endif /* DVBSETUP */ frontendType = feinfo.type; dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType); } @@ -638,6 +691,13 @@ eVideoSystem cDvbDevice::GetVideoSystem( bool cDvbDevice::SetAudioBypass(bool On) { +#ifdef USE_DVBSETUP + if (Setup.DolbyTransferFix && On) { + cChannel *c=Channels.GetByNumber(cDevice::CurrentChannel()); + if (c->Ca(0) != 0) + return false; + } +#endif /* DVBSETUP */ if (setTransferModeForDolbyDigital != 1) return false; return ioctl(fd_audio, AUDIO_SET_BYPASS_MODE, On) == 0; @@ -743,23 +803,74 @@ void cDvbDevice::TurnOffLiveMode(bool Li bool cDvbDevice::ProvidesSource(int Source) const { int type = Source & cSource::st_Mask; +#ifdef USE_SOURCECAPS + if (Setup.SourceCapsSet && type == cSource::stSat && frontendType == FE_QPSK) { + for (int i = 0; i < MAXSOURCECAPS; i++) + if (sourceCaps[i] == Source) + return true; + return false; + } + else +#endif /* SOURCECAPS */ return type == cSource::stNone || type == cSource::stCable && frontendType == FE_QAM +#ifdef USE_ATSC + || type == cSource::stCable && frontendType == FE_ATSC + || type == cSource::stTerr && frontendType == FE_ATSC +#endif /* ATSC */ || type == cSource::stSat && frontendType == FE_QPSK || type == cSource::stTerr && frontendType == FE_OFDM; } bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const { +#ifdef USE_DVBSETUP + if (Setup.ChannelBlocker != 0) { + if ((Setup.ChannelBlockerMode == 0) || + (Setup.ChannelBlockerMode == 1 && HasDecoder()) || + (Setup.ChannelBlockerMode == 2 && IsPrimaryDevice()) || + (Setup.ChannelBlockerMode == 3 && IsPrimaryDevice() && HasDecoder())) { + if ((Setup.ChannelBlocker == 1 && cSource::IsCable(Channel->Source()) && fe_modulation_t(Channel->Modulation()) == QAM_256) || + (Setup.ChannelBlocker == 2 && cSource::IsCable(Channel->Source())) || + (Setup.ChannelBlocker == 3 && cSource::IsSat(Channel->Source())) || + (Setup.ChannelBlocker == 4 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) != NULL) || // blacklist + (Setup.ChannelBlocker == 5 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) == NULL) || // whitelist + (Setup.ChannelBlocker == 6)) + return false; + } + } +#endif /* DVBSETUP */ + return ProvidesSource(Channel->Source()) && (!cSource::IsSat(Channel->Source()) || !Setup.DiSEqC || Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization())); } bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const { +#ifdef USE_DVBSETUP + if (Setup.ChannelBlocker != 0) { + if ((Setup.ChannelBlockerMode == 0) || + (Setup.ChannelBlockerMode == 1 && HasDecoder()) || + (Setup.ChannelBlockerMode == 2 && IsPrimaryDevice()) || + (Setup.ChannelBlockerMode == 3 && IsPrimaryDevice() && HasDecoder())) { + if ((Setup.ChannelBlocker == 1 && cSource::IsCable(Channel->Source()) && fe_modulation_t(Channel->Modulation()) == QAM_256) || + (Setup.ChannelBlocker == 2 && cSource::IsCable(Channel->Source())) || + (Setup.ChannelBlocker == 3 && cSource::IsSat(Channel->Source())) || + (Setup.ChannelBlocker == 4 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) != NULL) || // blacklist + (Setup.ChannelBlocker == 5 && strstr(::Setup.ChannelBlockerList, Channel->GetChannelID().ToString()) == NULL) || // whitelist + (Setup.ChannelBlocker == 6)) + return false; + } + } +#endif /* DVBSETUP */ bool result = false; bool hasPriority = Priority < 0 || Priority > this->Priority(); bool needsDetachReceivers = false; +#ifdef USE_ANALOGTV + if ((Channel->Ca(0) == 0xA0) || (Channel->Ca(0) == 0xA1) || (Channel->Ca(0) == 0xA2)) + return false; +#endif /* ANALOGTV */ + if (ProvidesSource(Channel->Source())) { result = hasPriority; if (Priority >= 0 && Receiving(true)) { @@ -815,7 +926,11 @@ bool cDvbDevice::SetChannelDevice(const || pidHandlesVideo // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER ); +#ifdef USE_LIVEBUFFER + bool StartTransferMode = IsPrimaryDevice() && !DoTune && !Setup.LiveBuffer +#else bool StartTransferMode = IsPrimaryDevice() && !DoTune +#endif /* LIVEBUFFER */ && (LiveView && HasPid(vpid ? vpid : apid) && (!pidHandlesVideo || (!pidHandlesAudio && (dpid ? pidHandles[ptAudio].pid != dpid : true)))// the PID is already set as DMX_PES_OTHER || !LiveView && (pidHandlesVideo || pidHandlesAudio) // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER ); @@ -871,6 +986,13 @@ bool cDvbDevice::HasLock(int TimeoutMs) return dvbTuner ? dvbTuner->Locked(TimeoutMs) : false; } +#ifdef USE_ROTOR +bool cDvbDevice::SendDiseqcCmd(dvb_diseqc_master_cmd cmd) +{ + return dvbTuner->SendDiseqcCmd(cmd); +} +#endif /* ROTOR */ + int cDvbDevice::GetAudioChannelDevice(void) { if (HasDecoder()) { diff -ruNp vdr-1.6.0-2/dvbdevice.h vdr-1.6.0-2-extensions/dvbdevice.h --- vdr-1.6.0-2/dvbdevice.h 2008-02-08 14:48:31.000000000 +0100 +++ vdr-1.6.0-2-extensions/dvbdevice.h 2009-04-09 20:48:26.000000000 +0200 @@ -71,6 +71,9 @@ protected: virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); public: virtual bool HasLock(int TimeoutMs = 0); +#ifdef USE_ROTOR + virtual bool SendDiseqcCmd(dvb_diseqc_master_cmd cmd); +#endif /* ROTOR */ // PID handle facilities diff -ruNp vdr-1.6.0-2/dvbosd.c vdr-1.6.0-2-extensions/dvbosd.c --- vdr-1.6.0-2/dvbosd.c 2007-09-16 10:55:54.000000000 +0200 +++ vdr-1.6.0-2-extensions/dvbosd.c 2009-04-09 20:48:26.000000000 +0200 @@ -20,12 +20,26 @@ #define MAXNUMWINDOWS 7 // OSD windows are counted 1...7 #define MAXOSDMEMORY 92000 // number of bytes available to the OSD (for unmodified DVB cards) +#ifdef USE_SOFTOSD + #define SOFTOSD_MAXSIZE (720*576) + #define SOFTOSD_MINSIZE (720*64) +#endif + class cDvbOsd : public cOsd { private: int osdDev; int osdMem; bool shown; void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL); +#ifdef USE_SOFTOSD + int GetOsdSize() { + int OsdSize = 0; + cBitmap *Bitmap; + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) + OsdSize += Bitmap->Width() * Bitmap->Height(); + return OsdSize; + } +#endif protected: virtual void SetActive(bool On); public: @@ -76,6 +90,44 @@ void cDvbOsd::SetActive(bool On) } else if (shown) { cBitmap *Bitmap; +#ifdef USE_SOFTOSD + if (Setup.UseSoftOsd) { + if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) { + for (int fade = Setup.SoftOsdFadeoutSteps - 1; fade > 0; fade--) { + int64_t flush_start = cTimeMs::Now(); + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + int NumColors; + const tColor *Colors = Bitmap->Colors(NumColors); + if (Colors) { + tColor colors[NumColors]; + for (int i = 0; i < NumColors; i++) { + // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): + int alpha = (Colors[i] >> 24) & 0x000000FF; + alpha = (alpha * fade) / Setup.SoftOsdFadeoutSteps; + colors[i] = (alpha << 24) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); + } + Colors = colors; + Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); + if (!Setup.SoftOsdPaletteOnly) { + //Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, Bitmap->Width() - 1, Bitmap->Height() - 1, Bitmap->Data(0, 0)); + Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, 0, 0, Bitmap->Data(0, 0)); + } + } + } + int flush_time = cTimeMs::Now() - flush_start; + dsyslog("SOFTOSD: FadeOut Step %d from %d FlushTime = %d ms", + Setup.SoftOsdFadeoutSteps - fade, Setup.SoftOsdFadeoutSteps - 1, flush_time); + int wait_time = 1000 / Setup.SoftOsdRate; + while (flush_time > wait_time && fade > 2) { + fade--; + flush_time -= wait_time; + } + cCondWait::SleepMs(wait_time-flush_time); + } + } + } +#endif /* SOFTOSD */ for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { Cmd(OSD_SetWindow, 0, i + 1); Cmd(OSD_Close); @@ -83,6 +135,12 @@ void cDvbOsd::SetActive(bool On) shown = false; } } +#ifdef USE_YAEPG + if (vidWin.bpp != 0) { + Cmd(OSD_SetWindow, 0, 5); + Cmd(OSD_Close); + } +#endif /* YAEPG */ } eOsdError cDvbOsd::CanHandleAreas(const tArea *Areas, int NumAreas) @@ -182,6 +240,12 @@ void cDvbOsd::Flush(void) for (int i = 0; i < NumColors; i++) { // convert AARRGGBB to AABBGGRR (the driver expects the colors the wrong way): colors[i] = (Colors[i] & 0xFF000000) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); +#ifdef USE_SOFTOSD + if (Setup.UseSoftOsd && !shown) { + if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) + colors[i] = 0; + } +#endif /* SOFTOSD */ } Colors = colors; //TODO end of stuff that should be fixed in the driver @@ -198,6 +262,51 @@ void cDvbOsd::Flush(void) Cmd(OSD_SetWindow, 0, i + 1); Cmd(OSD_MoveWindow, 0, Left() + Bitmap->X0(), Top() + Bitmap->Y0()); } +#ifdef USE_YAEPG + if (vidWin.bpp != 0) { + Cmd(OSD_SetWindow, 0, 5); + Cmd(OSD_OpenRaw, vidWin.bpp, vidWin.x1, vidWin.y1, vidWin.x2, vidWin.y2, (void *)0); + } +#endif /* YAEPG */ +#ifdef USE_SOFTOSD + if (Setup.UseSoftOsd) { + if (SOFTOSD_MAXSIZE > GetOsdSize() && SOFTOSD_MINSIZE < GetOsdSize()) { + for (int fade = 1; fade <= Setup.SoftOsdFadeinSteps; fade++) { + int64_t flush_start = cTimeMs::Now(); + for (int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) { + Cmd(OSD_SetWindow, 0, i + 1); + int NumColors; + const tColor *Colors = Bitmap->Colors(NumColors); + if (Colors) { + tColor colors[NumColors]; + for (int i = 0; i < NumColors; i++) { + // convert AARRGGBB to AABBGGRR: + int alpha = (Colors[i]>>24) & 0x000000FF; + alpha = (alpha * fade) / Setup.SoftOsdFadeinSteps; + colors[i] = (alpha << 24) | ((Colors[i] & 0x0000FF) << 16) | (Colors[i] & 0x00FF00) | ((Colors[i] & 0xFF0000) >> 16); + } + Colors = colors; + Cmd(OSD_SetPalette, 0, NumColors - 1, 0, 0, 0, Colors); + if (!Setup.SoftOsdPaletteOnly) { + //Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, Bitmap->Width() - 1, Bitmap->Height() - 1, Bitmap->Data(0, 0)); + Cmd(OSD_SetBlock, Bitmap->Width(), 0, 0, 0, 0, Bitmap->Data(0, 0)); + } + } + } + int flush_time = cTimeMs::Now() - flush_start; + dsyslog("SOFTOSD: FadeIn Step %d from %d FlushTime = %d ms", fade, Setup.SoftOsdFadeinSteps, flush_time); + int wait_time = 1000 / Setup.SoftOsdRate; + while (flush_time > wait_time && fade < Setup.SoftOsdFadeinSteps - 1) { + fade++; + flush_time -= wait_time; + } + if (fade == Setup.SoftOsdFadeinSteps) /* last step, don't wait */ + break; + cCondWait::SleepMs(wait_time - flush_time); + } + } + } +#endif /* SOFTOSD */ shown = true; } } diff -ruNp vdr-1.6.0-2/dvbplayer.c vdr-1.6.0-2-extensions/dvbplayer.c --- vdr-1.6.0-2/dvbplayer.c 2008-02-09 16:10:54.000000000 +0100 +++ vdr-1.6.0-2-extensions/dvbplayer.c 2009-04-09 20:48:26.000000000 +0200 @@ -14,6 +14,9 @@ #include "ringbuffer.h" #include "thread.h" #include "tools.h" +#ifdef USE_TTXTSUBS +#include "vdrttxtsubshooks.h" +#endif /* TTXTSUBS */ // --- cBackTrace ------------------------------------------------------------ @@ -193,6 +196,9 @@ private: cNonBlockingFileReader *nonBlockingFileReader; cRingBufferFrame *ringBuffer; cBackTrace *backTrace; +#ifdef USE_JUMPPLAY + cMarksReload marks; +#endif /* JUMPPLAY */ cFileName *fileName; cIndexFile *index; cUnbufferedFile *replayFile; @@ -234,7 +240,11 @@ public: int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; cDvbPlayer::cDvbPlayer(const char *FileName) +#ifdef USE_JUMPPLAY +:cThread("dvbplayer"), marks(FileName) +#else :cThread("dvbplayer") +#endif /* JUMPPLAY */ { nonBlockingFileReader = NULL; ringBuffer = NULL; @@ -312,6 +322,35 @@ void cDvbPlayer::Empty(void) firstPacket = true; } + +#ifdef USE_TTXTSUBS +static void StripExtendedPackets(uchar *b, int Length) +{ + for (int i = 0; i < Length - 6; i++) { + if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { + uchar c = b[i + 3]; + int l = b[i + 4] * 256 + b[i + 5] + 6; + switch (c) { + case 0xBD: // dolby + // EBU Teletext data, ETSI EN 300 472 + if (b[i + 8] == 0x24 && b[i + 45] >= 0x10 && b[i + 45] < 0x20) { + cVDRTtxtsubsHookListener::Hook()->PlayerTeletextData(&b[i], l); + // continue with deleting the data - otherwise it disturbs DVB replay + int n = l; + for (int j = i; j < Length && n--; j++) + b[j] = 0x00; + } + break; + default: + break; + } + if (l) + i += l - 1; // the loop increments, too! + } + } +} +#endif /* TTXTSUBS */ + bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset) { if (FileNumber > 0) @@ -341,6 +380,11 @@ bool cDvbPlayer::Save(void) if (index) { int Index = writeIndex; if (Index >= 0) { +#ifdef USE_JUMPPLAY + // set resume position to 0 if replay stops at the first mark + if (Setup.PlayJump && marks.First() && abs(Index - marks.First()->position) <= RESUMEBACKUP) + Index = 0; +#endif /* JUMPPLAY */ Index -= RESUMEBACKUP; if (Index > 0) Index = index->GetNextIFrame(Index, false); @@ -363,16 +407,154 @@ void cDvbPlayer::Activate(bool On) Cancel(9); } +#ifdef USE_DVBPLAYER +// --- BEGIN fix for I frames ------------------------------------------- +// +// Prior to the introduction of cVideoRepacker, VDR didn't start a new +// PES packet when a new frame started. So, it was likely that the tail +// of an I frame was at the beginning of the packet which started the +// following B frame. Due to the organisation of VDR's index file, VDR +// typically didn't read the tail of the I frame and therefore caused +// softdevice plugins to not render such a frame as it was incomplete, +// e. g. when moving cutting marks. +// +// The following code tries to fix incomplete I frames for recordings +// made prior to the introdcution of cVideoRepacker, to be able to +// edit cutting marks for example with softdevice plugins like vdr-xine. +// + +static uchar *findStartCode(uchar *Data, int Length, int &PesPayloadOffset) +{ + uchar *limit = Data + Length; + if (AnalyzePesHeader(Data, Length, PesPayloadOffset) <= phInvalid) + return 0; // neither MPEG1 nor MPEG2 + + Data += PesPayloadOffset + 3; // move to video payload and skip 00 00 01 + while (Data < limit) { + // possible start codes that appear before/after picture data + // 00 00 01 B3: sequence header code + // 00 00 01 B8: group start code + // 00 00 01 00: picture start code + // 00 00 01 B7: sequence end code + if (0x01 == Data[-1] && (0xB3 == Data[0] || 0xB8 == Data[0] || 0x00 == Data[0] || 0xB7 == Data[0]) && 0x00 == Data[-2] && 0x00 == Data[-3]) + return Data - 3; + Data++; + } + + return 0; +} + +static void fixIFrameHead(uchar *Data, int Length) +{ + int pesPayloadOffset = 0; + uchar *p = findStartCode(Data, Length, pesPayloadOffset); + if (!p) { + esyslog("fixIframeHead: start code not found!\n"); + return; + } + + Data += pesPayloadOffset; // move to video payload + if (Data < p) + memset(Data, 0, p - Data); // zero preceeding bytes +} + +static int fixIFrameTail(uchar *Data, int Length) +{ + int pesPayloadOffset = 0; + uchar *p = findStartCode(Data, Length, pesPayloadOffset); + if (!p) { + esyslog("fixIframeTail: start code not found!\n"); + return Length; + } + + // is this PES packet required? + uchar *videoPayload = Data + pesPayloadOffset; + if (videoPayload >= p) + return 0; // no + + // adjust PES length + int lenPES = (p - Data); + Data[4] = (lenPES - 6) >> 8; + Data[5] = (lenPES - 6) & 0xFF; + + return lenPES; +} + +#define IPACKS 2048 // originally defined in remux.c + +static void fixIFrame(uchar *Data, int &Length, const int OriginalLength) +{ + int done = 0; + + while (done < Length) { + if (0x00 != Data[0] || 0x00 != Data[1] || 0x01 != Data[2]) { + esyslog("fixIFrame: PES start code not found at offset %d (data length: %d, original length: %d)!", done, Length, OriginalLength); + if (Length > OriginalLength) // roll back additional data + Length = OriginalLength; + return; + } + + int lenPES = 6 + Data[4] * 256 + Data[5]; + if (0xBA == Data[3]) { // pack header has fixed length + if (0x00 == (0xC0 & Data[4])) + lenPES = 12; // MPEG1 + else + lenPES = 14 + (Data[13] & 0x07); // MPEG2 + } + else if (0xB9 == Data[3]) // stream end has fixed length + lenPES = 4; + else if (0xE0 == (0xF0 & Data[3])) { // video packet + int todo = Length - done; + int bite = (lenPES < todo) ? lenPES : todo; + if (0 == done) // first packet + fixIFrameHead(Data, bite); + else if (done >= OriginalLength) { // last packet + Length = done + fixIFrameTail(Data, bite); + return; + } + } + else if (0 == done && 0xC0 == (0xE0 & Data[3])) { + // if the first I frame packet is an audio packet then this is a radio recording: don't touch it! + if (Length > OriginalLength) // roll back additional data + Length = OriginalLength; + return; + } + + done += lenPES; + Data += lenPES; + } +} + +// --- END fix for I frames --------------------------------------------- +#endif /* DVBPLAYER */ + void cDvbPlayer::Action(void) { uchar *b = NULL; uchar *p = NULL; int pc = 0; +#ifdef USE_JUMPPLAY + bool cutIn = false; + int total = -1; +#endif /* JUMPPLAY */ readIndex = Resume(); if (readIndex >= 0) isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true)); +#ifdef USE_JUMPPLAY + if (Setup.PlayJump && readIndex <= 0 && marks.First() && index) { + int Index = marks.First()->position; + uchar FileNumber; + int FileOffset; + if (index->Get(Index, &FileNumber, &FileOffset) && NextFile(FileNumber, FileOffset)) { + isyslog("PlayJump: start replay at first mark %d (%s)", Index, *IndexToHMSF(Index, true)); + readIndex = Index; + } + } + + bool LastMarkPause = false; +#endif /* JUMPPLAY */ nonBlockingFileReader = new cNonBlockingFileReader; int Length = 0; bool Sleep = false; @@ -393,7 +575,11 @@ void cDvbPlayer::Action(void) // Read the next frame from the file: +#ifdef USE_JUMPPLAY + if (playMode != pmStill && playMode != pmPause && !LastMarkPause) { +#else if (playMode != pmStill && playMode != pmPause) { +#endif /* JUMPPLAY */ if (!readFrame && (replayFile || readIndex >= 0)) { if (!nonBlockingFileReader->Reading()) { if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { @@ -411,6 +597,9 @@ void cDvbPlayer::Action(void) if (!NextFile(FileNumber, FileOffset)) { readIndex = Index; continue; +#ifdef USE_DVBPLAYER + Length += IPACKS; // fixIFrame needs next video packet +#endif /* DVBPLAYER */ } } else { @@ -438,6 +627,43 @@ void cDvbPlayer::Action(void) uchar FileNumber; int FileOffset; readIndex++; +#ifdef USE_JUMPPLAY + if (Setup.PlayJump || Setup.PauseLastMark) { + // check for end mark - jump to next mark or pause + marks.Reload(); + cMark *m = marks.Get(readIndex); + if (m && (m->Index() & 0x01) != 0) { + m = marks.Next(m); + int Index; + if (m) + Index = m->position; + else if (Setup.PauseLastMark) { + // pause at last mark + isyslog("PauseLastMark: pause at position %d (%s)", readIndex, *IndexToHMSF(readIndex, true)); + LastMarkPause = true; + Index = -1; + } + else if (total == index->Last()) + // at last mark jump to end of recording + Index = index->Last() - 1; + else + // jump but stay off end of live-recordings + Index = index->GetNextIFrame(index->Last() - 150, true); + + // don't jump in edited recordings + if (Setup.PlayJump && Index > readIndex && Index > index->GetNextIFrame(readIndex, true)) { + isyslog("PlayJump: %d frames to %d (%s)", Index - readIndex, Index, *IndexToHMSF(Index, true)); + readIndex = Index; + cutIn = true; + } + } + } + // for detecting growing length of live-recordings + uchar PictureType; + if (index->Get(readIndex, &FileNumber, &FileOffset, &PictureType) && + PictureType == I_FRAME) + total = index->Last(); +#endif /* JUMPPLAY */ if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) { readIndex = -1; eof = true; @@ -457,6 +683,10 @@ void cDvbPlayer::Action(void) int r = nonBlockingFileReader->Read(replayFile, b, Length); if (r > 0) { WaitingForData = false; +#ifdef USE_DVBPLAYER + if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) + fixIFrame(b, r, Length - IPACKS); +#endif /* DVBPLAYER */ readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer b = NULL; } @@ -473,6 +703,12 @@ void cDvbPlayer::Action(void) // Store the frame in the buffer: if (readFrame) { +#ifdef USE_JUMPPLAY + if (cutIn) { + cRemux::SetBrokenLink(readFrame->Data(), readFrame->Count()); + cutIn = false; + } +#endif /* JUMPPLAY */ if (ringBuffer->Put(readFrame)) readFrame = NULL; } @@ -503,6 +739,9 @@ void cDvbPlayer::Action(void) } } if (p) { +#ifdef USE_TTXTSUBS + StripExtendedPackets(p, pc); +#endif /* TTXTSUBS */ int w = PlayPes(p, pc, playMode != pmPlay); if (w > 0) { p += w; @@ -521,8 +760,19 @@ void cDvbPlayer::Action(void) p = NULL; } } +#ifdef USE_JUMPPLAY + else { + if (LastMarkPause) { + LastMarkPause = false; + playMode = pmPause; + writeIndex = readIndex; + } + Sleep = true; + } +#else else Sleep = true; +#endif /* JUMPPLAY */ } } @@ -699,9 +949,15 @@ void cDvbPlayer::Goto(int Index, bool St int FileOffset, Length; Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length); if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { +#ifdef USE_DVBPLAYER + Length += IPACKS; // fixIFrame needs next video packet +#endif /* DVBPLAYER */ uchar b[MAXFRAMESIZE + 4 + 5 + 4]; int r = ReadFrame(replayFile, b, Length, sizeof(b)); if (r > 0) { +#ifdef USE_DVBPLAYER + fixIFrame(b, r, Length - IPACKS); +#endif /* DVBPLAYER */ if (playMode == pmPause) DevicePlay(); // append sequence end code to get the image shown immediately with softdevices diff -ruNp vdr-1.6.0-2/eit.c vdr-1.6.0-2-extensions/eit.c --- vdr-1.6.0-2/eit.c 2008-09-11 13:29:39.000000000 +0200 +++ vdr-1.6.0-2-extensions/eit.c 2009-04-09 20:48:26.000000000 +0200 @@ -17,13 +17,40 @@ #include "libsi/section.h" #include "libsi/descriptor.h" +#ifdef USE_SETTIME +extern char *SetTime; +#endif /* SETTIME */ + // --- cEIT ------------------------------------------------------------------ class cEIT : public SI::EIT { public: cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus = false); +#ifdef USE_NOEPG +private: + bool allowedEPG(tChannelID kanalID); +#endif /* NOEPG */ }; +#ifdef USE_NOEPG +bool cEIT::allowedEPG(tChannelID kanalID) { + bool rc; + + if (Setup.noEPGMode == 1) { + rc = false; + if (strstr(::Setup.noEPGList, kanalID.ToString()) != NULL) + rc = true; + } + else { + rc = true; + if (strstr(::Setup.noEPGList, kanalID.ToString()) != NULL) + rc = false; + } + + return rc; +} +#endif /* NOEPG */ + cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bool OnlyRunningStatus) :SI::EIT(Data, false) { @@ -35,6 +62,14 @@ cEIT::cEIT(cSchedules *Schedules, int So if (!channel) return; // only collect data for known channels +#ifdef USE_NOEPG + // only use epg from channels not blocked by noEPG-patch + tChannelID kanalID; + kanalID = channel->GetChannelID(); + if (!allowedEPG(kanalID)) + return; +#endif /* NOEPG */ + cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true); bool Empty = true; @@ -71,8 +106,74 @@ cEIT::cEIT(cSchedules *Schedules, int So // If the existing event has a zero table ID it was defined externally and shall // not be overwritten. if (pEvent->TableID() == 0x00) { +#ifdef USE_DDEPGENTRY + if (pEvent->Version() == getVersionNumber()) { + if (Setup.MixEpgAction == 0) + continue; + //printf("in"); + //printf("%s", pEvent->GetTimeString()); + // to use the info of the original epg, update the extern one, + // if it has less info + SI::Descriptor *d; + SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL; + //SI::ExtendedEventDescriptor *eed = NULL; + SI::ShortEventDescriptor *ShortEventDescriptor = NULL; + //SI::ShortEventDescriptor *sed = NULL; + //SI::TimeShiftedEventDescriptor *tsed = NULL; + //cLinkChannels *LinkChannels = NULL; + for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2));) { + if (d->getDescriptorTag() == SI::ShortEventDescriptorTag) { + int LanguagePreferenceShort = -1; + SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d; + if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) { + delete ShortEventDescriptor; + ShortEventDescriptor = sed; + d = NULL; // so that it is not deleted + } + } + else if (d->getDescriptorTag() == SI::ExtendedEventDescriptorTag) { + int LanguagePreferenceExt = -1; + bool UseExtendedEventDescriptor = false; + SI::ExtendedEventDescriptor *eed = (SI::ExtendedEventDescriptor *)d; + if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { + delete ExtendedEventDescriptors; + ExtendedEventDescriptors = new SI::ExtendedEventDescriptors; + UseExtendedEventDescriptor = true; + } + if (UseExtendedEventDescriptor) { + ExtendedEventDescriptors->Add(eed); + d = NULL; // so that it is not deleted + } + if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber()) + UseExtendedEventDescriptor = false; + } + delete d; + } + if (pEvent) { + if (ShortEventDescriptor) { + char buffer[256]; + if (ShortEventDescriptor->text.getText(buffer, sizeof(buffer)) && pEvent->ShortText() && (strlen(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))) > strlen(pEvent->ShortText()))) { + pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer, sizeof(buffer))); + pEvent->FixEpgBugs(); + } + } + if (ExtendedEventDescriptors) { + char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ") + 1]; + //pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); + if (ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ") && pEvent->Description() && (strlen(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")) > strlen(pEvent->Description()))) { + pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); + pEvent->FixEpgBugs(); + } + } + } + delete ExtendedEventDescriptors; + delete ShortEventDescriptor; + continue; + } +#else if (pEvent->Version() == getVersionNumber()) continue; +#endif /* DDEPGENTRY */ HasExternalData = ExternalData = true; } // If the new event has a higher table ID, let's skip it. @@ -97,7 +198,11 @@ cEIT::cEIT(cSchedules *Schedules, int So if (newEvent) pSchedule->AddEvent(newEvent); if (Tid == 0x4E) { // we trust only the present/following info on the actual TS +#ifdef USE_DDEPGENTRY + if (Setup.DisableVPS == 0 && SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) +#else if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning) +#endif /* DDEPGENTRY */ pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel); } if (OnlyRunningStatus) @@ -143,8 +248,46 @@ cEIT::cEIT(cSchedules *Schedules, int So } break; case SI::ContentDescriptorTag: +#ifdef USE_PARENTALRATING + { + int NumContents = 0; + uchar Contents[MAXEVCONTENTS + 1] = { 0 }; + SI::ContentDescriptor *cd = (SI::ContentDescriptor *)d; + SI::ContentDescriptor::Nibble Nibble; + for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3); ) { + if (NumContents < MAXEVCONTENTS) { + Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF); + NumContents++; + } + } + pEvent->SetContents(Contents); + } +#endif /* PARENTALRATING */ break; case SI::ParentalRatingDescriptorTag: +#ifdef USE_PARENTALRATING + { + int LanguagePreferenceRating = -1; + SI::ParentalRatingDescriptor *prd = (SI::ParentalRatingDescriptor *)d; + SI::ParentalRatingDescriptor::Rating Rating; + for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3); ) { + if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode, LanguagePreferenceRating)) { + int rate = (Rating.getRating() & 0xFF); + switch (rate) { + case 0x01 ... 0x0F: // minimum age = rating + 3 years + rate += 3; + break; + case 0: // undefined + case 0x10 ... 0xFF: // defined by the broadcaster + default: + rate = 0; + break; + } + pEvent->SetParentalRating(rate); + } + } + } +#endif /* PARENTALRATING */ break; case SI::PDCDescriptorTag: { SI::PDCDescriptor *pd = (SI::PDCDescriptor *)d; @@ -259,6 +402,62 @@ cEIT::cEIT(cSchedules *Schedules, int So if (LinkChannels) channel->SetLinkChannels(LinkChannels); Modified = true; +#ifdef USE_DDEPGENTRY + //to avoid double epg-entrys from ext and int epg sources :EW + if (pEvent && pEvent->TableID() != 0x00) { + cEvent *pPreviousEvent = (cEvent *)pSchedule->GetPreviousEvent(pEvent); + if (pPreviousEvent) { + if (Setup.DoubleEpgAction == 0) { + pPreviousEvent->SetStartTime(pEvent->StartTime()); + pPreviousEvent->SetDuration(pEvent->Duration()); + if (Setup.DisableVPS == 0) { + if (channel) + pPreviousEvent->SetRunningStatus(pEvent->RunningStatus(), channel); + else + pPreviousEvent->SetRunningStatus(pEvent->RunningStatus()); + } + // to use the info of the original epg, update the extern one, + // if it has less info + char buffer_short_intern[256]; + char buffer_short_extern[256]; + int len_short_intern = 0; + int len_short_extern = 0; + if (pEvent->ShortText()) + len_short_intern = snprintf (buffer_short_intern, sizeof(buffer_short_intern)-1, "%s", pEvent->ShortText()); + if (pPreviousEvent->ShortText()) + len_short_extern = snprintf (buffer_short_extern, sizeof(buffer_short_extern)-1, "%s", pPreviousEvent->ShortText()); + if (len_short_intern > 0) { + if (len_short_extern < 1) + pPreviousEvent->SetShortText(buffer_short_intern); + else if (len_short_intern > len_short_extern) + pPreviousEvent->SetShortText(buffer_short_intern); + } + if (pEvent->Description()) { + char buffer_title_intern[4096]; + char buffer_title_extern[4096]; + int len_title_intern = 0; + int len_title_extern = 0; + if (pEvent->Description()) + len_title_intern = snprintf (buffer_title_intern, sizeof(buffer_title_intern)-1, "%s", pEvent->Description()); + if (pPreviousEvent->Description()) + len_title_extern = snprintf (buffer_title_extern, sizeof(buffer_title_extern)-1, "%s", pPreviousEvent->Description()); + if (len_title_intern > 0) { + if (len_title_extern < 1) + pPreviousEvent->SetDescription(buffer_title_intern); + else if (len_title_intern > len_title_extern) + pPreviousEvent->SetDescription(buffer_title_intern); + } + } + if (pPreviousEvent->Vps() == 0 && pEvent->Vps() != 0) + pPreviousEvent->SetVps(pEvent->Vps()); + pSchedule->DelEvent(pEvent); + pPreviousEvent->FixEpgBugs(); + } + else + pSchedule->DelEvent(pPreviousEvent); + } + } +#endif /* DDEPGENTRY */ } if (Empty && Tid == 0x4E && getSectionNumber() == 0) // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running @@ -296,10 +495,26 @@ cTDT::cTDT(const u_char *Data) time_t sattim = getTime(); time_t loctim = time(NULL); +#ifdef USE_SETTIME + char timestr[20]; + struct tm *ptm; + struct tm tm_r; + ptm = localtime_r(&sattim, &tm_r); +#endif /* SETTIME */ + int diff = abs(sattim - loctim); if (diff > 2) { mutex.Lock(); if (abs(diff - lastDiff) < 3) { +#ifdef USE_SETTIME + if (SetTime) { + strftime(timestr, 20, "%m%d%H%M%Y.%S", ptm); + cString cmd = cString::sprintf("%s %s %ld", SetTime, timestr, sattim); + dsyslog("Executing: %s", *cmd); + SystemExec(cmd); + } + else +#endif /* SETTIME */ if (stime(&sattim) == 0) isyslog("system time changed from %s (%ld) to %s (%ld)", *TimeToString(loctim), loctim, *TimeToString(sattim), sattim); else diff -ruNp vdr-1.6.0-2/eitscan.c vdr-1.6.0-2-extensions/eitscan.c --- vdr-1.6.0-2/eitscan.c 2006-01-07 15:10:17.000000000 +0100 +++ vdr-1.6.0-2-extensions/eitscan.c 2009-04-09 20:48:26.000000000 +0200 @@ -151,9 +151,17 @@ void cEITScanner::Process(void) if (Device->ProvidesTransponder(Channel)) { if (!Device->Receiving()) { bool MaySwitchTransponder = Device->MaySwitchTransponder(); +#ifdef USE_LNBSHARE + if (MaySwitchTransponder && Device->GetMaxBadPriority(Channel) == -2 || Device->ProvidesTransponderExclusively(Channel) && Device->GetMaxBadPriority(Channel) <= -1 && now - lastActivity > Setup.EPGScanTimeout * 3600) { +#else if (MaySwitchTransponder || Device->ProvidesTransponderExclusively(Channel) && now - lastActivity > Setup.EPGScanTimeout * 3600) { +#endif /* LNBSHARE */ if (!MaySwitchTransponder) { +#ifdef USE_LNBSHARE + if ((Device == cDevice::ActualDevice() || Device->GetMaxBadPriority(Channel) == -1) && !currentChannel) { +#else if (Device == cDevice::ActualDevice() && !currentChannel) { +#endif /* LNBSHARE */ cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode currentChannel = Device->CurrentChannel(); Skins.Message(mtInfo, tr("Starting EPG scan")); diff -ruNp vdr-1.6.0-2/epg.c vdr-1.6.0-2-extensions/epg.c --- vdr-1.6.0-2/epg.c 2008-02-16 17:09:12.000000000 +0100 +++ vdr-1.6.0-2-extensions/epg.c 2009-04-09 20:48:26.000000000 +0200 @@ -112,6 +112,11 @@ cEvent::cEvent(tEventID EventID) components = NULL; startTime = 0; duration = 0; +#ifdef USE_PARENTALRATING + for (int i = 0; i < MAXEVCONTENTS; i++) + contents[i] = 0; + parentalRating = 0; +#endif /* PARENTALRATING */ vps = 0; SetSeen(); } @@ -200,6 +205,19 @@ void cEvent::SetDuration(int Duration) duration = Duration; } +#ifdef USE_PARENTALRATING +void cEvent::SetContents(uchar *Contents) +{ + for (int i = 0; i < MAXEVCONTENTS; i++) + contents[i] = Contents[i]; +} + +void cEvent::SetParentalRating(uchar ParentalRating) +{ + parentalRating = ParentalRating; +} +#endif /* PARENTALRATING */ + void cEvent::SetVps(time_t Vps) { vps = Vps; @@ -255,6 +273,340 @@ cString cEvent::GetVpsString(void) const return buf; } +#ifdef USE_PARENTALRATING +cString cEvent::GetContentsString(int i) const +{ + cString str(""); + switch (contents[i] & 0xF0) { + case EVCONTENTMASK_MOVIEDRAMA: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$Movie/Drama")); + break; + case 0x01: + str = cString(tr("Content$Detective/Thriller")); + break; + case 0x02: + str = cString(tr("Content$Adventure/Western/War")); + break; + case 0x03: + str = cString(tr("Content$Science Fiction/Fantasy/Horror")); + break; + case 0x04: + str = cString(tr("Content$Comedy")); + break; + case 0x05: + str = cString(tr("Content$Soap/Melodrama/Folkloric")); + break; + case 0x06: + str = cString(tr("Content$Romance")); + break; + case 0x07: + str = cString(tr("Content$Serious/Classical/Religious/Historical Movie/Drama")); + break; + case 0x08: + str = cString(tr("Content$Adult Movie/Drama")); + break; + } + break; + + case EVCONTENTMASK_NEWSCURRENTAFFAIRS: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$News/Current Affairs")); + break; + case 0x01: + str = cString(tr("Content$News/Weather Report")); + break; + case 0x02: + str = cString(tr("Content$News Magazine")); + break; + case 0x03: + str = cString(tr("Content$Documentary")); + break; + case 0x04: + str = cString(tr("Content$Discussion/Inverview/Debate")); + break; + } + break; + + case EVCONTENTMASK_SHOW: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$Show/Game Show")); + break; + case 0x01: + str = cString(tr("Content$Game Show/Quiz/Contest")); + break; + case 0x02: + str = cString(tr("Content$Variety Show")); + break; + case 0x03: + str = cString(tr("Content$Talk Show")); + break; + } + break; + + case EVCONTENTMASK_SPORTS: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$Sports")); + break; + case 0x01: + str = cString(tr("Content$Special Event")); + break; + case 0x02: + str = cString(tr("Content$Sport Magazine")); + break; + case 0x03: + str = cString(tr("Content$Football")); + break; + case 0x04: + str = cString(tr("Content$Tennis/Squash")); + break; + case 0x05: + str = cString(tr("Content$Team Sports")); + break; + case 0x06: + str = cString(tr("Content$Athletics")); + break; + case 0x07: + str = cString(tr("Content$Motor Sport")); + break; + case 0x08: + str = cString(tr("Content$Water Sport")); + break; + case 0x09: + str = cString(tr("Content$Winter Sports")); + break; + case 0x0A: + str = cString(tr("Content$Equestrian")); + break; + case 0x0B: + str = cString(tr("Content$Martial Sports")); + break; + } + break; + + case EVCONTENTMASK_CHILDRENYOUTH: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$Children's/Youth Programmes")); + break; + case 0x01: + str = cString(tr("Content$Pre-school Children's Programmes")); + break; + case 0x02: + str = cString(tr("Content$Entertainment Programmes for 6 to 14")); + break; + case 0x03: + str = cString(tr("Content$Entertainment Programmes for 10 to 16")); + break; + case 0x04: + str = cString(tr("Content$Informational/Educational/School Programme")); + break; + case 0x05: + str = cString(tr("Content$Cartoons/Puppets")); + break; + } + break; + + case EVCONTENTMASK_MUSICBALLETDANCE: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$Music/Ballet/Dance")); + break; + case 0x01: + str = cString(tr("Content$Rock/Pop")); + break; + case 0x02: + str = cString(tr("Content$Serious/Classical Music")); + break; + case 0x03: + str = cString(tr("Content$Folk/Tradional Music")); + break; + case 0x04: + str = cString(tr("Content$Jazz")); + break; + case 0x05: + str = cString(tr("Content$Musical/Opera")); + break; + case 0x06: + str = cString(tr("Content$Ballet")); + break; + } + break; + + case EVCONTENTMASK_ARTSCULTURE: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$Arts/Culture")); + break; + case 0x01: + str = cString(tr("Content$Performing Arts")); + break; + case 0x02: + str = cString(tr("Content$Fine Arts")); + break; + case 0x03: + str = cString(tr("Content$Religion")); + break; + case 0x04: + str = cString(tr("Content$Popular Culture/Traditional Arts")); + break; + case 0x05: + str = cString(tr("Content$Literature")); + break; + case 0x06: + str = cString(tr("Content$Film/Cinema")); + break; + case 0x07: + str = cString(tr("Content$Experimental Film/Video")); + break; + case 0x08: + str = cString(tr("Content$Broadcasting/Press")); + break; + case 0x09: + str = cString(tr("Content$New Media")); + break; + case 0x0A: + str = cString(tr("Content$Arts/Culture Magazines")); + break; + case 0x0B: + str = cString(tr("Content$Fashion")); + break; + } + break; + + case EVCONTENTMASK_SOCIALPOLITICALECONOMICS: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$Social/Political/Economics")); + break; + case 0x01: + str = cString(tr("Content$Magazines/Reports/Documentary")); + break; + case 0x02: + str = cString(tr("Content$Economics/Social Advisory")); + break; + case 0x03: + str = cString(tr("Content$Remarkable People")); + break; + } + break; + + case EVCONTENTMASK_EDUCATIONALSCIENCE: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$Education/Science/Factual")); + break; + case 0x01: + str = cString(tr("Content$Nature/Animals/Environment")); + break; + case 0x02: + str = cString(tr("Content$Technology/Natural Sciences")); + break; + case 0x03: + str = cString(tr("Content$Medicine/Physiology/Psychology")); + break; + case 0x04: + str = cString(tr("Content$Foreign Countries/Expeditions")); + break; + case 0x05: + str = cString(tr("Content$Social/Spiritual Sciences")); + break; + case 0x06: + str = cString(tr("Content$Further Education")); + break; + case 0x07: + str = cString(tr("Content$Languages")); + break; + } + break; + + case EVCONTENTMASK_LEISUREHOBBIES: + switch (contents[i] & 0x0F) { + default: + case 0x00: + str = cString(tr("Content$Leisure/Hobbies")); + break; + case 0x01: + str = cString(tr("Content$Tourism/Travel")); + break; + case 0x02: + str = cString(tr("Content$Handicraft")); + break; + case 0x03: + str = cString(tr("Content$Motoring")); + break; + case 0x04: + str = cString(tr("Content$Fitness & Health")); + break; + case 0x05: + str = cString(tr("Content$Cooking")); + break; + case 0x06: + str = cString(tr("Content$Advertisement/Shopping")); + break; + case 0x07: + str = cString(tr("Content$Gardening")); + break; + } + break; + + case EVCONTENTMASK_SPECIAL: + switch (contents[i] & 0x0F) { + case 0x00: + str = cString(tr("Content$Original Language")); + break; + case 0x01: + str = cString(tr("Content$Black & White")); + break; + case 0x02: + str = cString(tr("Content$Unpublished")); + break; + case 0x03: + str = cString(tr("Content$Live Broadcast")); + break; + default: + str = cString(tr("Content$Special Characteristics")); + break; + } + break; + + case EVCONTENTMASK_USERDEFINED: + switch (contents[i] & 0x0F) { + case 0x00: + str = cString(tr("Content$Drama")); // UK Freeview + break; + default: + break; + } + break; + + default: + break; + } + return str; +} + +cString cEvent::GetParentalRatingString(void) const +{ + if (parentalRating > 0) + return cString::sprintf(tr("Suitable for those aged %d and over"), parentalRating); + return NULL; +} +#endif /* PARENTALRATING */ + void cEvent::Dump(FILE *f, const char *Prefix, bool InfoOnly) const { if (InfoOnly || startTime + duration + Setup.EPGLinger * 60 >= time(NULL)) { @@ -742,6 +1094,28 @@ const cEvent *cSchedule::GetEventAround( return pe; } +#ifdef USE_DDEPGENTRY +const cEvent *cSchedule::GetPreviousEvent(cEvent *Event) const +{ + if (!Event || Event->Duration() == 0 || Event->StartTime() == 0) + return NULL; + // Returns either the event info to the previous/following event to the given EventID or, if that one can't be found NULL :EW + cEvent *pt = NULL; + int epgTimeDelta = Setup.DoubleEpgTimeDelta * 60 + 1; + for (pt = events.First(); pt; pt = events.Next(pt)) + if (pt && pt->TableID() == 0x00) + if ((Event->StartTime() - pt->StartTime()) > - epgTimeDelta && (Event->StartTime() - pt->StartTime()) < epgTimeDelta) { + if ((pt->Duration() + (pt->Duration()/ 5) + 1) > Event->Duration() && (pt->Duration() - (pt->Duration()/ 5) - 1) < Event->Duration()) + return pt; + else if (pt->Title() && Event->Title() && (strcmp(pt->Title(), ".") != 0 && strcmp(Event->Title(), ".") != 0)) { + if (strstr(pt->Title(), Event->Title()) != NULL || strstr(Event->Title(), pt->Title()) != NULL) + return pt; + } + } + return NULL; +} +#endif /* DDEPGENTRY */ + void cSchedule::SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel) { hasRunning = false; diff -ruNp vdr-1.6.0-2/epg.h vdr-1.6.0-2-extensions/epg.h --- vdr-1.6.0-2/epg.h 2006-10-07 15:47:19.000000000 +0200 +++ vdr-1.6.0-2-extensions/epg.h 2009-04-09 20:48:26.000000000 +0200 @@ -50,6 +50,22 @@ class cSchedule; typedef u_int32_t tEventID; +#ifdef USE_PARENTALRATING +#define MAXEVCONTENTS 4 +#define EVCONTENTMASK_MOVIEDRAMA 0x10 +#define EVCONTENTMASK_NEWSCURRENTAFFAIRS 0x20 +#define EVCONTENTMASK_SHOW 0x30 +#define EVCONTENTMASK_SPORTS 0x40 +#define EVCONTENTMASK_CHILDRENYOUTH 0x50 +#define EVCONTENTMASK_MUSICBALLETDANCE 0x60 +#define EVCONTENTMASK_ARTSCULTURE 0x70 +#define EVCONTENTMASK_SOCIALPOLITICALECONOMICS 0x80 +#define EVCONTENTMASK_EDUCATIONALSCIENCE 0x90 +#define EVCONTENTMASK_LEISUREHOBBIES 0xA0 +#define EVCONTENTMASK_SPECIAL 0xB0 +#define EVCONTENTMASK_USERDEFINED 0xF0 +#endif /* PARENTALRATING */ + class cEvent : public cListObject { friend class cSchedule; private: @@ -64,6 +80,10 @@ private: cComponents *components; // The stream components of this event time_t startTime; // Start time of this event int duration; // Duration of this event in seconds +#ifdef USE_PARENTALRATING + uchar contents[MAXEVCONTENTS + 1]; // Contents of this event; list is zero-terminated + uchar parentalRating; // Parental rating of this event +#endif /* PARENTALRATING */ time_t vps; // Video Programming Service timestamp (VPS, aka "Programme Identification Label", PIL) time_t seen; // When this event was last seen in the data stream public: @@ -83,6 +103,10 @@ public: time_t StartTime(void) const { return startTime; } time_t EndTime(void) const { return startTime + duration; } int Duration(void) const { return duration; } +#ifdef USE_PARENTALRATING + uchar Contents(int i = 0) const { return (0 <= i && i < MAXEVCONTENTS) ? contents[i] : 0; } + uchar ParentalRating(void) const { return parentalRating; } +#endif /* PARENTALRATING */ time_t Vps(void) const { return vps; } time_t Seen(void) const { return seen; } bool SeenWithin(int Seconds) const { return time(NULL) - seen < Seconds; } @@ -92,6 +116,10 @@ public: cString GetTimeString(void) const; cString GetEndTimeString(void) const; cString GetVpsString(void) const; +#ifdef USE_PARENTALRATING + cString GetContentsString(int i = 0) const; + cString GetParentalRatingString(void) const; +#endif /* PARENTALRATING */ void SetEventID(tEventID EventID); void SetTableID(uchar TableID); void SetVersion(uchar Version); @@ -102,6 +130,10 @@ public: void SetComponents(cComponents *Components); // Will take ownership of Components! void SetStartTime(time_t StartTime); void SetDuration(int Duration); +#ifdef USE_PARENTALRATING + void SetContents(uchar *Contents); + void SetParentalRating(uchar ParentalRating); +#endif /* PARENTALRATING */ void SetVps(time_t Vps); void SetSeen(void); cString ToDescr(void) const; @@ -137,6 +169,9 @@ public: void DropOutdated(time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version); void Cleanup(time_t Time); void Cleanup(void); +#ifdef USE_DDEPGENTRY + const cEvent *GetPreviousEvent(cEvent *Event) const; //:EW +#endif /* DDEPGENTRY */ cEvent *AddEvent(cEvent *Event); void DelEvent(cEvent *Event); void HashEvent(cEvent *Event); diff -ruNp vdr-1.6.0-2/HISTORY-liemikuutio vdr-1.6.0-2-extensions/HISTORY-liemikuutio --- vdr-1.6.0-2/HISTORY-liemikuutio 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/HISTORY-liemikuutio 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,108 @@ +----------------------------------- +Liemikuutio for Video Disc Recorder + +Maintainer: Rolf Ahrenberg +----------------------------------- + +2006-01-08: Version 1.0 + +- Based on enAIO with these original patches: + Simple recordings sorting by Walter@VDRPortal + Alternate rename recordings by Ralf Müller + Menu selection by Peter Dittmann + Recording length by Tobias Faust + +2006-01-15: Version 1.1 + +- Removed patches already found in vdr-1.3.39. + +2006-01-25: Version 1.2 + +- Added "Main menu command position" feature. + +2006-02-05: Version 1.3 + +- Improved menu selection response. + +2006-04-18: Version 1.4 + +- Added Estonian translation (Thanks to Arthur Konovalov). + +2006-04-30: Version 1.5 + +- Added progress bar view into "What's on now?" menu. + +2006-06-06: Version 1.6 + +- Added French translation (Thanks to ECLiPSE). + +2006-06-14: Version 1.7 + +- Fixed RENR crash. + +2006-07-14: Version 1.8 + +- Fixed RENR/OSD bug. + +2006-08-27: Version 1.9 + +- Some modifications to the recording length and rename recordings + patches (Thanks to Firefly). +- Added k1_k3_jumps_20s patch by Petri Hintukainen. + +2006-08-29: Version 1.10 + +- The cRecording:Title() method now defaults to original formatting. + +2006-09-04: Version 1.11 + +- Removed unused variable from cRecording::Title() method (Thanks to + C.Y.M.). +- Some modifications to the rename recordings patch (Thanks to Firefly). + +2006-09-13: Version 1.12 + +- More modifications to the rename recordings patch (Thanks to Firefly). + +2006-10-01: Version 1.13 + +- Removed unnecessary syslog printing (Thanks to Firefly). + +2007-08-14: Version 1.14 + +- Updated for vdr-1.5.7. + +2007-10-16: Version 1.15 + +- Added recmenu play patch (Thanks to Ville Skyttä). +- Updated French translation (Thanks to ECLiPSE). + +2007-11-04: Version 1.16 + +- Updated for vdr-1.5.11. + +2007-12-08: Version 1.17 + +- Added binary skip patch. +- Removed k1_k3_jumps_20s patch. + +2008-02-17: Version 1.18 + +- Updated for vdr-1.5.15. + +2008-03-02: Version 1.19 + +- Modified binary skip to use kPrev and kNext keys and the skip is now + always shortened after a direction change (Thanks to Timo Eskola). +- Readded k1_k3_jumps_20s patch. + +2008-04-04: Version 1.20 + +- Added bitrate information into rename menu. +- Readded the path editing support of rename recordings patch (Thanks + to Firefly). + +2008-05-08: Version 1.21 + +- Fixed rename recordings (Thanks to Firefly). +- Added a DVB subtitles hack for old recordings (Thanks to Anssi Hannula). diff -ruNp vdr-1.6.0-2/iconpatch.c vdr-1.6.0-2-extensions/iconpatch.c --- vdr-1.6.0-2/iconpatch.c 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/iconpatch.c 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,31 @@ +#ifdef USE_WAREAGLEICON + +#include "iconpatch.h" + +#include +#include +#include +#include +#include + +bool IsLangUtf8(void) +{ + char *CodeSet = NULL; + if (setlocale(LC_CTYPE, "")) + CodeSet = nl_langinfo(CODESET); + else { + char *LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed + if (LangEnv) { + CodeSet = strchr(LangEnv, '.'); + if (CodeSet) + CodeSet++; // skip the dot + } + } + + if (CodeSet && strcasestr(CodeSet, "UTF-8") != 0) + return true; + + return false; +} + +#endif /* WAREAGLEICON */ diff -ruNp vdr-1.6.0-2/iconpatch.h vdr-1.6.0-2-extensions/iconpatch.h --- vdr-1.6.0-2/iconpatch.h 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/iconpatch.h 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,73 @@ +#ifdef USE_WAREAGLEICON +/* + * iconpatch.h: Information of iconpatch + * + * Diese Datei ist die Übersichtsdatei für den Iconpatch. + * Hier werden kleine Infos abgelegt. + * Der Iconpatch ändert die Dateien: + * iconpatch.h + * menu.c + * recording.c + * fontosd.c + * + */ + +// Iconpatch-Variablen - Anfang +#define ICON_NUMBERSIGN "\x23" +#define ICON_ASTERISK "\x2A" +#define ICON_GREATER "\x3E" +#define ICON_EXCLAM "\x21" +#define ICON_PLUSMINUS "\xB1" + +#define ICON_RESUME "\x80" +#define ICON_DVD "\x81" +#define ICON_FOLDER "\x82" +#define ICON_BLANK "\x83" +#define ICON_CUTTING "\x84" +#define ICON_MOVE_FILE "\x85" +#define ICON_MOVE_FOLDER "\x86" +#define ICON_BAR_START "\x87" +#define ICON_BAR_FILLED "\x88" +#define ICON_BAR_CLEAR "\x89" +#define ICON_BAR_END "\x8A" +#define ICON_REC "\x8B" +#define ICON_CLOCK "\x8C" +#define ICON_TV_CRYPTED "\x8D" +#define ICON_RADIO "\x8E" +#define ICON_TV "\x8F" +#define ICON_NEW "\x90" +#define ICON_ARROW "\x91" +#define ICON_RUNNING "\x92" +#define ICON_VPS "\x93" +#define ICON_CLOCK_UH "\x94" +#define ICON_CLOCK_LH "\x95" + +// UTF-8 Icons +#define ICON_RESUME_UTF8 "\uE000" +#define ICON_DVD_UTF8 "\uE001" +#define ICON_FOLDER_UTF8 "\uE002" +#define ICON_BLANK_UTF8 "\uE003" +#define ICON_CUTTING_UTF8 "\uE004" +#define ICON_MOVE_FILE_UTF8 "\uE005" +#define ICON_MOVE_FOLDER_UTF8 "\uE006" +#define ICON_BAR_START_UTF8 "\uE007" +#define ICON_BAR_FILLED_UTF8 "\uE008" +#define ICON_BAR_EMPTY_UTF8 "\uE009" +#define ICON_BAR_CLOSE_UTF8 "\uE00A" +#define ICON_REC_UTF8 "\uE00B" +#define ICON_CLOCK_UTF8 "\uE00C" +#define ICON_TV_CRYPTED_UTF8 "\uE00D" +#define ICON_RADIO_UTF8 "\uE00E" +#define ICON_TV_UTF8 "\uE00F" +#define ICON_NEW_UTF8 "\uE010" +#define ICON_ARROW_UTF8 "\uE011" +#define ICON_RUNNING_UTF8 "\uE012" +#define ICON_VPS_UTF8 "\uE013" +#define ICON_CLOCK_UH_UTF8 "\uE014" +#define ICON_CLOCK_LH_UTF8 "\uE015" + +// Iconpatch-Variablen - Ende + +bool IsLangUtf8(void); + +#endif /* WAREAGLEICON */ diff -ruNp vdr-1.6.0-2/keys.h vdr-1.6.0-2-extensions/keys.h --- vdr-1.6.0-2/keys.h 2007-08-26 14:34:50.000000000 +0200 +++ vdr-1.6.0-2-extensions/keys.h 2009-04-09 20:48:26.000000000 +0200 @@ -71,6 +71,10 @@ enum eKeys { // "Up" and "Down" must be #define kEditCut k2 #define kEditTest k8 +#ifdef USE_DVDARCHIVE +#define kDvdChapterJumpForward k6 +#define kDvdChapterJumpBack k4 +#endif /* DVDARCHIVE */ #define RAWKEY(k) (eKeys((k) & ~k_Flags)) #define ISRAWKEY(k) ((k) != kNone && ((k) & k_Flags) == 0) #define NORMALKEY(k) (eKeys((k) & ~k_Repeat)) diff -ruNp vdr-1.6.0-2/lirc.c vdr-1.6.0-2-extensions/lirc.c --- vdr-1.6.0-2/lirc.c 2006-05-28 10:48:13.000000000 +0200 +++ vdr-1.6.0-2-extensions/lirc.c 2009-04-09 20:48:26.000000000 +0200 @@ -12,6 +12,9 @@ #include "lirc.h" #include #include +#ifdef USE_LIRCSETTINGS +#include "config.h" +#endif /* LIRCSETTINGS */ #define REPEATDELAY 350 // ms #define REPEATFREQ 100 // ms @@ -94,7 +97,11 @@ void cLircRemote::Action(void) continue; } if (count == 0) { +#ifdef USE_LIRCSETTINGS + if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) +#else if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < REPEATDELAY) +#endif /* LIRCSETTINGS */ continue; // skip keys coming in too fast if (repeat) Put(LastKeyName, false, true); @@ -104,18 +111,34 @@ void cLircRemote::Action(void) timeout = -1; } else { +#ifdef USE_LIRCSETTINGS + if (LastTime.Elapsed() < (unsigned int)Setup.LircRepeatFreq) +#else if (LastTime.Elapsed() < REPEATFREQ) +#endif /* LIRCSETTINGS */ continue; // repeat function kicks in after a short delay (after last key instead of first key) +#ifdef USE_LIRCSETTINGS + if (FirstTime.Elapsed() < (unsigned int)Setup.LircRepeatDelay) +#else if (FirstTime.Elapsed() < REPEATDELAY) +#endif /* LIRCSETTINGS */ continue; // skip keys coming in too fast (for count != 0 as well) repeat = true; +#ifdef USE_LIRCSETTINGS + timeout = Setup.LircRepeatDelay; +#else timeout = REPEATDELAY; +#endif /* LIRCSETTINGS */ } LastTime.Set(); Put(KeyName, repeat); } else if (repeat) { // the last one was a repeat, so let's generate a release +#ifdef USE_LIRCSETTINGS + if (LastTime.Elapsed() >= (unsigned int)Setup.LircRepeatTimeout) { +#else if (LastTime.Elapsed() >= REPEATTIMEOUT) { +#endif /* LIRCSETTINGS */ Put(LastKeyName, false, true); repeat = false; *LastKeyName = 0; diff -ruNp vdr-1.6.0-2/livebuffer.c vdr-1.6.0-2-extensions/livebuffer.c --- vdr-1.6.0-2/livebuffer.c 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/livebuffer.c 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,1912 @@ +#ifdef USE_LIVEBUFFER +#include "livebuffer.h" +#include "menu.h" +#include "recording.h" +#include "transfer.h" + +#define RECORDERBUFSIZE MEGABYTE(2) + +// --- cFileName ------------------------------------------------------------- + +#include +#include +#include "videodir.h" + +#define MAXFILESPERRECORDING 255 +#define RECORDFILESUFFIX "/%03d.vdr" +#define RECORDFILESUFFIXLEN 20 + +cFileName64::cFileName64(const char *FileName, bool Record, bool Blocking) +{ + file = NULL; + record = Record; + blocking = Blocking; + // Prepare the file name: + fileName = MALLOC(char, strlen(FileName) + RECORDFILESUFFIXLEN); + if (!fileName) { + esyslog("ERROR: can't copy file name '%s'", fileName); + return; + } + strcpy(fileName, FileName); + pFileNumber = fileName + strlen(fileName); + + fileNumber = 1; + while (true) { + sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); + if (record) { + if (access(fileName, F_OK) == 0) { + struct stat64 buf; + if (stat64(fileName, &buf) == 0) { + fileNumber++; + continue; + } + } + else if (errno != ENOENT) + LOG_ERROR_STR(fileName); + } + break; + } +} + +cFileName64::~cFileName64() +{ + Close(); + free(fileName); +} + +void cFileName64::SetNumber(int Number) +{ + fileNumber = Number; + sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber); +} + +cUnbufferedFile64 *cFileName64::Open(void) +{ + if (!file) { + int BlockingFlag = blocking ? 0 : O_NONBLOCK; + if (record) { + file = cUnbufferedFile64::Create(fileName, O_RDWR | O_CREAT | BlockingFlag); + if (!file) + LOG_ERROR_STR(fileName); + } + else { + if (access(fileName, R_OK) == 0) { + file = cUnbufferedFile64::Create(fileName, O_RDONLY | BlockingFlag); + if (!file) + LOG_ERROR_STR(fileName); + } + else if (errno != ENOENT) + LOG_ERROR_STR(fileName); + } + } + return file; +} + +void cFileName64::Close(void) +{ + if (file) { + if (file->Close() < 0) + LOG_ERROR_STR(fileName); + delete file; + file = NULL; + } +} + +void cFileName64::CloseAndRemove(void) +{ + Close(); + remove(fileName); +} + +// --- cUnbufferedFile64 ----------------------------------------------------- + +#define USE_FADVISE + +#define WRITE_BUFFER KILOBYTE(800) + +cUnbufferedFile64::cUnbufferedFile64(void) +{ + fd = -1; +} + +cUnbufferedFile64::~cUnbufferedFile64() +{ + Close(); +} + +int cUnbufferedFile64::Open(const char *FileName, int Flags, mode_t Mode) +{ + Close(); + fd = open64(FileName, Flags, Mode); + curpos = 0; +#ifdef USE_FADVISE + begin = lastpos = ahead = 0; + cachedstart = 0; + cachedend = 0; + readahead = KILOBYTE(128); + written = 0; + totwritten = 0; + if (fd >= 0) + posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); +#endif + return fd; +} + +int cUnbufferedFile64::Close(void) +{ +#ifdef USE_FADVISE + if (fd >= 0) { + if (totwritten) + fdatasync(fd); + posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); + } +#endif + int OldFd = fd; + fd = -1; + return close(OldFd); +} + + +#define FADVGRAN KILOBYTE(4) +#define READCHUNK MEGABYTE(8) + +int cUnbufferedFile64::FadviseDrop(off64_t Offset, off64_t Len) +{ + return posix_fadvise64(fd, Offset - (FADVGRAN - 1), Len + (FADVGRAN - 1) * 2, POSIX_FADV_DONTNEED); +} + + +off64_t cUnbufferedFile64::Seek(off64_t Offset, int Whence) +{ + if (Whence == SEEK_SET && Offset == curpos) + return curpos; + curpos = lseek64(fd, Offset, Whence); + return curpos; +} + +ssize_t cUnbufferedFile64::Read(void *Data, size_t Size) +{ + if (fd >= 0) { +#ifdef USE_FADVISE + off64_t jumped = curpos-lastpos; + if ((cachedstart < cachedend) && (curpos < cachedstart || curpos > cachedend)) { + FadviseDrop(cachedstart, cachedend-cachedstart); + cachedstart = curpos; + cachedend = curpos; + } + cachedstart = min(cachedstart, curpos); +#endif + ssize_t bytesRead = safe_read(fd, Data, Size); +#ifdef USE_FADVISE + if (bytesRead > 0) { + curpos += bytesRead; + cachedend = max(cachedend, curpos); + + if (jumped >= 0 && jumped <= (off64_t)readahead) { + if (ahead - curpos < (off64_t)(readahead / 2)) { + posix_fadvise64(fd, curpos, readahead, POSIX_FADV_WILLNEED); + ahead = curpos + readahead; + cachedend = max(cachedend, ahead); + } + if (readahead < Size * 32) { + readahead = Size * 32; + } + } + else + ahead = curpos; + } + + if (cachedstart < cachedend) { + if (curpos - cachedstart > READCHUNK * 2) { + FadviseDrop(cachedstart, curpos - READCHUNK - cachedstart); + cachedstart = curpos - READCHUNK; + } + else if (cachedend > ahead && cachedend - curpos > READCHUNK * 2) { + FadviseDrop(curpos + READCHUNK, cachedend - (curpos + READCHUNK)); + cachedend = curpos + READCHUNK; + } + } + lastpos = curpos; +#endif + return bytesRead; + } + return -1; +} + +ssize_t cUnbufferedFile64::Write(const void *Data, size_t Size) +{ + if (fd >=0) { + ssize_t bytesWritten = safe_write(fd, Data, Size); +#ifdef USE_FADVISE + if (bytesWritten > 0) { + begin = min(begin, curpos); + curpos += bytesWritten; + written += bytesWritten; + lastpos = max(lastpos, curpos); + if (written > WRITE_BUFFER) { + if (lastpos > begin) { + off64_t headdrop = min(begin, (off64_t) WRITE_BUFFER * 2L); + posix_fadvise64(fd, begin - headdrop, lastpos - begin + headdrop, POSIX_FADV_DONTNEED); + } + begin = lastpos = curpos; + totwritten += written; + written = 0; + if (totwritten > MEGABYTE(32)) { + off64_t headdrop = min((off64_t) (curpos - totwritten), (off64_t) totwritten * 2L); + posix_fadvise64(fd, curpos - totwritten - headdrop, totwritten + headdrop, POSIX_FADV_DONTNEED); + totwritten = 0; + } + } + } +#endif + return bytesWritten; + } + return -1; +} + +cUnbufferedFile64 *cUnbufferedFile64::Create(const char *FileName, int Flags, mode_t Mode) +{ + cUnbufferedFile64 *File = new cUnbufferedFile64; + if (File->Open(FileName, Flags, Mode) < 0) { + delete File; + File = NULL; + } + return File; +} + +// --- cLiveIndex ------------------------------------------------------------ + +cLiveIndex::cLiveIndex(int BufSize) +{ + bufSize = BufSize; + headblock = tailblock = new block; + headblock->previous = headblock->next = headblock; + head = tail = 0; + blank = 0; + blockCount = 1; + writtenCount = delCount = 0; + lastWrittenSize = lastCount = 0; + fileSize = 0; + lastFrame = -1; + DPos = -1; + DCount = 0; + start = 0; + RwLock = new cRwLock(true); +} + +cLiveIndex::~cLiveIndex() +{ + while (tailblock != headblock) { + block *n = tailblock->next; + delete tailblock; + tailblock = n; + } + delete headblock; + delete RwLock; +} + +void cLiveIndex::Add(uchar pt, int pos) +{ + RwLock->Lock(true); + DCount=0; + DPos = pos; + headblock->Frame[head].offset = pos; + headblock->Frame[head].written = false; + headblock->Frame[head].pt = pt; + head++; + lastFrame++; + if (head == INDEXBLOCKSIZE) { + block* b = new block; + b->previous = headblock; + b->next = b; + headblock->next = b; + headblock = b; + head = 0; + blockCount++; + } + RwLock->Unlock(); +} + +void cLiveIndex::AddData(int pos) +{ + RwLock->Lock(true); + DCount=pos-DPos; + RwLock->Unlock(); +} + +void cLiveIndex::Delete(off64_t FilePos) +{ + RwLock->Lock(true); + if (tailblock->Frame[tail].offset <= FilePos) { + if (tailblock->Frame[tail].offset + MAXFRAMESIZE >= FilePos) { + int old_offset = tailblock->Frame[tail].offset; + while (tailblock->Frame[tail].written && tailblock->Frame[tail].offset < FilePos && tailblock->Frame[tail].offset >= old_offset) { + tail++; + delCount++; + if (tail == INDEXBLOCKSIZE) { + block *b = tailblock->next; + b->previous = b; + if (tailblock != headblock) + delete tailblock; + tailblock = b; + tail = 0; + blockCount--; + } + } + } + } + else { + if (tailblock->Frame[tail].offset - MAXFRAMESIZE > FilePos) { + int old_offset = tailblock->Frame[tail].offset; + while (tailblock->Frame[tail].written && (tailblock->Frame[tail].offset < FilePos || tailblock->Frame[tail].offset >= old_offset)) { + tail++; + delCount++; + if (tail == INDEXBLOCKSIZE) { + block *b = tailblock->next; + b->previous = b; + if (tailblock != headblock) + delete tailblock; + tailblock = b; + tail = 0; + blockCount--; + } + } + } + } + RwLock->Unlock(); +} + +int cLiveIndex::DelFirst(void) +{ + RwLock->Lock(true); + tail++; + delCount++; + writtenCount++; + if (tail == INDEXBLOCKSIZE) { + block *b = tailblock->next; + b->previous = b; + if (tailblock != headblock) + delete tailblock; + tailblock = b; + tail = 0; + blockCount--; + } + int r = tailblock->Frame[tail].offset; + RwLock->Unlock(); + return r; +} + +void cLiveIndex::Clear(void) +{ + RwLock->Lock(true); + while (tailblock != headblock) { + block *n = tailblock->next; + delete tailblock; + tailblock = n; + } + headblock->previous = headblock; + head = tail = blank = 0; + blockCount = 1; + writtenCount = delCount = 0; + DPos = -1; + DCount = 0; + start = 0; + lastFrame = -1; + lastWrittenSize = lastCount = 0; + fileSize = 0; + RwLock->Unlock(); +} + +int cLiveIndex::NextWrite(void) +{ + RwLock->Lock(false); + block *b; + int i = GetFrame(&b,writtenCount); + int off = 0; + if (i+1 == INDEXBLOCKSIZE) + off = b->next->Frame[0].offset; + else + off = b->Frame[i+1].offset; + int r = 0; + if (off < b->Frame[i].offset) + r = bufSize - b->Frame[i].offset - blank; + else + r = off - b->Frame[i].offset; + RwLock->Unlock(); + return r; +} + +void cLiveIndex::WrittenTo(off64_t FilePos, int Count) +{ + RwLock->Lock(true); + lastWrittenSize=Count; + block *b; + int i = GetFrame(&b, writtenCount); + writtenCount++; + if (FilePos == 0) { + if (i) + fileSize = b->Frame[i-1].offset + lastCount; + else if (b->previous != b) + fileSize = b->previous->Frame[INDEXBLOCKSIZE-1].offset + lastCount; + } + b->Frame[i].offset = FilePos; + b->Frame[i].written = true; + RwLock->Unlock(); + lastCount = Count; +} + +int cLiveIndex::GetFrame(block** Block, int Number) +{ + int bc = 0; + int i = Number-delCount; + if (INDEXBLOCKSIZE-tail <= i) + bc = 1 + (i-INDEXBLOCKSIZE+tail)/INDEXBLOCKSIZE; + i-= bc*INDEXBLOCKSIZE-tail; + block *b = tailblock; + for (int j=0; jnext; + *Block = b; + return i; +} + +off64_t cLiveIndex::GetOffset(int Number) +{ + RwLock->Lock(false); + off64_t r = -1; + if (HasFrame(Number)) { + block *b; + int i = GetFrame(&b, Number); + r = b->Frame[i].offset; + } + else if (HasFrame(Number-1)) + r = DPos; + RwLock->Unlock(); + return r; +} + +int cLiveIndex::Size(int Number, uchar *PictureType) +{ + int r = -1; + RwLock->Lock(false); + if (HasFrame(Number)) { + if (Number+1 == writtenCount) + r = lastWrittenSize; + else { + block *b; + int i = GetFrame(&b, Number); + if (PictureType) + *PictureType = b->Frame[i].pt; + off64_t off = 0; + if (i+1 == INDEXBLOCKSIZE) + off = b->next->Frame[0].offset; + else + off = b->Frame[i+1].offset; + if (off < b->Frame[i].offset) { + if (b->Frame[i].written) + r = fileSize - b->Frame[i].offset; + else + r = bufSize - b->Frame[i].offset - blank; + } + else + r = off - b->Frame[i].offset; + } + } + else if (HasFrame(Number-1) && DPos >= 0) + r = DCount; + RwLock->Unlock(); + return r; +} + +int cLiveIndex::GetNextIFrame(int Index, bool Forward) +{ + int d = Forward ? 1 : -1; + Index += d; + while (Index >= delCount && Index < lastFrame) { + block *b; + RwLock->Lock(false); + int i = GetFrame(&b, Index); + uchar type = b->Frame[i].pt; + RwLock->Unlock(); + if (type == I_FRAME) + return Index; + Index +=d; + } + return -1; +} + +int cLiveIndex::FindIFrame(int64_t PTS, uchar *Buffer) +{ + int r = -1; + RwLock->Lock(false); + int Index=writtenCount; + int64_t pts=0; + do { + Index = GetNextIFrame(Index, true); + if (Index < 0) + break; + block *b; + int i = GetFrame(&b, Index); + uchar *p = &Buffer[b->Frame[i].offset]; + if (p[0]==0x00 && p[1]==0x00 && p[2]==0x01 && (p[7] & 0x80) && p[3]>=0xC0 && p[3]<=0xEF) { + pts = (int64_t) (p[ 9] & 0x0E) << 29 ; + pts |= (int64_t) p[ 10] << 22 ; + pts |= (int64_t) (p[ 11] & 0xFE) << 14 ; + pts |= (int64_t) p[ 12] << 7 ; + pts |= (int64_t) (p[ 13] & 0xFE) >> 1 ; + } + } while (pts!=PTS); + if (pts==PTS) + r = Index; + RwLock->Unlock(); + return r; +} + +void cLiveIndex::Switched(void) +{ + start = Last(); +} + +// --- cLiveFileReader ------------------------------------------------------- + +cLiveFileReader::cLiveFileReader(const char *FileName, int Number) +{ + fileName = new cFileName64(FileName, false); + fileName->SetNumber(Number); + readFile = fileName->Open(); + buffer = NULL; + filePos = 0; + Start(); +} + +cLiveFileReader::~cLiveFileReader() +{ + Cancel(3); + delete fileName; +} + +void cLiveFileReader::Action(void) +{ + while (Running()) { + Lock(); + if (buffer && !hasData) { + int r = readFile->Read(buffer + length, wanted - length); + if (r >= 0) { + length += r; + filePos += r; + if (length == wanted) + hasData = true; + } + else if (r < 0 && FATALERRNO) { + LOG_ERROR; + length = r; + hasData = true; + } + } + Unlock(); + newSet.Wait(1000); + } +} + +int cLiveFileReader::Read(uchar **Buffer, off64_t FilePos, int Size) +{ + if (buffer && hasData) { + *Buffer = buffer; + buffer = NULL; + return length; + } + if (!buffer) { + uchar *b = MALLOC(uchar, Size); + if (filePos != FilePos) { + filePos = FilePos; + readFile->Seek(FilePos,0); + } + wanted = Size; + length = 0; + hasData = false; + buffer = b; + newSet.Signal(); + } + return -1; +} + +void cLiveFileReader::Clear(void) +{ + Lock(); + delete buffer; + buffer = NULL; + Unlock(); +} + +// --- cLiveFileWriter ------------------------------------------------------- + +cLiveFileWriter::cLiveFileWriter(const char *FileName) +{ + MakeDirs(FileName, true); + SpinUpDisk(FileName); + fileName = new cFileName64(FileName, true); + writeFile = fileName->Open(); + buffer = NULL; + filePos = fileSize = 0; + lastCheck = time(NULL); + full = false; + Start(); +} + +cLiveFileWriter::~cLiveFileWriter() +{ + Cancel(3); + fileName->CloseAndRemove(); + delete fileName; +} + +void cLiveFileWriter::Action(void) +{ + while (Running()) { + Lock(); + if (buffer && !hasWritten) { + int r = writeFile->Write(buffer, wantWrite); + if (r >= 0) { + filePos += r; + hasWritten = true; + } + else if (r < 0 && FATALERRNO) { + LOG_ERROR; + hasWritten = true; + } + } + Unlock(); + newSet.Wait(1000); + } +} + +#define MINFREE 600 + +bool cLiveFileWriter::LowDiskSpace() +{ + if (!full && time (NULL) > lastCheck + 60 || full && filePos >= fileSize) { + int Free = FreeDiskSpaceMB(fileName->Name()); + lastCheck = time(NULL); + if (Free < MINFREE) + return true; + } + return false; +} + +off64_t cLiveFileWriter::Write(uchar *Buffer, int Size, bool Wait) +{ + if (buffer && hasWritten) { + buffer = NULL; + return filePos; + } + if (!buffer) { + if (filePos + Size > (off64_t)Setup.LiveBufferSize*1024*1024 || LowDiskSpace()) { + fileSize = filePos > fileSize ? filePos : fileSize; + filePos = 0; + writeFile->Seek(0,0); + full = true; + } + if (Wait) { + writeFile->Write(Buffer, Size); + filePos += Size; + return filePos; + } + else { + wantWrite = Size; + hasWritten = false; + buffer = Buffer; + newSet.Signal(); + } + } + if (Wait) { + while (!hasWritten) + usleep(5); + buffer = NULL; + return filePos; + } + return -1; +} + +void cLiveFileWriter::Clear(void) +{ + Lock(); + buffer = NULL; + filePos = 0; + full = false; + writeFile->Seek(0,0); + Unlock(); +} + +// --- cLiveCutterThread ----------------------------------------------------- + +cLiveCutterThread::cLiveCutterThread(const char *FileName, int FileNumber, cLiveBuffer *LiveBuffer, int StartFrame, int EndFrame) +{ + readFile = NULL; + + writeFileName = new cFileName64(FileName, true); + writeFileName->SetNumber(FileNumber); + writeFile = writeFileName->Open(); + + liveBuffer = LiveBuffer; + startFrame = StartFrame; + endFrame = EndFrame; + Start(); +} + +cLiveCutterThread::~cLiveCutterThread() +{ + Cancel(3); + if (readFile) + readFileName->Close(); + writeFileName->Close(); +} + +void cLiveCutterThread::Action(void) +{ + int Frame = startFrame; + int readPos = 0; + int writePos = 0; + while (Running() && Frame < endFrame) { + uchar pt; + liveBuffer->index->RwLock->Lock(false); + int size = liveBuffer->index->Size(Frame, &pt); + if (pt == I_FRAME && writePos > MEGABYTE(Setup.MaxVideoFileSize)) { + int Number = writeFileName->Number(); + writeFileName->Close(); + writeFileName->SetNumber(Number+1); + writeFile = writeFileName->Open(); + writePos = 0; + } + if (liveBuffer->index->IsWritten(Frame)) { + if (!readFile) { + readFileName = new cFileName64(liveBuffer->filestring, false); + readFileName->SetNumber(liveBuffer->fileWriter->FileNumber()); + readFile = readFileName->Open(); + } + uchar b[MAXFRAMESIZE]; + if (liveBuffer->index->GetOffset(Frame) != readPos) { + readPos = liveBuffer->index->GetOffset(Frame); + readFile->Seek(readPos,0); + } + int c = readFile->Read(b, size); + readPos += c; + writeFile->Write(b,c); + writePos+=size; + if (c != size) + writeFile->Seek(writePos,0); + } + else { + writeFile->Write(&liveBuffer->buffer[liveBuffer->index->GetOffset(Frame)], size); + writePos+=size; + } + liveBuffer->index->RwLock->Unlock(); + Frame++; + cCondWait::SleepMs(5); + } + if (readFile) + readFileName->Close(); + writeFileName->Close(); +} + +// --- cLiveBuffer ----------------------------------------------------------- + +cLiveBuffer::cLiveBuffer(const char *FileName, cRemux *Remux, const cChannel *Channel, int Number) +:cThread("livebuffer") +{ + number = Number; + bufSize = (Setup.InRAM && Number == 0) ? MEGABYTE(Setup.MemBufSize) : LIVEBUFSIZE; + buffer = MALLOC(uchar, bufSize); + writeHD = !(Setup.InRAM && Number == 0); + lastRead = 0; + if (!buffer) { + dsyslog("Couldn't reserve memory for livebuffer\n"); + bufSize = LIVEBUFSIZE; + buffer = MALLOC(uchar, bufSize); + } + channel = Channel; + index = new cLiveIndex(bufSize); + remux = Remux; + filestring = strdup(FileName); + head = tail = blank = 0; + startFrame = -1; + liveCutter = NULL; + fileWriter = NULL; + fileReader = NULL; + if (writeHD) { + fileWriter = new cLiveFileWriter(FileName); + fileReader = new cLiveFileReader(FileName, fileWriter->FileNumber()); + } + status = 0; + Start(); +} + +cLiveBuffer::~cLiveBuffer() +{ + Cancel(3); + delete liveCutter; + delete fileReader; + delete index; + delete fileWriter; + free(filestring); + free(buffer); +} + +void cLiveBuffer::SetStatus(int s) +{ + if (s == -1 || status != 2 && s == 0) + status = 0; + if (status == 0 && s == 1) + status = 1; + if (s == 2) + status = 2; + if (s == -2 && status == 0) + status = -1; +} + +void cLiveBuffer::Write(bool Wait) +{ + int wcount = index->NextWrite(); + off64_t pos=fileWriter->Write(&buffer[tail], wcount, Wait); + if (pos>=0) { + index->WrittenTo(pos-wcount, wcount); + tail += wcount; + if (tail + MAXFRAMESIZE > bufSize) { + tail = 0; + blank = 0; + index->SetBlank(blank); + } + if (fileWriter->Full()) + index->Delete(pos); + } +} + +void cLiveBuffer::Store(uchar *Data, int Count) +{ + + if (pictureType != NO_PICTURE) { + if (head + MAXFRAMESIZE > bufSize) { + blank = bufSize - head; + head = 0; + index->SetBlank(blank); + } + index->Add(pictureType,head); + } + else + index->AddData(head); + memcpy(&buffer[head], Data, Count); + head += Count; + + int free = head >= tail ? max(tail,bufSize-head) : tail - head; + + while (free < MAXFRAMESIZE) { + if (writeHD) + Write(true); + else { + tail = index->DelFirst(); + if (tail == 0) { + blank = 0; + index->SetBlank(blank); + } + if (Setup.ExtendBuffer && lastRead < index->delCount+25 && status >= 0) { + writeHD = true; + fileWriter = new cLiveFileWriter(filestring); + fileReader = new cLiveFileReader(filestring, fileWriter->FileNumber()); + } + } + free = head >= tail ? max(tail,bufSize-head) : tail - head; + } +} + +void cLiveBuffer::Action(void) +{ + while (Running()) { + int Count; + Lock(); + uchar *p = remux->Get(Count, &pictureType); + if (p) { + Store(p,Count); + remux->Del(Count); + } + Unlock(); + if (writeHD) { + int free = head >= tail ? max(tail,bufSize-head) : tail - head; + if (free < 2*MAXFRAMESIZE) + Write(false); + } + } + +} + +void cLiveBuffer::SetNewRemux(cRemux *Remux, const cChannel *Channel) +{ + if (Channel != channel) { + index->Switched(); + } + channel = Channel; + if (!Remux) { + Cancel(3); + return; + } + if (fileReader) fileReader->Clear(); + if (!Running() && Remux) { + remux = Remux; + Start(); + } + else { + Cancel(-1); + Lock(); + if (writeHD && Setup.InRAM && number == 0 && !status) { + index->Clear(); + delete fileReader; fileReader = NULL; + delete fileWriter; fileWriter = NULL; + writeHD = false; + } + remux = Remux; + Unlock(); + Start(); + } +} + +int cLiveBuffer::GetFrame(uchar **Buffer, int Number, int Off) +{ + if (!Buffer) { + if (fileReader) fileReader->Clear(); + return -1; + } + if (Number < FirstIndex()) + return -2; + if (!index->HasFrame(Number) && (Off < 0 || !index->HasFrame(Number-1))) + return -1; + lastRead = Number; + if (!index->IsWritten(Number)) { + index->RwLock->Lock(false); + int size=index->Size(Number); + int off = index->GetOffset(Number); + if (off >= 0) { + if (Off>=0) { + size -= Off; + off += Off; + } + if (size > 0) { + uchar *b = MALLOC(uchar, size); + *Buffer = b; + memcpy(b,&buffer[off],size); + } + if (!index->HasFrame(Number)) + size = -size; + } + else + size = -1; + index->RwLock->Unlock(); + return size; + } + else + return fileReader->Read(Buffer,index->GetOffset(Number),index->Size(Number)); + return -1; +} + +void cLiveBuffer::CreateIndexFile(const char *FileName, int64_t PTS, int EndFrame) +{ + if (liveCutter) { + if (liveCutter->Active()) { + startFrame = -1; + return; + } + else { + delete liveCutter; + liveCutter = NULL; + } + } + if (startFrame < 0) + return; + cIndexFile *indexFile = new cIndexFile(FileName, true); + if (!indexFile) + return; + int endFrame = EndFrame ? EndFrame : index->FindIFrame(PTS, buffer); + int timeout = 0; + while (endFrame < 0 && timeout < 50) { + cCondWait::SleepMs(100); + endFrame = index->FindIFrame(PTS, buffer); + timeout++; + } + + char *data="LiveBuffer"; + cFileName fileName(FileName, true); + cUnbufferedFile *file = fileName.Open(); + file->Write(data,10); + int Number = fileName.Number(); + int FileOffset=0; + for (int Frame = startFrame; Frame < endFrame; Frame++) { + uchar pt; + int size = index->Size(Frame, &pt); + if (pt == I_FRAME && FileOffset > MEGABYTE(Setup.MaxVideoFileSize)) { + file = fileName.NextFile(); + file->Write(data,10); + FileOffset=0; + } + indexFile->Write(pt,fileName.Number(),FileOffset); + FileOffset+=size; + } + liveCutter = new cLiveCutterThread(FileName,Number,this,startFrame,endFrame); + startFrame = -1; + delete indexFile; +} + +// --- cLiveReceiver --------------------------------------------------------- + +cLiveReceiver::cLiveReceiver(const cChannel *Channel) +:cReceiver(Channel->GetChannelID(), -1, Channel->Vpid(), Channel->Apids(), Setup.UseDolbyDigital ? Channel->Dpids() : NULL, Channel->Spids()) +{ + channel = Channel; + vpid = Channel->Vpid(); + for (int i = 0; i < MAXAPIDS; i++) + apids[i]=Channel->Apid(i); + for (int i = 0; i < MAXDPIDS; i++) + dpids[i]= Setup.UseDolbyDigital ? Channel->Dpid(i) : 0; + for (int i = 0; i < MAXSPIDS; i++) + spids[i]=Channel->Spid(i); + ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder"); + ringBuffer->SetTimeouts(0, 20); + remux = new cRemux(Channel->Vpid(), Channel->Apids(), Setup.UseDolbyDigital ? Channel->Dpids() : NULL, Channel->Spids()); + remux->SetTimeouts(0, 50); + attached = false; +} + +cLiveReceiver::~cLiveReceiver() +{ + Detach(); + Cancel(3); + delete remux; + delete ringBuffer; +} + +void cLiveReceiver::Activate(bool On) +{ + if (On) { + Start(); + attached = true; + } + else { + Cancel(-1); + attached = false; + } +} + +void cLiveReceiver::Receive(uchar *Data, int Length) +{ + int p = ringBuffer->Put(Data, Length); + if (p != Length && Running()) + ringBuffer->ReportOverflow(Length - p); +} + +void cLiveReceiver::Action(void) +{ + while (Running()) { + int r; + uchar *b = ringBuffer->Get(r); + if (b) { + int Count = remux->Put(b, r); + if (Count) + ringBuffer->Del(Count); + else + cCondWait::SleepMs(20); + } + } +} + +bool cLiveReceiver::IsReceiving(const cChannel *Channel) +{ + if (vpid != Channel->Vpid()) + return false; + for (int i = 0; i < MAXAPIDS; i++) + if (apids[i] != Channel->Apid(i)) + return false; + for (int i = 0; i < MAXDPIDS && Setup.UseDolbyDigital; i++) + if (dpids[i] != Channel->Dpid(i)) + return false; + for (int i = 0; i < MAXSPIDS; i++) + if (spids[i] != Channel->Spid(i)) + return false; + + return true; +} + +// --- cLiveBackTrace -------------------------------------------------------- + +#define AVG_FRAME_SIZE 15000 +#define DVB_BUF_SIZE (256 * 1024) +#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) + +class cLiveBackTrace { +private: + int index[BACKTRACE_ENTRIES]; + int length[BACKTRACE_ENTRIES]; + int pos, num; +public: + cLiveBackTrace(void); + void Clear(void); + void Add(int Index, int Length); + int Get(bool Forward); + }; + +cLiveBackTrace::cLiveBackTrace(void) +{ + Clear(); +} + +void cLiveBackTrace::Clear(void) +{ + pos = num = 0; +} + +void cLiveBackTrace::Add(int Index, int Length) +{ + index[pos] = Index; + length[pos] = Length; + if (++pos >= BACKTRACE_ENTRIES) + pos = 0; + if (num < BACKTRACE_ENTRIES) + num++; +} + +int cLiveBackTrace::Get(bool Forward) +{ + int p = pos; + int n = num; + int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); + int i = -1; + + while (n && l > 0) { + if (--p < 0) + p = BACKTRACE_ENTRIES - 1; + i = index[p] - 1; + l -= length[p]; + n--; + } + return i; +} + +// --- cLivePlayer ----------------------------------------------------------- + +#define PLAYERBUFSIZE MEGABYTE(1) + +#define MAX_VIDEO_SLOWMOTION 63 +#define NORMAL_SPEED 4 +#define MAX_SPEEDS 3 +#define SPEED_MULT 12 +int cLivePlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; + +cLivePlayer::cLivePlayer(cLiveBuffer *LiveBuffer) +:cThread("liveplayer") +{ + liveBuffer = LiveBuffer; + ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE); + readIndex = writeIndex = -1; + readFrame = playFrame = NULL; + firstPacket = true; + playMode = pmPlay; + playDir = pdForward; + trickSpeed = NORMAL_SPEED; + Off = 0; + backTrace = new cLiveBackTrace; + liveBuffer->SetStatus(0); +} + +cLivePlayer::~cLivePlayer() +{ + liveBuffer->SetStatus(-2); + Detach(); + Cancel(3); + liveBuffer->GetFrame(NULL,0); + delete readFrame; + delete backTrace; + delete ringBuffer; +} + +void cLivePlayer::TrickSpeed(int Increment) +{ + int nts = trickSpeed + Increment; + if (Speeds[nts] == 1) { + trickSpeed = nts; + if (playMode == pmFast) + Play(); + else + Pause(); + } + else if (Speeds[nts]) { + trickSpeed = nts; + int Mult = (playMode == pmSlow && playDir == pdForward) ? 1 : SPEED_MULT; + int sp = (Speeds[nts] > 0) ? Mult / Speeds[nts] : -Speeds[nts] * Mult; + if (sp > MAX_VIDEO_SLOWMOTION) + sp = MAX_VIDEO_SLOWMOTION; + DeviceTrickSpeed(sp); + } +} + +void cLivePlayer::Empty(void) +{ + LOCK_THREAD; + liveBuffer->GetFrame(NULL,0); + if ((readIndex = backTrace->Get(playDir == pdForward)) < 0) + readIndex = writeIndex; + delete readFrame; + readFrame = NULL; + playFrame = NULL; + ringBuffer->Clear(); + DeviceClear(); + backTrace->Clear(); + firstPacket = true; + Off = 0; +} + +void cLivePlayer::Activate(bool On) +{ + if (On) + Start(); + else + Cancel(-1); +} + +void cLivePlayer::Action(void) +{ + int PollTimeouts = 0; + uchar *b = NULL; + uchar **pb = &b; + uchar *p = NULL; + int pc = 0; + + if (liveBuffer->Stay()) + readIndex = liveBuffer->LastRead(); + else + readIndex = liveBuffer->LastIndex(); + + bool Sleep = false; + bool WaitingForData = false; + + while (Running()) { + if (Sleep) { + if (WaitingForData) + cCondWait::SleepMs(3); + else + cCondWait::SleepMs(3); + Sleep = false; + } + + cPoller Poller; + if (!DevicePoll(Poller, 100)) { + PollTimeouts++; + continue; + } + else + PollTimeouts = 0; + + if (PollTimeouts >= 6) { + DeviceClear(); + PlayPes(NULL, 0); + } + + LOCK_THREAD; + + if (playMode != pmStill && playMode != pmPause) { + if (!readFrame) { + if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { + int Index = liveBuffer->GetNextIFrame(readIndex, playDir == pdForward); + if (Index < 0) { + if (!DeviceFlush(100)) + continue; + DevicePlay(); + playMode = pmPlay; + playDir = pdForward; + continue; + } + int r = liveBuffer->GetFrame(pb, Index); + if (r>0) { + readIndex = Index; + WaitingForData = false; + readFrame = new cFrame(b, -r, ftUnknown, readIndex); + b = NULL; + } + else + WaitingForData = true; + } + else { + int r=liveBuffer->GetFrame(pb, readIndex+1, Off); + if (r>0) + readIndex++; + if (r > 0 || r < -10) { + WaitingForData = false; + readFrame = new cFrame(b, -abs(r), ftUnknown, readIndex); + b = NULL; + if (r<0) + Off += -r; + else + Off = 0; + } + else if (r==-2) + readIndex = liveBuffer->GetNextIFrame(liveBuffer->FirstIndex(), true)-1; + else + WaitingForData = true; + } + } + if (readFrame) { + if (ringBuffer->Put(readFrame)) + readFrame = NULL; + } + } + else + Sleep = true; + if (!playFrame) { + playFrame = ringBuffer->Get(); + p = NULL; + pc = 0; + } + if (playFrame) { + if (!p) { + p = playFrame->Data(); + pc = playFrame->Count(); + if (p) { + if (firstPacket) { + PlayPes(NULL, 0); + cRemux::SetBrokenLink(p, pc); + firstPacket = false; + } + } + } + if (p) { + int w = PlayPes(p, pc, playMode != pmPlay); + if (w > 0) { + p += w; + pc -= w; + } + else { + if (w < 0 && FATALERRNO) { + LOG_ERROR; + break; + } + } + } + if (pc == 0) { + writeIndex = playFrame->Index(); + backTrace->Add(playFrame->Index(), playFrame->Count()); + ringBuffer->Drop(playFrame); + playFrame = NULL; + p = NULL; + } + } + else + Sleep = true; + } +} + +void cLivePlayer::Pause(void) +{ + if (playMode == pmPause || playMode == pmStill) + Play(); + else { + liveBuffer->SetStatus(1); + LOCK_THREAD; + if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) + Empty(); + DeviceFreeze(); + playMode = pmPause; + } +} + +void cLivePlayer::Play(void) +{ + if (playMode != pmPlay) { + liveBuffer->SetStatus(0); + LOCK_THREAD; + if (playMode == pmStill || playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) + Empty(); + DevicePlay(); + playMode = pmPlay; + playDir = pdForward; + } +} + +void cLivePlayer::Forward(void) +{ + switch (playMode) { + case pmFast: + if (Setup.MultiSpeedMode) { + TrickSpeed(playDir == pdForward ? 1 : -1); + break; + } + else if (playDir == pdForward) { + Play(); + break; + } + case pmPlay: { + LOCK_THREAD; + Empty(); + DeviceMute(); + playMode = pmFast; + playDir = pdForward; + trickSpeed = NORMAL_SPEED; + TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); + } + break; + case pmSlow: + if (Setup.MultiSpeedMode) { + TrickSpeed(playDir == pdForward ? -1 : 1); + break; + } + else if (playDir == pdForward) { + Pause(); + break; + } + case pmStill: + case pmPause: + DeviceMute(); + playMode = pmSlow; + playDir = pdForward; + trickSpeed = NORMAL_SPEED; + TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); + break; + } +} + +void cLivePlayer::Backward(void) +{ + switch (playMode) { + case pmFast: + if (Setup.MultiSpeedMode) { + TrickSpeed(playDir == pdBackward ? 1 : -1); + break; + } + else if (playDir == pdBackward) { + Play(); + break; + } + case pmPlay: { + LOCK_THREAD; + Empty(); + DeviceMute(); + playMode = pmFast; + playDir = pdBackward; + trickSpeed = NORMAL_SPEED; + TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS); + } + break; + case pmSlow: + if (Setup.MultiSpeedMode) { + TrickSpeed(playDir == pdBackward ? -1 : 1); + break; + } + else if (playDir == pdBackward) { + Pause(); + break; + } + case pmStill: + case pmPause: { + LOCK_THREAD; + Empty(); + DeviceMute(); + playMode = pmSlow; + playDir = pdBackward; + trickSpeed = NORMAL_SPEED; + TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS); + } + break; + } +} + +bool cLivePlayer::Stop(void) +{ + liveBuffer->SetStatus(-1); + if (readIndex >= liveBuffer->LastIndex() - 25) + return false; + LOCK_THREAD; + Empty(); + readIndex = writeIndex = liveBuffer->GetNextIFrame(liveBuffer->LastIndex()-1, false)-1; + Play(); + return true; +} + +void cLivePlayer::SkipSeconds(int Seconds) +{ + if (Seconds) { + LOCK_THREAD; + Empty(); + int Index = writeIndex; + if (Index >= 0) { + Index = max(Index + Seconds * FRAMESPERSEC, liveBuffer->FirstIndex()); + if (Index > liveBuffer->FirstIndex()) + Index = liveBuffer->GetNextIFrame(Index, false); + if (Index >= 0) + readIndex = writeIndex = Index - 1; + } + Play(); + } +} + +bool cLivePlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame) +{ + if (liveBuffer) { + if (playMode == pmStill) + Current = max(readIndex, 0); + else { + Current = max(writeIndex, 0); + // TODO SnapToIFrame + } + Total = liveBuffer->LastIndex() - liveBuffer->FirstIndex(); + Current -= liveBuffer->FirstIndex(); + return true; + } + Current = Total = -1; + return false; +} + +bool cLivePlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed) +{ + Play = (playMode == pmPlay || playMode == pmFast); + Forward = (playDir == pdForward); + if (playMode == pmFast || playMode == pmSlow) + Speed = Setup.MultiSpeedMode ? abs(trickSpeed - NORMAL_SPEED) : 0 ; + else + Speed = -1; + return true; +} + +// --- cLiveBufferControl ---------------------------------------------------- + +cLiveBufferControl::cLiveBufferControl(cLivePlayer *Player) +:cControl(Player, true) +{ + player = Player; + displayReplay = NULL; + visible = modeOnly = shown = false; + lastCurrent = lastTotal = -1; + lastPlay = lastForward = false; + lastSpeed = -2; + timeoutShow = 0; +} + +cLiveBufferControl::~cLiveBufferControl() +{ + Hide(); + cTransferControl::receiverDevice = NULL; + cLiveBufferManager::livePlayer = NULL; + delete player; + cLiveBufferManager::liveControl = NULL; + if (!Setup.LiveBuffer) + cLiveBufferManager::Shutdown(); +} + +bool cLiveBufferControl::GetIndex(int &Current, int &Total, bool SnapToIFrame) +{ + if (player) { + player->GetIndex(Current, Total, SnapToIFrame); + return true; + } + return false; + +} + +bool cLiveBufferControl::GetReplayMode(bool &Play, bool &Forward, int &Speed) +{ + return player && player->GetReplayMode(Play, Forward, Speed); +} + +void cLiveBufferControl::ShowTimed(int Seconds) +{ + if (modeOnly) + Hide(); + if (!visible) { + shown = ShowProgress(true); + timeoutShow = (shown && Seconds > 0) ? time(NULL) + Seconds : 0; + } +} + +void cLiveBufferControl::Show(void) +{ + ShowTimed(); +} + +void cLiveBufferControl::Hide(void) +{ + if (visible) { + delete displayReplay; + displayReplay = NULL; + SetNeedsFastResponse(false); + visible = false; + modeOnly = false; + lastPlay = lastForward = false; + lastSpeed = -2; // an invalid value +// timeSearchActive = false; + } +} + +void cLiveBufferControl::ShowMode(void) +{ + if (visible || Setup.ShowReplayMode && !cOsd::IsOpen()) { + bool Play, Forward; + int Speed; + if (GetReplayMode(Play, Forward, Speed) && (!visible || Play != lastPlay || Forward != lastForward || Speed != lastSpeed)) { + bool NormalPlay = (Play && Speed == -1); + + if (!visible) { + if (NormalPlay) + return; + visible = modeOnly = true; + displayReplay = Skins.Current()->DisplayReplay(modeOnly); + } + + if (modeOnly && !timeoutShow && NormalPlay) + timeoutShow = time(NULL) + 3; + displayReplay->SetMode(Play, Forward, Speed); + lastPlay = Play; + lastForward = Forward; + lastSpeed = Speed; + } + } +} + +bool cLiveBufferControl::ShowProgress(bool Initial) +{ + int Current, Total; + + if (GetIndex(Current, Total) && Total > 0) { + if (!visible) { + displayReplay = Skins.Current()->DisplayReplay(modeOnly); + SetNeedsFastResponse(true); + visible = true; + } + if (Initial) { + lastCurrent = lastTotal = -1; + } + if (Total != lastTotal) { + displayReplay->SetTotal(IndexToHMSF(Total)); + if (!Initial) + displayReplay->Flush(); + } + if (Current != lastCurrent || Total != lastTotal) { + displayReplay->SetProgress(Current, Total); + if (!Initial) + displayReplay->Flush(); +int displayFrames = false; + displayReplay->SetCurrent(IndexToHMSF(Current, displayFrames)); + displayReplay->Flush(); + lastCurrent = Current; + } + lastTotal = Total; + ShowMode(); + return true; + } + return false; +} + +eOSState cLiveBufferControl::ProcessKey(eKeys Key) +{ + if (visible) { + if (timeoutShow && time(NULL) > timeoutShow) { + Hide(); + ShowMode(); + timeoutShow = 0; + } + else if (modeOnly) + ShowMode(); + else + shown = ShowProgress(!shown) || shown; + } + bool DoShowMode = true; + switch (Key) { + case kDown: if (!visible || modeOnly) + return osUnknown; + case kPause: if (player) + player->Pause(); + break; + case kPlay: if (visible && !modeOnly) { + Hide(); + DoShowMode = true; + } + else + Show(); + case kUp: if (Key == kUp && (!visible || modeOnly)) + return osUnknown; + if (player) + player->Play(); + break; + case kLeft|k_Release: + if (!visible || modeOnly) + return osUnknown; + case kFastRew|k_Release: + if (Setup.MultiSpeedMode) break; + case kLeft: if (Key == kLeft && (!visible || modeOnly)) + return osUnknown; + case kFastRew: if (player) + player->Backward(); + break; + case kRight|k_Release: + if (!visible || modeOnly) + return osUnknown; + case kFastFwd|k_Release: + if (Setup.MultiSpeedMode) break; + case kRight: if (Key == kRight && (!visible || modeOnly)) + return osUnknown; + case kFastFwd: if (player) + player->Forward(); + break; + case kGreen|k_Repeat: + case kGreen: if (visible && !modeOnly && player) + player->SkipSeconds(-60); + else + return osUnknown; + break; + case kYellow|k_Repeat: + case kYellow: if (visible && !modeOnly && player) + player->SkipSeconds(60); + else + return osUnknown; + break; + default: { + DoShowMode = false; + switch (Key) { + case kStop: if (player) + if (player->Stop()) + break; + return osUnknown; + case kBack: if (visible && !modeOnly && player) + Hide(); + else + return osUnknown; + break; + case kRecord: { + cTimer *timer = new cTimer(true); + int Current, Total; + GetIndex(Current,Total); + time_t start = time(NULL) - (Total - Current) / FRAMESPERSEC; + time_t t = start; + struct tm tm_r; + struct tm *now = localtime_r(&t, &tm_r); + timer->start = now->tm_hour * 100 + now->tm_min; + timer->stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime; + timer->stop = (timer->stop / 60) * 100 + (timer->stop % 60); + if (timer->stop >= 2400) + timer->stop -= 2400; + timer->day = cTimer::SetTime(start, 0); + timer->channel = Channels.GetByNumber(cDevice::CurrentChannel()); + Timers.Add(timer); + Timers.SetModified(); + if (cRecordControls::Start(timer)) + Skins.Message(mtInfo, tr("Recording started")); + break; + } + default: return osUnknown; + } + } + } + if (DoShowMode) + ShowMode(); + return osContinue; +} + +// --- cLiveBufferManager ---------------------------------------------------- + +cLiveReceiver *cLiveBufferManager::liveReceiver[MAXLIVEBUFFERS] = { NULL }; +cLiveBuffer *cLiveBufferManager::liveBuffer[MAXLIVEBUFFERS] = { NULL }; +cDevice *cLiveBufferManager::receiverDevice[MAXLIVEBUFFERS] = { NULL }; +cLivePlayer *cLiveBufferManager::livePlayer = NULL; +cLiveBufferControl *cLiveBufferManager::liveControl = NULL; + +void cLiveBufferManager::ChannelSwitch(cDevice *ReceiverDevice, const cChannel *Channel) +{ + int i; + for (i=0; iChannel() == Channel) + break; + if (i == MAXLIVEBUFFERS) { + if (Setup.InRAM && !liveBuffer[0]) + i = 0; + else + for (i=0; iStay() || !liveReceiver[i]->IsAttached())) + break; + if (i == MAXLIVEBUFFERS) { + for (i = 0; iIsReceiving(Channel) && liveReceiver[i]->IsAttached())) { + cLiveReceiver *oldReceiver = liveReceiver[i]; + liveReceiver[i] = new cLiveReceiver(Channel); + ReceiverDevice->AttachReceiver(liveReceiver[i]); + liveBuffer[i]->SetNewRemux(liveReceiver[i]->remux, Channel); + delete oldReceiver; + receiverDevice[i] = ReceiverDevice; + } + else if (liveBuffer[i]->Stay()) + liveBuffer[i]->SetStatus(2); + } + else { + liveReceiver[i] = new cLiveReceiver(Channel); + ReceiverDevice->AttachReceiver(liveReceiver[i]); + receiverDevice[i] = ReceiverDevice; + char FileName[256]; + sprintf(FileName,"%s/LiveBuffer",BufferDirectory); + liveBuffer[i] = new cLiveBuffer(FileName,liveReceiver[i]->remux, Channel, i); + } + delete liveControl; + + cTransferControl::receiverDevice = receiverDevice[i]; + + livePlayer = new cLivePlayer(liveBuffer[i]); + cControl::Launch(liveControl = new cLiveBufferControl(livePlayer)); + + for (int j = 0; j < MAXLIVEBUFFERS; j++) + if (i!=j && liveBuffer[j] && !liveBuffer[j]->LiveCutterActive() && (!liveBuffer[j]->Stay() || !liveReceiver[j]->IsAttached())) { + delete liveBuffer[j]; + liveBuffer[j] = NULL; + delete liveReceiver[j]; + liveReceiver[j] = NULL; + } +} + +void cLiveBufferManager::Shutdown(void) +{ + delete liveControl; + for (int i = 0; i < MAXLIVEBUFFERS; i++) { + delete liveBuffer[i]; + liveBuffer[i] = NULL; + delete liveReceiver[i]; + liveReceiver[i] = NULL; + } + char FileName[256]; + sprintf(FileName,"%s/LiveBuffer",BufferDirectory); + RemoveFileOrDir(FileName, true); +} + +cLiveBuffer *cLiveBufferManager::InLiveBuffer(cTimer *timer, int *StartFrame, int *EndFrame) +{ + bool recstart = false; + if (timer && timer->HasFlags(tfRecording)) { + timer->SetFlags(tfhasLiveBuf); + recstart = true; + } + for (int i = 0; i < MAXLIVEBUFFERS; i++) + if (timer && timer->HasFlags(tfActive) && !timer->HasFlags(tfVps) && (!timer->HasFlags(tfhasLiveBuf) || recstart) && liveBuffer[i] && liveReceiver[i]->GetChannel() == timer->Channel()) { + int now = liveBuffer[i]->LastIndex(); + int first = liveBuffer[i]->FirstIndex() + 50; + if (now-first < 250) // Erst wenn LiveBuffer größer 10s + return NULL; + if (timer->StartTime() < time(NULL) && now-first > (time(NULL)-timer->StopTime())*FRAMESPERSEC) { + if (StartFrame) { + if ((time(NULL)-timer->StartTime())*FRAMESPERSEC < now - first) + *StartFrame = now - (time(NULL) - timer->StartTime())*FRAMESPERSEC; + else + *StartFrame = first; + } + if (EndFrame) { + if (time(NULL) > timer->StopTime()) + *EndFrame = now - (time(NULL) - timer->StopTime()) * FRAMESPERSEC; + else + *EndFrame = 0; + } + return liveBuffer[i]; + } + } + return NULL; +} + +int cLiveBufferManager::Impact(cDevice *device, const cChannel *Channel, bool LiveView) +{ + if (!Setup.LiveBuffer) + return 0; + int r = 1; + for (int i=0; i < MAXLIVEBUFFERS; i++) + if (liveBuffer[i] && receiverDevice[i] == device) { + if (liveBuffer[i]->Stay() && liveReceiver[i]->IsAttached()) + if (liveBuffer[i]->Channel()->Transponder() != Channel->Transponder() || + liveBuffer[i]->Channel()->Source() != Channel->Source()) + r = 2; + } + return r; +} + +bool cLiveBufferManager::AllowsChannelSwitch(void) +{ + return true; // return !liveBuffer || !liveBuffer->LiveCutterActive(); +} +#endif /* LIVEBUFFER */ diff -ruNp vdr-1.6.0-2/livebuffer.h vdr-1.6.0-2-extensions/livebuffer.h --- vdr-1.6.0-2/livebuffer.h 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/livebuffer.h 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,301 @@ +#ifndef __LIVEBUFFER_H +#define __LIVEBUFFER_H + +#include "player.h" +#include "receiver.h" +#include "remux.h" +#include "ringbuffer.h" +#include "thread.h" + +#define LIVEBUFSIZE MEGABYTE(5) + +#define INDEXBLOCKSIZE 20000 + +class cUnbufferedFile64 { +private: + int fd; + off64_t curpos; + off64_t cachedstart; + off64_t cachedend; + off64_t begin; + off64_t lastpos; + off64_t ahead; + size_t readahead; + size_t written; + size_t totwritten; + int FadviseDrop(off64_t Offset, off64_t Len); +public: + cUnbufferedFile64(void); + ~cUnbufferedFile64(); + int Open(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE); + int Close(void); + off64_t Seek(off64_t Offset, int Whence); + ssize_t Read(void *Data, size_t Size); + ssize_t Write(const void *Data, size_t Size); + static cUnbufferedFile64 *Create(const char *FileName, int Flags, mode_t Mode = DEFFILEMODE); + }; + +class cFileName64 { +private: + cUnbufferedFile64 *file; + int fileNumber; + char *fileName, *pFileNumber; + bool record; + bool blocking; +public: + cFileName64(const char *FileName, bool Record, bool Blocking = false); + ~cFileName64(); + const char *Name(void) { return fileName; } + int Number(void) { return fileNumber; } + void SetNumber(int Number); + cUnbufferedFile64 *Open(void); + void Close(void); + void CloseAndRemove(void); + void Remove(void); + }; + +class cLiveIndex { +friend class cLiveCutterThread; +friend class cLiveBuffer; +private: + struct frame { + off64_t offset ; //:36; + bool written ; //:1 ; + uchar pt ; //:3 ; + }; + struct block { + frame Frame[INDEXBLOCKSIZE]; + block *previous, *next; + }; + block *headblock, *tailblock; + int blockCount; + int head, tail; + int blank; + int start; + int writtenCount, delCount; + int DPos, DCount; + int lastWrittenSize, lastCount; + off64_t fileSize; + int bufSize; + int lastFrame; + int GetFrame(block** Block, int Number); + cRwLock *RwLock; +public: + cLiveIndex(int BufSize); + ~cLiveIndex(); + void Add(uchar pt, int pos); + void AddData(int pos); + void Delete(off64_t FilePos); + int DelFirst(void); + void Clear(void); + void SetBlank(int Blank) { RwLock->Lock(true); blank = Blank; RwLock->Unlock(); } + int NextWrite(); + void WrittenTo(off64_t FilePos, int Count); + bool HasFrame(int Number) { return lastFrame > Number && Number >=delCount; } + bool IsWritten(int Number) { return writtenCount > Number; } + off64_t GetOffset(int Number); + int Size(int Number, uchar *PictureType = NULL); + int GetNextIFrame(int Index, bool Forward); + int FindIFrame(int64_t PTS, uchar *Buffer); + void Switched(); + int Last(void) { return lastFrame+1; } + int First(void) { return start > delCount ? start : delCount; } +}; + +class cLiveFileReader : public cThread { +private: + cFileName64 *fileName; + cUnbufferedFile64 *readFile; + cCondWait newSet; + off64_t filePos; + int hasData, length, wanted; + uchar *buffer; +protected: + virtual void Action(void); +public: + cLiveFileReader(const char *FileName, int Number); + ~cLiveFileReader(); + int Read(uchar **Buffer, off64_t FilePos, int Size); + void Clear(void); +}; + +class cLiveFileWriter : public cThread { +private: + cFileName64 *fileName; + cUnbufferedFile64 *writeFile; + cCondWait newSet,written; + off64_t filePos,fileSize; + int hasWritten, length, wantWrite; + uchar *buffer; + time_t lastCheck; + bool full; + bool LowDiskSpace(void); +protected: + virtual void Action(void); +public: + cLiveFileWriter(const char *FileName); + ~cLiveFileWriter(); + off64_t Write(uchar *Buffer, int Size, bool Wait); + int FileNumber(void) { return fileName->Number(); } + void Clear(void); + bool Full(void) { return full; } +}; + +class cLiveBuffer; + +class cLiveCutterThread : public cThread { +private: + cFileName64 *readFileName, *writeFileName; + cUnbufferedFile64 *readFile, *writeFile; + cLiveBuffer *liveBuffer; + int startFrame, endFrame; +protected: + virtual void Action(void); +public: + cLiveCutterThread(const char *FileName, int FileNumber, cLiveBuffer *LiveBuffer, int StartFrame, int EndFrame); + ~cLiveCutterThread(); +}; + +class cLiveBuffer : public cThread { +friend class cLiveCutterThread; +private: + int number; + uchar *buffer; + int bufSize; + bool writeHD; + int lastRead; + int head, tail, blank; + cLiveIndex *index; + cRemux *remux; + cLiveFileWriter *fileWriter; + char *filestring; + uchar pictureType; + cLiveFileReader *fileReader; + int startFrame; + cLiveCutterThread *liveCutter; + const cChannel *channel; + int status; + void Write(bool Wait); + void Store(uchar *Data, int Count); +protected: + virtual void Action(void); +public: + cLiveBuffer(const char *FileName, cRemux *Remux, const cChannel *Channel, int Number); + virtual ~cLiveBuffer(); + void SetStatus(int s); + void SetNewRemux(cRemux *Remux, const cChannel *Channel); + int GetFrame(uchar **Buffer, int Number, int Off = -1); + int GetNextIFrame(int Index, bool Forward) { return index->GetNextIFrame(Index,Forward); } + int LastIndex(void) { return index->Last(); } + int FirstIndex(void) { return index->First(); } + int LastRead(void) { return lastRead; } + void CreateIndexFile(const char *FileName, int64_t PTS, int EndFrame = 0); + void SetStartFrame(int StartFrame) { startFrame = StartFrame; } + bool LiveCutterActive(void) { return liveCutter && liveCutter->Active(); } + const cChannel* Channel(void) { return channel; } + bool Stay(void) { return status>0 && Setup.KeepPaused; }; +}; + +class cLiveBackTrace; + +class cLivePlayer : public cPlayer, public cThread { +private: + enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill }; + enum ePlayDirs { pdForward, pdBackward }; + static int Speeds[]; + ePlayModes playMode; + ePlayDirs playDir; + int trickSpeed; + cLiveBuffer *liveBuffer; + cRingBufferFrame *ringBuffer; + cLiveBackTrace *backTrace; + int readIndex, writeIndex; + cFrame *readFrame; + cFrame *playFrame; + int Off; + bool firstPacket; + void TrickSpeed(int Increment); + void Empty(void); +protected: + virtual void Activate(bool On); + virtual void Action(void); +public: + cLivePlayer(cLiveBuffer *LiveBuffer); + virtual ~cLivePlayer(); + void Pause(void); + void Play(void); + void Forward(void); + void Backward(void); + bool Stop(void); + void SkipSeconds(int Seconds); + virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); + virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed); +}; + +class cLiveReceiver : public cReceiver, cThread { +friend class cLiveBufferManager; +friend class cLiveBufferControl; +private: + cRingBufferLinear *ringBuffer; + cRemux *remux; + const cChannel *channel; + bool attached; + int vpid; + int apids[MAXAPIDS]; + int dpids[MAXDPIDS]; + int spids[MAXSPIDS]; +protected: + virtual void Activate(bool On); + virtual void Receive(uchar *Data, int Length); + virtual void Action(void); +public: + cLiveReceiver(const cChannel *Channel); + virtual ~cLiveReceiver(); + const cChannel *GetChannel() { return channel; } + bool IsReceiving(const cChannel *Channel); + bool IsAttached() { return attached; } + }; + +class cLiveBufferControl : public cControl { +private: + cSkinDisplayReplay *displayReplay; + cLivePlayer *player; + bool visible, modeOnly, shown; + int lastCurrent, lastTotal; + bool lastPlay, lastForward; + int lastSpeed; + time_t timeoutShow; + void ShowTimed(int Seconds = 0); + void ShowMode(void); + bool ShowProgress(bool Initial); +public: + cLiveBufferControl(cLivePlayer *Player); + ~cLiveBufferControl(); + bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); + bool GetReplayMode(bool &Play, bool &Forward, int &Speed); + virtual eOSState ProcessKey(eKeys Key); + virtual void Show(void); + virtual void Hide(void); + bool Visible(void) { return visible; } + }; + +#define MAXLIVEBUFFERS 16 + +class cLiveBufferManager { +friend class cLiveBufferControl; +private: + static cLiveReceiver* liveReceiver[MAXLIVEBUFFERS]; + static cLiveBuffer* liveBuffer[MAXLIVEBUFFERS]; + static cDevice* receiverDevice[MAXLIVEBUFFERS]; + static cLivePlayer* livePlayer; + static cLiveBufferControl* liveControl; +public: + static void ChannelSwitch(cDevice *ReceiverDevice, const cChannel *Channel); + static void Shutdown(void); + static cLiveBufferControl *GetLiveBufferControl(void) { return liveControl; } + static cLiveBuffer *InLiveBuffer(cTimer *timer, int *StartFrame = NULL, int *EndFrame = NULL); + static int Impact(cDevice *device, const cChannel *Channel, bool LiveView); + static bool AllowsChannelSwitch(void); +}; + +#endif //__LIVEBUFFER_H diff -ruNp vdr-1.6.0-2/mainmenuitemsprovider.h vdr-1.6.0-2-extensions/mainmenuitemsprovider.h --- vdr-1.6.0-2/mainmenuitemsprovider.h 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/mainmenuitemsprovider.h 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,62 @@ +#ifdef USE_MENUORG +/* + * vdr-menuorg - A plugin for the Linux Video Disk Recorder + * Copyright (c) 2007 - 2008 Tobias Grimm + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * $Id$ + * + */ + +#ifndef __MAINMENUITEMSPROVIDER_H +#define __MAINMENUITEMSPROVIDER_H + +#include + +class cOsdItem; +class cOsdMenu; + +class IMenuItemDefinition +{ + public: + virtual ~IMenuItemDefinition() {}; + virtual bool IsCustomOsdItem() = 0; + virtual bool IsPluginItem() = 0; + virtual bool IsSeparatorItem() = 0; + virtual cOsdItem* CustomOsdItem() = 0; + virtual const char* PluginMenuEntry() = 0; + virtual bool IsSelected() = 0; + virtual int PluginIndex() = 0; +}; + +typedef std::vector MenuItemDefinitions; + +#define MENU_ITEMS_PROVIDER_SERVICE_ID "MenuOrgPatch-v0.4.2::MainMenuItemsProvider" + +class IMainMenuItemsProvider +{ + public: + virtual ~IMainMenuItemsProvider() {}; + virtual bool IsCustomMenuAvailable() = 0; + virtual MenuItemDefinitions* MainMenuItems() = 0; + virtual void EnterRootMenu() = 0; + virtual void EnterSubMenu(cOsdItem* item) = 0; + virtual bool LeaveSubMenu() = 0; + virtual cOsdMenu* Execute(cOsdItem* item) = 0; +}; + +#endif //__MAINMENUITEMSPROVIDER_H +#endif /* MENUORG */ diff -ruNp vdr-1.6.0-2/Make.config.template vdr-1.6.0-2-extensions/Make.config.template --- vdr-1.6.0-2/Make.config.template 2008-01-13 13:54:09.000000000 +0100 +++ vdr-1.6.0-2-extensions/Make.config.template 2009-04-09 20:48:26.000000000 +0200 @@ -41,8 +41,262 @@ RCU_DEVICE = /dev/ttyS1 ## Define if you want vdr to not run as root #VDR_USER = vdr +### VDR-Extensions: +# Comment the patches you don't need +# DVDCHAPJUMP needs DVDARCHIVE enabled +# DVDARCHIVE needs LIEMIEXT enabled +# SORTRECORDS needs LIEMIEXT enabled +# you can only enable MENUORG or SETUP + +#ANALOGTV = 1 +#ATSC = 1 +#CHANNELSCAN = 1 +CMDRECCMDI18N = 1 +CMDSUBMENU = 1 +#CUTTERLIMIT = 1 +#CUTTERQUEUE = 1 +CUTTIME = 1 +DDEPGENTRY = 1 +#DELTIMESHIFTREC = 1 +DOLBYINREC = 1 +#DVBPLAYER = 1 +#DVBSETUP = 1 +#DVDARCHIVE = 1 +#DVDCHAPJUMP = 1 +#DVLFRIENDLYFNAMES = 1 +#DVLRECSCRIPTADDON = 1 +#DVLVIDPREFER = 1 +#EM84XX = 1 +#GRAPHTFT = 1 +#HARDLINKCUTTER = 1 +JUMPPLAY = 1 +LIEMIEXT = 1 +#LIRCSETTINGS = 1 +#LIVEBUFFER = 1 +#LNBSHARE = 1 +#MAINMENUHOOKS = 1 +#MENUORG = 1 +#NOEPG = 1 +#OSDMAXITEMS = 1 +#PARENTALRATING = 1 +#PINPLUGIN = 1 +PLUGINAPI = 1 +PLUGINMISSING = 1 +#PLUGINPARAM = 1 +#ROTOR = 1 +SETTIME = 1 +#SETUP = 1 +#SOFTOSD = 1 +#SOURCECAPS = 1 +#SORTRECORDS = 1 +#STREAMDEVEXT = 1 +#SYNCEARLY = 1 +#TIMERCMD = 1 +#TIMERINFO = 1 +#TTXTSUBS = 1 +#VALIDINPUT = 1 +#VOLCTRL = 1 +#WAREAGLEICON = 1 +#YAEPG = 1 + ### You don't need to touch the following: ifdef DVBDIR INCLUDES += -I$(DVBDIR)/include endif + +ifdef ANALOGTV +DEFINES += -DUSE_ANALOGTV +endif + +ifdef ATSC +DEFINES += -DUSE_ATSC +endif + +ifdef CHANNELSCAN +DEFINES += -DUSE_CHANNELSCAN +endif + +ifdef CMDRECCMDI18N +DEFINES += -DUSE_CMDRECCMDI18N +endif + +ifdef CMDSUBMENU +DEFINES += -DUSE_CMDSUBMENU +endif + +ifdef CUTTERLIMIT +DEFINES += -DUSE_CUTTERLIMIT +endif + +ifdef CUTTERQUEUE +DEFINES += -DUSE_CUTTERQUEUE +endif + +ifdef CUTTIME +DEFINES += -DUSE_CUTTIME +endif + +ifdef DDEPGENTRY +DEFINES += -DUSE_DDEPGENTRY +endif + +ifdef DELTIMESHIFTREC +DEFINES += -DUSE_DELTIMESHIFTREC +endif + +ifdef DOLBYINREC +DEFINES += -DUSE_DOLBYINREC +endif + +ifdef DVBPLAYER +DEFINES += -DUSE_DVBPLAYER +endif + +ifdef DVBSETUP +DEFINES += -DUSE_DVBSETUP +endif + +ifdef DVDARCHIVE +ifdef LIEMIEXT +DEFINES += -DUSE_DVDARCHIVE +endif +endif + +ifdef DVLRECSCRIPTADDON +DEFINES += -DUSE_DVLRECSCRIPTADDON +endif + +ifdef DVLVIDPREFER +DEFINES += -DUSE_DVLVIDPREFER +endif + +ifdef DVLFRIENDLYFNAMES +DEFINES += -DUSE_DVLFRIENDLYFNAMES +endif + +ifdef EM84XX +DEFINES += -DUSE_EM84XX +endif + +ifdef GRAPHTFT +DEFINES += -DUSE_GRAPHTFT +endif + +ifdef HARDLINKCUTTER +DEFINES += -DUSE_HARDLINKCUTTER +endif + +ifdef JUMPPLAY +DEFINES += -DUSE_JUMPPLAY +endif + +ifdef LIEMIEXT +DEFINES += -DUSE_LIEMIEXT +endif + +ifdef LIRCSETTINGS +DEFINES += -DUSE_LIRCSETTINGS +endif + +ifdef LIVEBUFFER +DEFINES += -DUSE_LIVEBUFFER +endif + +ifdef LNBSHARE +DEFINES += -DUSE_LNBSHARE +endif + +ifdef MAINMENUHOOKS +DEFINES += -DUSE_MAINMENUHOOKS +endif + +ifdef MENUORG +DEFINES += -DUSE_MENUORG +else +ifdef SETUP +DEFINES += -DUSE_SETUP +endif +endif + +ifdef NOEPG +DEFINES += -DUSE_NOEPG +endif + +ifdef OSDMAXITEMS +DEFINES += -DUSE_OSDMAXITEMS +endif + +ifdef PARENTALRATING +DEFINES += -DUSE_PARENTALRATING +endif + +ifdef PINPLUGIN +DEFINES += -DUSE_PINPLUGIN +endif + +ifdef PLUGINMISSING +DEFINES += -DUSE_PLUGINMISSING +endif + +ifdef PLUGINPARAM +DEFINES += -DUSE_PLUGINPARAM +endif + +ifdef ROTOR +DEFINES += -DUSE_ROTOR +endif + +ifdef SETTIME +DEFINES += -DUSE_SETTIME +endif + +ifdef SOFTOSD +DEFINES += -DUSE_SOFTOSD +endif + +ifdef SOURCECAPS +DEFINES += -DUSE_SOURCECAPS +endif + +ifdef SORTRECORDS +ifdef LIEMIEXT +DEFINES += -DUSE_SORTRECORDS +endif +endif + +ifdef SYNCEARLY +DEFINES += -DUSE_SYNCEARLY +endif + +ifdef STREAMDEVEXT +DEFINES += -DUSE_STREAMDEVEXT +endif + +ifdef TIMERCMD +DEFINES += -DUSE_TIMERCMD +endif + +ifdef TIMERINFO +DEFINES += -DUSE_TIMERINFO +endif + +ifdef TTXTSUBS +DEFINES += -DUSE_TTXTSUBS +endif + +ifdef VALIDINPUT +DEFINES += -DUSE_VALIDINPUT +endif + +ifdef VOLCTRL +DEFINES += -DUSE_VOLCTRL +endif + +ifdef WAREAGLEICON +DEFINES += -DUSE_WAREAGLEICON +endif + +ifdef YAEPG +DEFINES += -DUSE_YAEPG +endif diff -ruNp vdr-1.6.0-2/Makefile vdr-1.6.0-2-extensions/Makefile --- vdr-1.6.0-2/Makefile 2008-02-29 22:43:03.000000000 +0100 +++ vdr-1.6.0-2-extensions/Makefile 2009-04-09 20:48:26.000000000 +0200 @@ -43,6 +43,22 @@ OBJS = audio.o channels.o ci.o config.o skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\ timers.o tools.o transfer.o vdr.o videodir.o +ifdef WAREAGLEICON +OBJS += iconpatch.o +endif + +ifdef LIVEBUFFER +OBJS += livebuffer.o +endif + +ifdef SETUP +OBJS += tinystr.o tinyxml.o tinyxmlerror.o tinyxmlparser.o submenu.o +endif + +ifdef TTXTSUBS +OBJS += vdrttxtsubshooks.o +endif + ifndef NO_KBD DEFINES += -DREMOTE_KBD endif @@ -75,6 +91,14 @@ ifdef VFAT DEFINES += -DVFAT endif +ifdef DVDARCHIVE +ifdef DVDCHAPJUMP +LIBS += -ldvdread +INCLUDES += -I/usr/include/dvdread +DEFINES += -DUSE_DVDCHAPJUMP +endif +endif + all: vdr i18n # Implicit rules: @@ -140,6 +164,26 @@ include-dir: # Plugins: +ifdef PLUGINAPI +DEFINES += -DUSE_PLUGINAPI +plugins: include-dir + @failed="";\ + noapiv="";\ + for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do\ + echo "Plugin $$i:";\ + if ! grep -q "\$$(LIBDIR)/.*\$$(APIVERSION)" "$(PLUGINDIR)/src/$$i/Makefile" ; then\ + sed -i -e s/VDRVERSION/APIVERSION/g $(PLUGINDIR)/src/$$i/Makefile;\ + if ! grep -q "\$$(LIBDIR)/.*\$$(APIVERSION)" "$(PLUGINDIR)/src/$$i/Makefile" ; then\ + echo "ERROR: plugin $$i doesn't honor APIVERSION - not compiled!";\ + noapiv="$$noapiv $$i";\ + continue;\ + fi;\ + fi;\ + $(MAKE) -C "$(PLUGINDIR)/src/$$i" all || failed="$$failed $$i";\ + done;\ + if [ -n "$$noapiv" ] ; then echo; echo "*** plugins without APIVERSION:$$noapiv"; echo; fi;\ + if [ -n "$$failed" ] ; then echo; echo "*** failed plugins:$$failed"; echo; fi +else plugins: include-dir @failed="";\ noapiv="";\ @@ -154,6 +198,7 @@ plugins: include-dir done;\ if [ -n "$$noapiv" ] ; then echo; echo "*** plugins without APIVERSION:$$noapiv"; echo; fi;\ if [ -n "$$failed" ] ; then echo; echo "*** failed plugins:$$failed"; echo; exit 1; fi +endif clean-plugins: @for i in `ls $(PLUGINDIR)/src | grep -v '[^a-z0-9]'`; do $(MAKE) -C "$(PLUGINDIR)/src/$$i" clean; done diff -ruNp vdr-1.6.0-2/MANUAL vdr-1.6.0-2-extensions/MANUAL --- vdr-1.6.0-2/MANUAL 2008-02-24 11:09:17.000000000 +0100 +++ vdr-1.6.0-2-extensions/MANUAL 2009-04-09 20:48:26.000000000 +0200 @@ -813,6 +813,30 @@ Version 1.6 0 resulting in a file named 'resume.vdr', and any other value resulting in 'resume.n.vdr'. + Jump&Play = no Turns playing on or off after jumping forward to the + next editing mark with the '9' key. + + Play&Jump = no Turns automatic jumping over commercial breaks on or + off. This includes jumping to the first mark, if the + replay starts at the beginning of a recording - and + stopping the replay at the last mark. + With this setting enabled, the behaviour of the '8' + key during replay is changed too. It moves the actual + replay position not only three seconds before the + next "start" mark, but also before the next "end" + mark. This can be used to test, if the editing marks + are correctly positioned for a "smooth" jump over a + commercial break. + + Pause at last mark = no + Turns pausing of replay at the last editing mark on or + off. + + Reload marks = no Turns reloading of editing marks on or off. This can + be used if an external programme adjusts the editing + marks, e.g. noad in online mode. The marks are reloaded + in 10 seconds intervals. + Miscellaneous: Min. event timeout = 30 diff -ruNp vdr-1.6.0-2/menu.c vdr-1.6.0-2-extensions/menu.c --- vdr-1.6.0-2/menu.c 2008-03-16 12:15:28.000000000 +0100 +++ vdr-1.6.0-2-extensions/menu.c 2009-04-09 20:48:26.000000000 +0200 @@ -8,11 +8,17 @@ */ #include "menu.h" +#ifdef USE_WAREAGLEICON +#include "iconpatch.h" +#endif /* WAREAGLEICON */ #include #include #include #include #include +#ifdef USE_LIEMIEXT +#include +#endif /* LIEMIEXT */ #include "channels.h" #include "config.h" #include "cutter.h" @@ -28,7 +34,17 @@ #include "themes.h" #include "timers.h" #include "transfer.h" +#ifdef USE_TTXTSUBS +#include "vdrttxtsubshooks.h" +#endif /* TTXTSUBS */ #include "videodir.h" +#ifdef USE_MENUORG +#include "menuorgpatch.h" +#endif /* MENUORG */ + +#ifdef USE_CMDRECCMDI18N +extern const char *ConfigDirectory; +#endif /* CMDRECCMDI18N */ #define MAXWAIT4EPGINFO 3 // seconds #define MODETIMEOUT 3 // seconds @@ -253,10 +269,16 @@ private: cChannel *channel; cChannel data; char name[256]; +#ifdef USE_PLUGINPARAM + char pluginParam[256]; +#endif /* PLUGINPARAM */ void Setup(void); public: cMenuEditChannel(cChannel *Channel, bool New = false); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuEditChannel"; } +#endif /* GRAPHTFT */ }; cMenuEditChannel::cMenuEditChannel(cChannel *Channel, bool New) @@ -285,6 +307,9 @@ void cMenuEditChannel::Setup(void) // Parameters for all types of sources: strn0cpy(name, data.name, sizeof(name)); +#ifdef USE_PLUGINPARAM + strn0cpy(pluginParam, data.pluginParam, sizeof(pluginParam)); +#endif /* PLUGINPARAM */ Add(new cMenuEditStrItem( tr("Name"), name, sizeof(name))); Add(new cMenuEditSrcItem( tr("Source"), &data.source)); Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency)); @@ -315,6 +340,9 @@ void cMenuEditChannel::Setup(void) ST(" T") Add(new cMenuEditMapItem( tr("Transmission"), &data.transmission, TransmissionValues)); ST(" T") Add(new cMenuEditMapItem( tr("Guard"), &data.guard, GuardValues)); ST(" T") Add(new cMenuEditMapItem( tr("Hierarchy"), &data.hierarchy, HierarchyValues, tr("none"))); +#ifdef USE_PLUGINPARAM + ST("P ") Add(new cMenuEditStrItem( tr("Parameters"), pluginParam, sizeof(pluginParam), tr(FileNameChars))); +#endif /* PLUGINPARAM */ SetCurrent(Get(current)); Display(); @@ -329,9 +357,15 @@ eOSState cMenuEditChannel::ProcessKey(eK if (Key == kOk) { if (Channels.HasUniqueChannelID(&data, channel)) { data.name = strcpyrealloc(data.name, name); +#ifdef USE_PLUGINPARAM + data.pluginParam = strcpyrealloc(data.pluginParam, pluginParam); +#endif /* PLUGINPARAM */ if (channel) { *channel = data; isyslog("edited channel %d %s", channel->Number(), *data.ToText()); +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(channel, scMod); +#endif /* STREAMDEVEXT */ state = osBack; } else { @@ -340,6 +374,9 @@ eOSState cMenuEditChannel::ProcessKey(eK Channels.Add(channel); Channels.ReNumber(); isyslog("added channel %d %s", channel->Number(), *data.ToText()); +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(channel, scAdd); +#endif /* STREAMDEVEXT */ state = osUser1; } Channels.SetModified(true); @@ -402,6 +439,16 @@ void cMenuChannelItem::Set(void) if (!channel->GroupSep()) { if (sortMode == csmProvider) buffer = cString::sprintf("%d\t%s - %s", channel->Number(), channel->Provider(), channel->Name()); +#ifdef USE_WAREAGLEICON + else if (Setup.WarEagleIcons) { + if (channel->Vpid() == 1 || channel->Vpid() == 0) + buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_RADIO_UTF8 : ICON_RADIO, channel->Name()); + else if (channel->Ca() == 0) + buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_UTF8 : ICON_TV, channel->Name()); + else + buffer = cString::sprintf("%d\t%s %-30s", channel->Number(), IsLangUtf8() ? ICON_TV_CRYPTED_UTF8 : ICON_TV_CRYPTED, channel->Name()); + } +#endif /* WAREAGLEICON */ else buffer = cString::sprintf("%d\t%s", channel->Number(), channel->Name()); } @@ -432,6 +479,9 @@ public: cMenuChannels(void); ~cMenuChannels(); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuChannels"; } +#endif /* GRAPHTFT */ }; cMenuChannels::cMenuChannels(void) @@ -561,6 +611,9 @@ eOSState cMenuChannels::Delete(void) Propagate(); Channels.SetModified(true); isyslog("channel %d deleted", DeletedChannel); +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(NULL, scDel); +#endif /* STREAMDEVEXT */ if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) Channels.SwitchTo(CurrentChannel->Number()); @@ -586,6 +639,9 @@ void cMenuChannels::Move(int From, int T Propagate(); Channels.SetModified(true); isyslog("channel %d moved to %d", FromNumber, ToNumber); +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(ToChannel, scMod); +#endif /* STREAMDEVEXT */ if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) Channels.SwitchTo(CurrentChannel->Number()); @@ -698,14 +754,47 @@ cMenuEditTimer::cMenuEditTimer(cTimer *T data.SetFlags(tfActive); channel = data.Channel()->Number(); Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive)); +#ifdef USE_PINPLUGIN + if (cOsd::pinValid) Add(new cMenuEditChanItem(tr("Channel"), &channel)); + else { + cString buf = cString::sprintf("%s\t%s", tr("Channel"), Channels.GetByNumber(channel)->Name()); + Add(new cOsdItem(buf)); + } +#else Add(new cMenuEditChanItem(tr("Channel"), &channel)); +#endif /* PINPLUGIN */ Add(new cMenuEditDateItem(tr("Day"), &data.day, &data.weekdays)); Add(new cMenuEditTimeItem(tr("Start"), &data.start)); Add(new cMenuEditTimeItem(tr("Stop"), &data.stop)); Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps)); Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); +#ifdef USE_PINPLUGIN + if (cOsd::pinValid || !data.fskProtection) Add(new cMenuEditBoolItem(tr("Childlock"),&data.fskProtection)); + else { + cString buf = cString::sprintf("%s\t%s", tr("Childlock"), data.fskProtection ? tr("yes") : tr("no")); + Add(new cOsdItem(buf)); + } +#endif /* PINPLUGIN */ +#ifdef USE_LIEMIEXT + char* p = strrchr(data.file, '~'); + if (p) { + p++; + Utf8Strn0Cpy(name, p, sizeof(name)); + Utf8Strn0Cpy(path, data.file, sizeof(path)); + p = strrchr(path, '~'); + if (p) + p[0] = 0; + } + else { + Utf8Strn0Cpy(name, data.file, sizeof(name)); + Utf8Strn0Cpy(path, "", sizeof(path)); + } + Add(new cMenuEditStrItem(tr("File"), name, sizeof(name), tr(FileNameChars))); + Add(new cMenuEditRecPathItem(tr("Path"), path, sizeof(path))); +#else Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file))); +#endif /* LIEMIEXT */ SetFirstDayItem(); } Timers.IncBeingEdited(); @@ -745,6 +834,12 @@ eOSState cMenuEditTimer::ProcessKey(eKey Skins.Message(mtError, tr("*** Invalid Channel ***")); break; } +#ifdef USE_LIEMIEXT + if (strlen(path)) + snprintf(data.file, sizeof(data.file), "%s~%s", path, name); + else + snprintf(data.file, sizeof(data.file), "%s", name); +#endif /* LIEMIEXT */ if (!*data.file) strcpy(data.file, data.Channel()->ShortName(true)); if (timer) { @@ -772,13 +867,37 @@ eOSState cMenuEditTimer::ProcessKey(eKey return state; } +#ifdef USE_TIMERCMD +// --- cMenuCommands --------------------------------------------------------- +// declaration shifted so it can be used in cMenuTimers +class cMenuCommands : public cOsdMenu { +private: + cCommands *commands; + char *parameters; + eOSState Execute(void); +public: + cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL); + virtual ~cMenuCommands(); + virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuCommands"; } +#endif /* GRAPHTFT - passt das so? */ + }; +#endif /* TIMERCMD */ + // --- cMenuTimerItem -------------------------------------------------------- class cMenuTimerItem : public cOsdItem { private: cTimer *timer; +#ifdef USE_TIMERINFO + char diskStatus; +#endif /* TIMERINFO */ public: cMenuTimerItem(cTimer *Timer); +#ifdef USE_TIMERINFO + void SetDiskStatus(char DiskStatus); +#endif /* TIMERINFO */ virtual int Compare(const cListObject &ListObject) const; virtual void Set(void); cTimer *Timer(void) { return timer; } @@ -787,6 +906,9 @@ public: cMenuTimerItem::cMenuTimerItem(cTimer *Timer) { timer = Timer; +#ifdef USE_TIMERINFO + diskStatus = ' '; +#endif /* TIMERINFO */ Set(); } @@ -812,8 +934,56 @@ void cMenuTimerItem::Set(void) strftime(buffer, sizeof(buffer), "%Y%m%d", &tm_r); day = buffer; } +#ifdef USE_LIEMIEXT + if (!Setup.ShowTimerStop) { +#ifdef USE_TIMERINFO +#ifdef USE_WAREAGLEICON + SetText(cString::sprintf("%c%s\t%d\t%s%s%s\t%02d:%02d\t%s", +#else + SetText(cString::sprintf("%c%c\t%d\t%s%s%s\t%02d:%02d\t%s", +#endif /* WAREAGLEICON */ + diskStatus, +#else +#ifdef USE_WAREAGLEICON + SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%s", +#else + SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%s", +#endif /* WAREAGLEICON */ +#endif /* TIMERINFO */ +#ifdef USE_WAREAGLEICON + !(timer->HasFlags(tfActive)) ? " " : timer->FirstDay() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_ARROW_UTF8 : ICON_ARROW : "!" : timer->Recording() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_REC_UTF8 : ICON_REC : "#" : Setup.WarEagleIcons ? IsLangUtf8() ? ICON_CLOCK_UTF8 : ICON_CLOCK : ">", +#else + !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', +#endif /* WAREAGLEICON */ + timer->Channel()->Number(), + *name, + *name && **name ? " " : "", + *day, + timer->Start() / 100, + timer->Start() % 100, + timer->File())); + } + else { +#endif /* LIEMIEXT */ +#ifdef USE_TIMERINFO +#ifdef USE_WAREAGLEICON + SetText(cString::sprintf("%c%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", +#else + SetText(cString::sprintf("%c%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", +#endif /* WAREAGLEICON */ + diskStatus, +#else +#ifdef USE_WAREAGLEICON + SetText(cString::sprintf("%s\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", +#else SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s", +#endif /* WAREAGLEICON */ +#endif /* TIMERINFO */ +#ifdef USE_WAREAGLEICON + !(timer->HasFlags(tfActive)) ? " " : timer->FirstDay() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_ARROW_UTF8 : ICON_ARROW : "!" : timer->Recording() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_REC_UTF8 : ICON_REC : "#" : Setup.WarEagleIcons ? IsLangUtf8() ? ICON_CLOCK_UTF8 : ICON_CLOCK : ">", +#else !(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', +#endif /* WAREAGLEICON */ timer->Channel()->Number(), *name, *name && **name ? " " : "", @@ -823,8 +993,64 @@ void cMenuTimerItem::Set(void) timer->Stop() / 100, timer->Stop() % 100, timer->File())); +#ifdef USE_LIEMIEXT + } +#endif /* LIEMIEXT */ +} + +#ifdef USE_TIMERINFO +void cMenuTimerItem::SetDiskStatus(char DiskStatus) +{ + diskStatus = DiskStatus; + Set(); +} + +// --- cTimerEntry ----------------------------------------------------------- + +class cTimerEntry : public cListObject { +private: + cMenuTimerItem *item; + const cTimer *timer; + time_t start; +public: + cTimerEntry(cMenuTimerItem *item) : item(item), timer(item->Timer()), start(timer->StartTime()) {} + cTimerEntry(const cTimer *timer, time_t start) : item(NULL), timer(timer), start(start) {} + virtual int Compare(const cListObject &ListObject) const; + bool active(void) const { return timer->HasFlags(tfActive); } + time_t startTime(void) const { return start; } + int priority(void) const { return timer->Priority(); } + int duration(void) const; + bool repTimer(void) const { return !timer->IsSingleEvent(); } + bool isDummy(void) const { return item == NULL; } + const cTimer *Timer(void) const { return timer; } + void SetDiskStatus(char DiskStatus); + }; + +int cTimerEntry::Compare(const cListObject &ListObject) const +{ + cTimerEntry *entry = (cTimerEntry *)&ListObject; + int r = startTime() - entry->startTime(); + if (r == 0) + r = entry->priority() - priority(); + return r; } +int cTimerEntry::duration(void) const +{ + int dur = (timer->Stop() / 100 * 60 + timer->Stop() % 100) - + (timer->Start() / 100 * 60 + timer->Start() % 100); + if (dur < 0) + dur += 24 * 60; + return dur; +} + +void cTimerEntry::SetDiskStatus(char DiskStatus) +{ + if (item) + item->SetDiskStatus(DiskStatus); +} +#endif /* TIMERINFO */ + // --- cMenuTimers ----------------------------------------------------------- class cMenuTimers : public cOsdMenu { @@ -837,14 +1063,31 @@ private: eOSState Info(void); cTimer *CurrentTimer(void); void SetHelpKeys(void); +#ifdef USE_TIMERINFO + void ActualiseDiskStatus(void); + bool actualiseDiskStatus; +#endif /* TIMERINFO */ +#ifdef USE_TIMERCMD + eOSState Commands(eKeys Key = kNone); +#endif /* TIMERCMD */ public: cMenuTimers(void); virtual ~cMenuTimers(); +#ifdef USE_TIMERINFO + virtual void Display(void); +#endif /* TIMERINFO */ virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuTimers"; } +#endif /* GRAPHTFT */ }; cMenuTimers::cMenuTimers(void) +#ifdef USE_TIMERINFO +:cOsdMenu(tr("Timers"), 3, CHNUMWIDTH, 10, 6, 6) +#else :cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6) +#endif /* TIMERINFO */ { helpKeys = -1; for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { @@ -855,6 +1098,9 @@ cMenuTimers::cMenuTimers(void) SetCurrent(First()); SetHelpKeys(); Timers.IncBeingEdited(); +#ifdef USE_TIMERINFO + actualiseDiskStatus = true; +#endif /* TIMERINFO */ } cMenuTimers::~cMenuTimers() @@ -893,7 +1139,11 @@ eOSState cMenuTimers::OnOff(void) timer->OnOff(); timer->SetEventFromSchedule(); RefreshCurrent(); +#ifdef USE_TIMERINFO + Display(); +#else DisplayCurrent(true); +#endif /* TIMERINFO */ if (timer->FirstDay()) isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay()); else @@ -952,6 +1202,117 @@ eOSState cMenuTimers::Info(void) return osContinue; } +#ifdef USE_TIMERCMD +#define CHECK_2PTR_NULL(x_,y_) ((x_)? ((y_)? y_:""):"") + +eOSState cMenuTimers::Commands(eKeys Key) +{ + if (HasSubMenu() || Count() == 0) + return osContinue; + cTimer *ti = CurrentTimer(); + if (ti) { + const cEvent *pEvent = ti->Event(); + int iRecNumber=0; + + if (!pEvent) { + Timers.SetEvents(); + pEvent = ti->Event(); + } + if (pEvent) { + // create a dummy recording to get the real filename + cRecording *rc_dummy = new cRecording(ti, pEvent); + Recordings.Load(); + cRecording *rc = Recordings.GetByName(rc_dummy->FileName()); + + delete rc_dummy; + if (rc) + iRecNumber=rc->Index() + 1; + } + // TODO: Geht das so...? + // Parameter format TimerNumber 'ChannelId' Start Stop 'Titel' 'Subtitel' 'file' RecNumer + // 1 2 3 4 5 6 7 8 + cString parameter = cString::sprintf("%d '%s' %d %d '%s' '%s' '%s' %d", ti->Index(), + *ti->Channel()->GetChannelID().ToString(), + (int)ti->StartTime(), + (int)ti->StopTime(), + CHECK_2PTR_NULL(pEvent, pEvent->Title()), + CHECK_2PTR_NULL(pEvent, pEvent->ShortText()), + ti->File(), + iRecNumber); + isyslog("timercmd: %s", *parameter); + cMenuCommands *menu; + eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Timer commands"), &TimerCommands, parameter)); + if (Key != kNone) + state = menu->ProcessKey(Key); + return state; + } + return osContinue; +} +#endif /* TIMERCMD */ + +#ifdef USE_TIMERINFO +void cMenuTimers::ActualiseDiskStatus(void) +{ + if (!actualiseDiskStatus || !Count()) + return; + + // compute free disk space + int freeMB, freeMinutes, runshortMinutes; + VideoDiskSpace(&freeMB); + freeMinutes = int(double(freeMB) * 1.1 / MB_PER_MINUTE); // overestimate by 10 percent + runshortMinutes = freeMinutes / 5; // 20 Percent + + // fill entries list + cTimerEntry *entry; + cList entries; + for (cOsdItem *item = First(); item; item = Next(item)) + entries.Add(new cTimerEntry((cMenuTimerItem *)item)); + + // search last start time + time_t last = 0; + for (entry = entries.First(); entry; entry = entries.Next(entry)) + last = max(entry->startTime(), last); + + // add entries for repeating timers + for (entry = entries.First(); entry; entry = entries.Next(entry)) + if (entry->repTimer() && !entry->isDummy()) + for (time_t start = cTimer::IncDay(entry->startTime(), 1); + start <= last; + start = cTimer::IncDay(start, 1)) + if (entry->Timer()->DayMatches(start)) + entries.Add(new cTimerEntry(entry->Timer(), start)); + + // set the disk-status + entries.Sort(); + for (entry = entries.First(); entry; entry = entries.Next(entry)) { + char status = ' '; + if (entry->active()) { + freeMinutes -= entry->duration(); + status = freeMinutes > runshortMinutes ? '+' : freeMinutes > 0 ? '~' /* ± 177 +/- */ : '-'; + } + entry->SetDiskStatus(status); +#ifdef DEBUG_TIMER_INFO + dsyslog("timer-info: %c | %d | %s | %s | %3d | %+5d -> %+5d", + status, + entry->startTime(), + entry->active() ? "aktiv " : "n.akt.", + entry->repTimer() ? entry->isDummy() ? " dummy " : "mehrmalig" : "einmalig ", + entry->duration(), + entry->active() ? freeMinutes + entry->duration() : freeMinutes, + freeMinutes); +#endif + } + + actualiseDiskStatus = false; +} + +void cMenuTimers::Display(void) +{ + ActualiseDiskStatus(); + cOsdMenu::Display(); +} +#endif /* TIMERINFO */ + eOSState cMenuTimers::ProcessKey(eKeys Key) { int TimerNumber = HasSubMenu() ? Count() : -1; @@ -960,18 +1321,40 @@ eOSState cMenuTimers::ProcessKey(eKeys K if (state == osUnknown) { switch (Key) { case kOk: return Edit(); +#ifdef USE_TIMERINFO + case kRed: actualiseDiskStatus = true; + state = OnOff(); break; // must go through SetHelpKeys()! +#else case kRed: state = OnOff(); break; // must go through SetHelpKeys()! +#endif /* TIMERINFO */ case kGreen: return New(); +#ifdef USE_TIMERINFO + case kYellow: actualiseDiskStatus = true; + state = Delete(); break; +#else case kYellow: state = Delete(); break; +#endif /* TIMERINFO */ case kInfo: case kBlue: return Info(); break; +#ifdef USE_TIMERCMD + case k1...k9: return Commands(Key); + case k0: return (TimerCommands.Count()? Commands():osContinue); +#endif /* TIMERCMD */ default: break; } } +#ifdef USE_TIMERINFO + if (TimerNumber >= 0 && !HasSubMenu()) { + if (Timers.Get(TimerNumber)) // a newly created timer was confirmed with Ok + Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); + Sort(); + actualiseDiskStatus = true; +#else if (TimerNumber >= 0 && !HasSubMenu() && Timers.Get(TimerNumber)) { // a newly created timer was confirmed with Ok Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); +#endif /* TIMERINFO */ Display(); } if (Key != kNone) @@ -1001,6 +1384,9 @@ void cMenuEvent::Display(void) { cOsdMenu::Display(); DisplayMenu()->SetEvent(event); +#ifdef USE_GRAPHTFT + cStatus::MsgOsdSetEvent(event); +#endif /* GRAPHTFT */ if (event->Description()) cStatus::MsgOsdTextItem(event->Description()); } @@ -1048,7 +1434,12 @@ public: const cChannel *channel; bool withDate; int timerMatch; +#ifdef USE_LIEMIEXT + bool withBar; + cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false, bool WithBar = false); +#else cMenuScheduleItem(const cEvent *Event, cChannel *Channel = NULL, bool WithDate = false); +#endif /* LIEMIEXT */ static void SetSortMode(eScheduleSortMode SortMode) { sortMode = SortMode; } static void IncSortMode(void) { sortMode = eScheduleSortMode((sortMode == ssmAllAll) ? ssmAllThis : sortMode + 1); } static eScheduleSortMode SortMode(void) { return sortMode; } @@ -1058,12 +1449,19 @@ public: cMenuScheduleItem::eScheduleSortMode cMenuScheduleItem::sortMode = ssmAllThis; +#ifdef USE_LIEMIEXT +cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate, bool WithBar) +#else cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event, cChannel *Channel, bool WithDate) +#endif /* LIEMIEXT */ { event = Event; channel = Channel; withDate = WithDate; timerMatch = tmNone; +#ifdef USE_LIEMIEXT + withBar = WithBar; +#endif /* LIEMIEXT */ Update(true); } @@ -1078,7 +1476,29 @@ int cMenuScheduleItem::Compare(const cLi return r; } +#ifdef USE_LIEMIEXT +static const char * const ProgressBar[7] = +{ + "[ ]", + "[| ]", + "[|| ]", + "[||| ]", + "[|||| ]", + "[||||| ]", + "[||||||]" +}; +#endif /* LIEMIEXT */ + +#ifdef USE_WAREAGLEICON +static const char *TimerMatchChars[9] = +{ + " ", "t", "T", + ICON_BLANK, ICON_CLOCK_UH, ICON_CLOCK, + ICON_BLANK_UTF8, ICON_CLOCK_UH_UTF8, ICON_CLOCK_UTF8 +}; +#else static const char *TimerMatchChars = " tT"; +#endif /* WAREAGLEICON */ bool cMenuScheduleItem::Update(bool Force) { @@ -1087,17 +1507,54 @@ bool cMenuScheduleItem::Update(bool Forc Timers.GetMatch(event, &timerMatch); if (Force || timerMatch != OldTimerMatch) { cString buffer; +#ifdef USE_WAREAGLEICON + const char *t = Setup.WarEagleIcons ? IsLangUtf8() ? TimerMatchChars[timerMatch+6] : TimerMatchChars[timerMatch+3] : TimerMatchChars[timerMatch]; + const char *v = event->Vps() && (event->Vps() - event->StartTime()) ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_VPS_UTF8 : ICON_VPS : "V" : " "; + const char *r = event->SeenWithin(30) && event->IsRunning() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_RUNNING_UTF8 : ICON_RUNNING : "*" : " "; +#else char t = TimerMatchChars[timerMatch]; char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' '; char r = event->SeenWithin(30) && event->IsRunning() ? '*' : ' '; +#endif /* WAREAGLEICON */ const char *csn = channel ? channel->ShortName(true) : NULL; cString eds = event->GetDateString(); if (channel && withDate) +#ifdef USE_WAREAGLEICON + buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); +#else buffer = cString::sprintf("%d\t%.*s\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); +#endif /* WAREAGLEICON */ else if (channel) +#ifdef USE_LIEMIEXT + if (Setup.ShowProgressBar && withBar) { + int progress = (int)roundf( (float)(time(NULL) - event->StartTime()) / (float)(event->Duration()) * 6.0 ); + if (progress < 0) progress = 0; + else if (progress > 6) progress = 6; +#ifdef USE_WAREAGLEICON + buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); +#else + buffer = cString::sprintf("%d\t%.*s\t%s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), ProgressBar[progress], t, v, r, event->Title()); +#endif /* WAREAGLEICON */ + } + else +#ifdef USE_WAREAGLEICON + buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); +#else + buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); +#endif /* WAREAGLEICON */ +#else +#ifdef USE_WAREAGLEICON + buffer = cString::sprintf("%d\t%.*s\t%s\t%s%s%s\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); +#else buffer = cString::sprintf("%d\t%.*s\t%s\t%c%c%c\t%s", channel->Number(), Utf8SymChars(csn, 6), csn, *event->GetTimeString(), t, v, r, event->Title()); +#endif /* WAREAGLEICON */ +#endif /* LIEMIEXT */ else +#ifdef USE_WAREAGLEICON + buffer = cString::sprintf("%.*s\t%s\t%s%s%s\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); +#else buffer = cString::sprintf("%.*s\t%s\t%c%c%c\t%s", Utf8SymChars(eds, 6), *eds, *event->GetTimeString(), t, v, r, event->Title()); +#endif /* WAREAGLEICON */ SetText(buffer); result = true; } @@ -1123,13 +1580,21 @@ public: static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; } static const cEvent *ScheduleEvent(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return now ? "MenuWhatsOnNow" : "MenuWhatsOnNext"; } + virtual void Display(void); +#endif /* GRAPHTFT */ }; int cMenuWhatsOn::currentChannel = 0; const cEvent *cMenuWhatsOn::scheduleEvent = NULL; cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr) +#ifdef USE_LIEMIEXT +:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4, 4) +#else :cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4) +#endif /* LIEMIEXT */ { now = Now; helpKeys = -1; @@ -1141,7 +1606,11 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedu if (Schedule) { const cEvent *Event = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent(); if (Event) +#ifdef USE_LIEMIEXT + Add(new cMenuScheduleItem(Event, Channel, false, Now), Channel->Number() == CurrentChannelNr); +#else Add(new cMenuScheduleItem(Event, Channel), Channel->Number() == CurrentChannelNr); +#endif /* LIEMIEXT */ } } } @@ -1150,6 +1619,19 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedu SetHelpKeys(); } +#ifdef USE_GRAPHTFT +void cMenuWhatsOn::Display(void) +{ + cOsdMenu::Display(); + + if (Count() > 0) { + int ni = 0; + for (cOsdItem *item = First(); item; item = Next(item)) + cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); + } +} +#endif /* GRAPHTFT */ + bool cMenuWhatsOn::Update(void) { bool result = false; @@ -1290,6 +1772,10 @@ public: cMenuSchedule(void); virtual ~cMenuSchedule(); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuSchedule"; } + virtual void Display(void); +#endif /* GRAPHTFT */ }; cMenuSchedule::cMenuSchedule(void) @@ -1315,6 +1801,19 @@ cMenuSchedule::~cMenuSchedule() cMenuWhatsOn::ScheduleEvent(); // makes sure any posted data is cleared } +#ifdef USE_GRAPHTFT +void cMenuSchedule::Display(void) +{ + cOsdMenu::Display(); + + if (Count() > 0) { + int ni = 0; + for (cOsdItem *item = First(); item; item = Next(item)) + cStatus::MsgOsdEventItem(((cMenuScheduleItem*)item)->event, item->Text(), ni++, Count()); + } +} +#endif /* GRAPHTFT */ + void cMenuSchedule::PrepareScheduleAllThis(const cEvent *Event, const cChannel *Channel) { Clear(); @@ -1548,6 +2047,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys // --- cMenuCommands --------------------------------------------------------- +#ifndef USE_TIMERCMD class cMenuCommands : public cOsdMenu { private: cCommands *commands; @@ -1557,7 +2057,11 @@ public: cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL); virtual ~cMenuCommands(); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuCommands"; } +#endif /* GRAPHTFT */ }; +#endif /* TIMERCMD */ cMenuCommands::cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters) :cOsdMenu(Title) @@ -1579,6 +2083,12 @@ eOSState cMenuCommands::Execute(void) cCommand *command = commands->Get(Current()); if (command) { bool confirmed = true; +#ifdef USE_CMDSUBMENU + if (command->hasChilds()) { + AddSubMenu(new cMenuCommands(command->Title(), command->getChilds(), parameters)); + return osContinue; + } +#endif /* CMDSUBMENU */ if (command->Confirm()) confirmed = Interface->Confirm(cString::sprintf("%s?", command->Title())); if (confirmed) { @@ -1629,6 +2139,9 @@ public: cMenuCam(cCamSlot *CamSlot); virtual ~cMenuCam(); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuCam"; } +#endif /* GRAPHTFT */ }; cMenuCam::cMenuCam(cCamSlot *CamSlot) @@ -1808,6 +2321,9 @@ public: cMenuRecording(const cRecording *Recording, bool WithButtons = false); virtual void Display(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuRecording"; } +#endif /* GRAPHTFT */ }; cMenuRecording::cMenuRecording(const cRecording *Recording, bool WithButtons) @@ -1823,6 +2339,9 @@ void cMenuRecording::Display(void) { cOsdMenu::Display(); DisplayMenu()->SetRecording(recording); +#ifdef USE_GRAPHTFT + cStatus::MsgOsdSetRecording(recording); +#endif /* GRAPHTFT */ if (recording->Info()->Description()) cStatus::MsgOsdTextItem(recording->Info()->Description()); } @@ -1883,7 +2402,11 @@ cMenuRecordingItem::cMenuRecordingItem(c fileName = strdup(Recording->FileName()); name = NULL; totalEntries = newEntries = 0; +#ifdef USE_LIEMIEXT + SetText(Recording->Title('\t', true, Level, false)); +#else SetText(Recording->Title('\t', true, Level)); +#endif /* LIEMIEXT */ if (*Text() == '\t') name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t' } @@ -1899,13 +2422,203 @@ void cMenuRecordingItem::IncrementCounte totalEntries++; if (New) newEntries++; +#ifdef USE_LIEMIEXT +#ifdef USE_WAREAGLEICON + switch (Setup.ShowRecTime + Setup.ShowRecDate + Setup.ShowRecLength) { + case 0: + if (Setup.WarEagleIcons) + SetText(cString::sprintf("%s %s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, name)); + else + SetText(cString::sprintf("%s", name)); + break; + case 1: + if (Setup.WarEagleIcons) + SetText(cString::sprintf("%s %d\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, name)); + else + SetText(cString::sprintf("%d\t%s", totalEntries, name)); + break; + case 2: + default: + if (Setup.WarEagleIcons) + SetText(cString::sprintf("%s (%d/%d)\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); + else + SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); + break; + case 3: + if (Setup.WarEagleIcons) + SetText(cString::sprintf("%s (%d/%d)\t\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); + else + SetText(cString::sprintf("%d\t%d\t\t%s", totalEntries, newEntries, name)); + break; + } +#else + switch (Setup.ShowRecTime + Setup.ShowRecDate + Setup.ShowRecLength) { + case 0: + SetText(cString::sprintf("%s", name)); + break; + case 1: + SetText(cString::sprintf("%d\t%s", totalEntries, name)); + break; + case 2: + default: + SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); + break; + case 3: + SetText(cString::sprintf("%d\t%d\t\t%s", totalEntries, newEntries, name)); + break; + } +#endif /* WAREAGLEICON */ +#else +#ifdef USE_WAREAGLEICON + if (Setup.WarEagleIcons) + SetText(cString::sprintf("%s (%d/%d)\t%s", IsLangUtf8() ? ICON_FOLDER_UTF8 : ICON_FOLDER, totalEntries, newEntries, name)); + else +#endif /* WAREAGLEICON */ SetText(cString::sprintf("%d\t%d\t%s", totalEntries, newEntries, name)); +#endif /* LIEMIEXT */ } +#ifdef USE_LIEMIEXT +// --- cMenuRenameRecording -------------------------------------------------- + +class cMenuRenameRecording : public cOsdMenu { +private: + int lifetime; + int priority; + char name[MaxFileName]; + char path[MaxFileName]; + cOsdItem *marksItem, *resumeItem; + bool isResume, isMarks; + cRecording *recording; +public: + cMenuRenameRecording(cRecording *Recording); + virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuRenameRecording"; } +#endif /* GRAPHTFT */ +}; + +cMenuRenameRecording::cMenuRenameRecording(cRecording *Recording) +:cOsdMenu(tr("Rename recording"), 12) +{ + cMarks marks; + + recording = Recording; + priority = recording->priority; + lifetime = recording->lifetime; + + char* p = strrchr(recording->Name(), '~'); + if (p) { + p++; + Utf8Strn0Cpy(name, p, sizeof(name)); + Utf8Strn0Cpy(path, recording->Name(), sizeof(path)); + p = strrchr(path, '~'); + if (p) + p[0] = 0; + } + else { + Utf8Strn0Cpy(name, recording->Name(), sizeof(name)); + Utf8Strn0Cpy(path, "", sizeof(path)); + } + Add(new cMenuEditStrItem(tr("Name"), name, sizeof(name), tr(FileNameChars))); + Add(new cMenuEditRecPathItem(tr("Path"), path, sizeof(path) )); + Add(new cMenuEditIntItem(tr("Priority"), &priority, 0, MAXPRIORITY )); + Add(new cMenuEditIntItem(tr("Lifetime"), &lifetime, 0, MAXLIFETIME )); + + Add(new cOsdItem("", osUnknown, false)); + + Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Date"), *DayDateTime(recording->start)), osUnknown, false)); + + cChannel *channel = Channels.GetByChannelID(((cRecordingInfo *)recording->Info())->ChannelID()); + if (channel) + Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Channel"), *ChannelString(channel, 0)), osUnknown, false)); + + cIndexFile *index = new cIndexFile(recording->FileName(), false); + int recLen = 0; + if (index) { + recLen = index->Last() / FRAMESPERSEC; + Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Length"), *IndexToHMSF(index->Last())), osUnknown, false)); + delete index; + } + + int dirSize = DirSizeMB(recording->FileName()); + cString bitRate = recLen ? cString::sprintf(" (%.2f MBit/s)", 8.0 * dirSize / recLen) : cString(""); + Add(new cOsdItem((dirSize > 9999) ? cString::sprintf("%s:\t%.2f GB%s", tr("Size"), dirSize / 1024.0, *bitRate) : cString::sprintf("%s:\t%d MB%s", tr("Size"), dirSize, *bitRate), osUnknown, false)); + + Add(new cOsdItem("", osUnknown, false)); + + isMarks = marks.Load(recording->FileName()) && marks.Count(); + marksItem = new cOsdItem(tr("Delete marks information?"), osUser1, isMarks); + Add(marksItem); + + cResumeFile ResumeFile(recording->FileName()); + isResume = (ResumeFile.Read() != -1); + resumeItem = new cOsdItem(tr("Delete resume information?"), osUser2, isResume); + Add(resumeItem); +} + +eOSState cMenuRenameRecording::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + if (Key == kOk) { + char buffer[MaxFileName]; + if (Utf8StrLen(path)) + snprintf(buffer, sizeof(buffer), "%s~%s", path, name); + else + snprintf(buffer, sizeof(buffer), "%s", name); + if (recording->Rename(buffer, &priority, &lifetime)) { + Recordings.ChangeState(); + Recordings.TouchUpdate(); + return osRecordings; + } + else + Skins.Message(mtError, tr("Error while accessing recording!")); + } + return osContinue; + } + else if (state == osUser1) { + if (isMarks && Interface->Confirm(tr("Delete marks information?"))) { + cMarks marks; + marks.Load(recording->FileName()); + cMark *mark = marks.First(); + while (mark) { + cMark *nextmark = marks.Next(mark); + marks.Del(mark); + mark = nextmark; + } + marks.Save(); + isMarks = false; + marksItem->SetSelectable(isMarks); + SetCurrent(First()); + Display(); + } + return osContinue; + } + else if (state == osUser2) { + if (isResume && Interface->Confirm(tr("Delete resume information?"))) { + cResumeFile ResumeFile(recording->FileName()); + ResumeFile.Delete(); + isResume = false; + resumeItem->SetSelectable(isResume); + SetCurrent(First()); + Display(); + } + return osContinue; + } + return state; +} +#endif /* LIEMIEXT */ + // --- cMenuRecordings ------------------------------------------------------- cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus) +#ifdef USE_LIEMIEXT +:cOsdMenu(Base ? Base : tr("Recordings"), 9, 7, 7) +#else :cOsdMenu(Base ? Base : tr("Recordings"), 9, 7) +#endif /* LIEMIEXT */ { base = Base ? strdup(Base) : NULL; level = Setup.RecordingDirs ? Level : -1; @@ -1982,7 +2695,12 @@ void cMenuRecordings::Set(bool Refresh) for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) { if (!base || (strstr(recording->Name(), base) == recording->Name() && recording->Name()[strlen(base)] == '~')) { cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level); +#ifdef USE_PINPLUGIN + if ((*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) + && (!cStatus::MsgReplayProtected(GetRecording(Item), Item->Name(), base, Item->IsDirectory(), true))) { +#else if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) { +#endif /* PINPLUGIN */ Add(Item); LastItem = Item; free(LastItemText); @@ -2032,13 +2750,43 @@ eOSState cMenuRecordings::Play(void) { cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); if (ri) { +#ifdef USE_PINPLUGIN + if (cStatus::MsgReplayProtected(GetRecording(ri), ri->Name(), base, ri->IsDirectory()) == true) + return osContinue; +#endif /* PINPLUGIN */ if (ri->IsDirectory()) Open(); else { cRecording *recording = GetRecording(ri); if (recording) { +#ifdef USE_DVDARCHIVE + int mountRet = MOUNT_DVD_REPLAY; + if (recording->IsOnlyOnDvd()) { + mountRet = recording->MountDvd(); + } + if (mountRet == MOUNT_DVD_REPLAY) { + cReplayControl::SetRecording(recording->FileName(), recording->Title()); + return osReplay; + } + else if (mountRet == MOUNT_DVD_LAUNCH_DVD_PLUGIN) { + //launch DVD plugin here + cPlugin *p = cPluginManager::GetPlugin("dvd"); + cOsdObject *osd = NULL; + if (p) { + osd = p->MainMenuAction(); + delete osd; + osd = NULL; + return osEnd; + } + else { + Skins.Message(mtError, tr("DVD plugin is not installed!")); + Skins.Flush(); + } + } +#else cReplayControl::SetRecording(recording->FileName(), recording->Title()); return osReplay; +#endif /* DVDARCHIVE */ } } } @@ -2136,12 +2884,34 @@ eOSState cMenuRecordings::Commands(eKeys return osContinue; } +#ifdef USE_LIEMIEXT +eOSState cMenuRecordings::Rename(void) +{ + if (HasSubMenu() || Count() == 0) + return osContinue; + cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); + if (ri && !ri->IsDirectory()) { + cRecording *recording = GetRecording(ri); + if (recording) + return AddSubMenu(new cMenuRenameRecording(recording)); + } + return osContinue; +} +#endif /* LIEMIEXT */ + eOSState cMenuRecordings::ProcessKey(eKeys Key) { bool HadSubMenu = HasSubMenu(); eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { +#ifdef USE_SORTRECORDS + const char *RecordingsSortModeTexts[MAXSORTMODES]; + RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); + RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); + RecordingsSortModeTexts[2] = tr("all alphabetically"); + RecordingsSortModeTexts[3] = tr("all by date"); +#endif /* SORTRECORDS */ switch (Key) { case kPlay: case kOk: return Play(); @@ -2150,7 +2920,26 @@ eOSState cMenuRecordings::ProcessKey(eKe case kYellow: return Delete(); case kInfo: case kBlue: return Info(); +#ifdef USE_SORTRECORDS + case k0: Setup.RecordingsSortMode = ++Setup.RecordingsSortMode % MAXSORTMODES; + Set(true); + Skins.Message(mtStatus, cString::sprintf("%s %d: %s", tr("Sorting"), Setup.RecordingsSortMode, RecordingsSortModeTexts[Setup.RecordingsSortMode])); + return osContinue; + case k1...k7: return Commands(Key); + case k8: return Rename(); + case k9: Recordings.ToggleSortOrder(); + Set(true); + return osContinue; +#elif defined (USE_LIEMIEXT) + case k0: DirOrderState = !DirOrderState; + Set(true); + return osContinue; + case k8: return Rename(); + case k9: + case k1...k7: return Commands(Key); +#else case k1...k9: return Commands(Key); +#endif /* LIEMIEXT & SORTRECORDS */ case kNone: if (Recordings.StateChanged(recordingsState)) Set(true); break; @@ -2199,6 +2988,9 @@ void cMenuSetupBase::Store(void) class cMenuSetupOSD : public cMenuSetupBase { private: const char *useSmallFontTexts[3]; +#ifdef USE_LIEMIEXT + const char *mainMenuTitle[MAXMAINMENUTITLE]; +#endif /* LIEMIEXT */ int osdLanguageIndex; int numSkins; int originalSkinIndex; @@ -2214,6 +3006,9 @@ public: cMenuSetupOSD(void); virtual ~cMenuSetupOSD(); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuSetupOsd"; } +#endif /* GRAPHTFT */ }; cMenuSetupOSD::cMenuSetupOSD(void) @@ -2249,12 +3044,21 @@ void cMenuSetupOSD::Set(void) useSmallFontTexts[0] = tr("never"); useSmallFontTexts[1] = tr("skin dependent"); useSmallFontTexts[2] = tr("always"); +#ifdef USE_LIEMIEXT + mainMenuTitle[0]=tr("default"); + mainMenuTitle[1]=tr("VDR - text"); + mainMenuTitle[2]=tr("text"); + mainMenuTitle[3]=tr("VDR - version"); +#endif /* LIEMIEXT */ Clear(); SetSection(tr("OSD")); Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &osdLanguageIndex, I18nNumLanguagesWithLocale(), &I18nLanguages()->At(0))); Add(new cMenuEditStraItem(tr("Setup.OSD$Skin"), &skinIndex, numSkins, skinDescriptions)); if (themes.NumThemes()) Add(new cMenuEditStraItem(tr("Setup.OSD$Theme"), &themeIndex, themes.NumThemes(), themes.Descriptions())); +#ifdef USE_WAREAGLEICON + Add(new cMenuEditBoolItem(tr("Setup.OSD$WarEagle icons"), &data.WarEagleIcons)); +#endif /* WAREAGLEICON */ Add(new cMenuEditIntItem( tr("Setup.OSD$Left"), &data.OSDLeft, 0, MAXOSDWIDTH)); Add(new cMenuEditIntItem( tr("Setup.OSD$Top"), &data.OSDTop, 0, MAXOSDHEIGHT)); Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDWidth, MINOSDWIDTH, MAXOSDWIDTH)); @@ -2276,6 +3080,24 @@ void cMenuSetupOSD::Set(void) Add(new cMenuEditBoolItem(tr("Setup.OSD$Scroll wraps"), &data.MenuScrollWrap)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Menu key closes"), &data.MenuKeyCloses)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs)); +#ifdef USE_LIEMIEXT + Add(new cMenuEditStraItem(tr("Setup.OSD$Main menu title"), &data.MainMenuTitle, MAXMAINMENUTITLE, mainMenuTitle)); + if (data.MainMenuTitle == 1 || data.MainMenuTitle == 2) + Add(new cMenuEditStrItem(tr("Setup.OSD$- Text"), data.CustomMainMenuTitle, sizeof(data.CustomMainMenuTitle))); + Add(new cMenuEditBoolItem(tr("Setup.OSD$Main menu command position"), &data.MenuCmdPosition, tr("bottom"), tr("top"))); +#endif /* LIEMIEXT */ +#ifdef USE_VALIDINPUT + Add(new cMenuEditBoolItem(tr("Setup.OSD$Show valid input"), &data.ShowValidInput)); +#endif /* VALIDINPUT */ +#ifdef USE_SOFTOSD + Add(new cMenuEditBoolItem(tr("Setup.OSD$Use SoftOSD"), &data.UseSoftOsd)); + if (data.UseSoftOsd) { + Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD Rate"), &data.SoftOsdRate, 10, 100)); + Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD FadeIn Steps"), &data.SoftOsdFadeinSteps, 1, 100)); + Add(new cMenuEditIntItem( tr("Setup.OSD$SoftOSD FadeOut Steps"), &data.SoftOsdFadeoutSteps, 1, 100)); + Add(new cMenuEditBoolItem(tr("Setup.OSD$SoftOSD Palette Only"), &data.SoftOsdPaletteOnly)); + } +#endif /* SOFTOSD */ SetCurrent(Get(current)); Display(); } @@ -2324,6 +3146,12 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys int oldSkinIndex = skinIndex; int oldOsdLanguageIndex = osdLanguageIndex; +#ifdef USE_LIEMIEXT + int oldMainMenuTitle = data.MainMenuTitle; +#endif /* LIEMIEXT */ +#ifdef USE_SOFTOSD + bool newUseSoftOsd = data.UseSoftOsd; +#endif /* SOFTOSD */ eOSState state = cMenuSetupBase::ProcessKey(Key); if (ModifiedApperance) @@ -2346,6 +3174,25 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys Set(); I18nSetLanguage(OriginalOSDLanguage); } + +#ifdef USE_LIEMIEXT + if (data.MainMenuTitle != oldMainMenuTitle) + Set(); +#endif /* LIEMIEXT */ +#ifdef USE_SOFTOSD + if (data.UseSoftOsd != newUseSoftOsd) + Set(); +#endif /* SOFTOSD */ +#ifdef USE_CMDRECCMDI18N + if (Key == kOk) { + // try to load translated command files if available, otherwise fallback to defaults + LoadCommandsI18n(Commands, AddDirectory(ConfigDirectory, "commands.conf"), true); + LoadCommandsI18n(RecordingCommands, AddDirectory(ConfigDirectory, "reccmds.conf"), true); +#ifdef USE_TIMERCMD + LoadCommandsI18n(TimerCommands, AddDirectory(ConfigDirectory, "timercmds.conf"), true); +#endif /* TIMERCMD */ + } +#endif /* CMDRECCMDI18N */ return state; } @@ -2353,12 +3200,18 @@ eOSState cMenuSetupOSD::ProcessKey(eKeys class cMenuSetupEPG : public cMenuSetupBase { private: +#ifdef USE_NOEPG + const char *noEPGModes[2]; +#endif /* NOEPG */ int originalNumLanguages; int numLanguages; void Setup(void); public: cMenuSetupEPG(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuSetupEpg"; } +#endif /* GRAPHTFT */ }; cMenuSetupEPG::cMenuSetupEPG(void) @@ -2375,11 +3228,19 @@ void cMenuSetupEPG::Setup(void) { int current = Current(); +#ifdef USE_NOEPG + noEPGModes[0] = tr("blacklist"); + noEPGModes[1] = tr("whitelist"); +#endif /* NOEPG */ + Clear(); Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout)); Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); Add(new cMenuEditIntItem( tr("Setup.EPG$EPG linger time (min)"), &data.EPGLinger, 0)); +#ifdef USE_LIEMIEXT + Add(new cMenuEditBoolItem(tr("Setup.EPG$Show progress bar"), &data.ShowProgressBar)); +#endif /* LIEMIEXT */ Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime)); if (data.SetSystemTime) Add(new cMenuEditTranItem(tr("Setup.EPG$Use time from transponder"), &data.TimeTransponder, &data.TimeSource)); @@ -2388,6 +3249,15 @@ void cMenuSetupEPG::Setup(void) for (int i = 0; i < numLanguages; i++) // TRANSLATORS: note the singular! Add(new cMenuEditStraItem(tr("Setup.EPG$Preferred language"), &data.EPGLanguages[i], I18nLanguages()->Size(), &I18nLanguages()->At(0))); +#ifdef USE_DDEPGENTRY + Add(new cMenuEditIntItem( tr("Setup.EPG$Period for double EPG search(min)"), &data.DoubleEpgTimeDelta)); + Add(new cMenuEditBoolItem(tr("Setup.EPG$Extern double Epg entry"), &data.DoubleEpgAction, tr("adjust"), tr("delete"))); + Add(new cMenuEditBoolItem(tr("Setup.EPG$Mix intern and extern EPG"), &data.MixEpgAction)); + Add(new cMenuEditBoolItem(tr("Setup.EPG$Disable running VPS event"), &data.DisableVPS)); +#endif /* DDEPGENTRY */ +#ifdef USE_NOEPG + Add(new cMenuEditStraItem(tr("Setup.EPG$Mode of noEPG-Patch"), &data.noEPGMode, 2, noEPGModes)); +#endif /* NOEPG */ SetCurrent(Get(current)); Display(); @@ -2444,6 +3314,10 @@ eOSState cMenuSetupEPG::ProcessKey(eKeys class cMenuSetupDVB : public cMenuSetupBase { private: +#ifdef USE_DVBSETUP + const char *ChannelBlockers[7]; + const char *ChannelBlockerModes[4]; +#endif /* DVBSETUP */ int originalNumAudioLanguages; int numAudioLanguages; int originalNumSubtitleLanguages; @@ -2454,6 +3328,9 @@ private: public: cMenuSetupDVB(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuSetupDvb"; } +#endif /* GRAPHTFT */ }; cMenuSetupDVB::cMenuSetupDVB(void) @@ -2482,6 +3359,21 @@ void cMenuSetupDVB::Setup(void) { int current = Current(); +#ifdef USE_DVBSETUP + ChannelBlockers[0] = tr("none"); + ChannelBlockers[1] = tr("qam256"); + ChannelBlockers[2] = tr("dvb-c"); + ChannelBlockers[3] = tr("dvb-s"); + ChannelBlockers[4] = tr("blacklist"); + ChannelBlockers[5] = tr("whitelist"); + ChannelBlockers[6] = tr("all"); + + ChannelBlockerModes[0] = tr("none"); + ChannelBlockerModes[1] = tr("has decoder"); + ChannelBlockerModes[2] = tr("is primary"); + ChannelBlockerModes[3] = tr("has decoder + is primary"); +#endif /* DVBSETUP */ + Clear(); Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices())); @@ -2502,6 +3394,14 @@ void cMenuSetupDVB::Setup(void) Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle foreground transparency"), &data.SubtitleFgTransparency, 0, 9)); Add(new cMenuEditIntItem( tr("Setup.DVB$Subtitle background transparency"), &data.SubtitleBgTransparency, 0, 10)); } +#ifdef USE_DVBSETUP + Add(new cMenuEditBoolItem(tr("Setup.DVB$Use AC3-Transfer Fix"), &data.DolbyTransferFix)); + Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker"), &data.ChannelBlocker, 7, ChannelBlockers)); + Add(new cMenuEditStraItem(tr("Setup.DVB$Channel Blocker Filter Mode"), &data.ChannelBlockerMode, 4, ChannelBlockerModes)); +#endif /* DVBSETUP */ +#ifdef USE_SYNCEARLY + Add(new cMenuEditBoolItem(tr("Setup.DVB$Use Sync Early Patch"), &data.UseSyncEarlyPatch)); +#endif /* SYNCEARLY */ SetCurrent(Get(current)); Display(); @@ -2583,6 +3483,9 @@ private: public: cMenuSetupLNB(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuSetupLnb"; } +#endif /* GRAPHTFT */ }; cMenuSetupLNB::cMenuSetupLNB(void) @@ -2597,6 +3500,23 @@ void cMenuSetupLNB::Setup(void) Clear(); +#ifdef USE_LNBSHARE + int numSatDevices = 0; + for (int i = 0; i < cDevice::NumDevices(); i++) { + if (cDevice::GetDevice(i)->ProvidesSource(cSource::stSat)) numSatDevices++; + } + if (numSatDevices > 1) { + char tmp[30]; + for (int i = 1; i <= cDevice::NumDevices(); i++) { + if (cDevice::GetDevice(i - 1)->ProvidesSource(cSource::stSat)) { + sprintf( tmp, tr("Setup.LNB$DVB device %d uses LNB No."), i); + Add(new cMenuEditIntItem( tmp, &data.CardUsesLNBnr[i - 1], 1, numSatDevices )); + } + } + } + Add(new cMenuEditBoolItem(tr("Setup.LNB$Log LNB usage"), &data.VerboseLNBlog)); +#endif /* LNBSHARE */ + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); if (!data.DiSEqC) { Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); @@ -2613,6 +3533,10 @@ eOSState cMenuSetupLNB::ProcessKey(eKeys int oldDiSEqC = data.DiSEqC; eOSState state = cMenuSetupBase::ProcessKey(Key); +#ifdef USE_LNBSHARE + if (Key == kOk) cDevice::SetLNBnr(); +#endif /* LNBSHARE */ + if (Key != kNone && data.DiSEqC != oldDiSEqC) Setup(); return state; @@ -2663,6 +3587,9 @@ private: public: cMenuSetupCAM(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuSetupCam"; } +#endif /* GRAPHTFT */ }; cMenuSetupCAM::cMenuSetupCAM(void) @@ -2736,12 +3663,73 @@ eOSState cMenuSetupCAM::ProcessKey(eKeys // --- cMenuSetupRecord ------------------------------------------------------ class cMenuSetupRecord : public cMenuSetupBase { +#ifdef USE_SORTRECORDS +private: + const char *RecordingsSortModeTexts[MAXSORTMODES]; +#endif /* SORTRECORDS */ +#ifdef USE_DELTIMESHIFTREC +private: + const char *DelTimeshiftRecValues[3]; +#endif /* DELTIMESHIFTREC */ public: cMenuSetupRecord(void); +#ifdef USE_DVLVIDPREFER + eOSState ProcessKey(eKeys key); + +private: + void Set(void); + + int tmpNVidPrefer, + tmpUseVidPrefer; +#endif /* DVLVIDPREFER */ }; +#ifdef USE_DVLVIDPREFER cMenuSetupRecord::cMenuSetupRecord(void) { + Set(); +} + +eOSState cMenuSetupRecord::ProcessKey(eKeys key) +{ + eOSState s = cMenuSetupBase::ProcessKey(key);; + + if (key != kNone) { + if (tmpNVidPrefer != data.nVidPrefer || tmpUseVidPrefer != data.UseVidPrefer) { + int cur = Current(); + + tmpNVidPrefer = data.nVidPrefer; + tmpUseVidPrefer = data.UseVidPrefer; + + Clear(); + Set(); + SetCurrent(Get(cur)); + Display(); + cMenuSetupBase::ProcessKey(kNone); + return osContinue; + } + } + return s; +} + +#else +cMenuSetupRecord::cMenuSetupRecord(void) +#endif /* DVLVIDPREFER */ +#ifdef USE_DVLVIDPREFER +void cMenuSetupRecord::Set(void) +#endif /* DVLVIDPREFER */ +{ +#ifdef USE_SORTRECORDS + RecordingsSortModeTexts[0] = tr("main dir alphabetically, subdirs flexible"); + RecordingsSortModeTexts[1] = tr("main dir by date, subdirs flexible"); + RecordingsSortModeTexts[2] = tr("all alphabetically"); + RecordingsSortModeTexts[3] = tr("all by date"); +#endif /* SORTRECORDS */ +#ifdef USE_DELTIMESHIFTREC + DelTimeshiftRecValues[0] = tr("request"); + DelTimeshiftRecValues[1] = tr("no"); + DelTimeshiftRecValues[2] = tr("yes"); +#endif /* DELTIMESHIFTREC */ SetSection(tr("Recording")); Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart)); Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop)); @@ -2750,14 +3738,61 @@ cMenuSetupRecord::cMenuSetupRecord(void) Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME)); Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME)); +#ifdef USE_DOLBYINREC + Add(new cMenuEditBoolItem(tr("Setup.Recording$Record Dolby Digital"), &data.UseDolbyInRecordings)); +#endif /* DOLBYINREC */ +#ifdef USE_DVLVIDPREFER + tmpNVidPrefer = data.nVidPrefer; + tmpUseVidPrefer = data.UseVidPrefer; + + Add(new cMenuEditBoolItem(tr("Setup.Recording$Video directory policy"), &data.UseVidPrefer)); + if (data.UseVidPrefer != 0) { + char tmp[ 64 ]; + Add(new cMenuEditIntItem(tr("Setup.Recording$Number of video directories"), &data.nVidPrefer, 1, DVLVIDPREFER_MAX)); + for (int zz = 0; zz < data.nVidPrefer; zz++) { + sprintf(tmp, tr("Setup.Recording$Video %d priority"), zz); + Add(new cMenuEditIntItem(tmp, &data.VidPreferPrio[ zz ], 0, 99)); + sprintf(tmp, tr("Setup.Recording$Video %d min. free MB"), zz); + Add(new cMenuEditIntItem(tmp, &data.VidPreferSize[ zz ], -1, 99999)); + } + } +#endif /* DVLVIDPREFER */ Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); +#ifdef USE_DVLFRIENDLYFNAMES + Add(new cMenuEditBoolItem(tr("Setup.Recording$Friendly filenames"), &data.UseFriendlyFNames)); +#endif /* DVLFRIENDLYFNAMES */ Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps)); Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0)); Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord)); Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord))); Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME)); Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE)); +#ifdef USE_HARDLINKCUTTER + Add(new cMenuEditIntItem( tr("Setup.Recording$Max. recording size (GB)"), &data.MaxRecordingSize, MINRECORDINGSIZE, MAXRECORDINGSIZE)); +#endif /* HARDLINKCUTTER */ Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); +#ifdef USE_HARDLINKCUTTER + Add(new cMenuEditBoolItem(tr("Setup.Recording$Hard Link Cutter"), &data.HardLinkCutter)); +#endif /* HARDLINKCUTTER */ +#ifdef USE_DELTIMESHIFTREC + Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"), &data.DelTimeshiftRec, 3, DelTimeshiftRecValues)); +#endif /* DELTIMESHIFTREC */ +#ifdef USE_LIEMIEXT + Add(new cMenuEditBoolItem(tr("Setup.Recording$Show date"), &data.ShowRecDate)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Show time"), &data.ShowRecTime)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Show length"), &data.ShowRecLength)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Show end of timer"), &data.ShowTimerStop)); +#endif /* LIEMIEXT */ +#ifdef USE_SORTRECORDS + Add(new cMenuEditStraItem(tr("Setup.Recording$Sort recordings by"), &data.RecordingsSortMode, MAXSORTMODES, RecordingsSortModeTexts)); + Add(new cMenuEditBoolItem(tr("Setup.Recording$Sort directories before recordings"), &data.RecordingsSortDirsFirst)); +#endif /* SORTRECORDS */ +#ifdef USE_CUTTERQUEUE + Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter auto delete"), &data.CutterAutoDelete)); +#endif /* CUTTERQUEUE */ +#ifdef USE_CUTTIME + Add(new cMenuEditBoolItem(tr("Setup.Recording$Cutter adjust starttime"), &data.CutTime)); +#endif /* CUTTIME */ } // --- cMenuSetupReplay ------------------------------------------------------ @@ -2775,6 +3810,31 @@ cMenuSetupReplay::cMenuSetupReplay(void) Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode)); Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode)); Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99)); +#ifdef USE_JUMPPLAY + Add(new cMenuEditBoolItem(tr("Setup.Replay$Jump&Play"), &data.JumpPlay)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Play&Jump"), &data.PlayJump)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause at last mark"), &data.PauseLastMark)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Reload marks"), &data.ReloadMarks)); +#endif /* JUMPPLAY */ +#ifdef USE_LIEMIEXT + Add(new cMenuEditIntItem(tr("Setup.Replay$Skip Seconds"), &data.JumpSeconds)); + Add(new cMenuEditIntItem(tr("Setup.Replay$Skip Seconds Slow"), &data.JumpSecondsSlow)); +#endif /* LIEMIEXT */ +#ifdef USE_DVDARCHIVE + static const char *dvddisplaymode[3]; + dvddisplaymode[0]=tr("Setup.Replay$Length"); + dvddisplaymode[1]=tr("Setup.Replay$Length / Number"); + dvddisplaymode[2]=tr("Setup.Replay$Number"); + Add(new cMenuEditStraItem(tr("Setup.Replay$DVD display mode"), &data.DvdDisplayMode,3,dvddisplaymode)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$DVD display leading zeros"), &data.DvdDisplayZeros)); + static const char *dvdtraymode[4]; + dvdtraymode[0]=tr("Setup.Replay$never"); + dvdtraymode[1]=tr("Setup.Replay$on begin"); + dvdtraymode[2]=tr("Setup.Replay$on end"); + dvdtraymode[3]=tr("Setup.Replay$on begin and end"); + Add(new cMenuEditStraItem(tr("Setup.Replay$Tray open"), &data.DvdTrayMode,4,dvdtraymode)); + Add(new cMenuEditIntItem( tr("Setup.Replay$Limit DVD to speed"), &data.DvdSpeedLimit, 0, 50)); +#endif /* DVDARCHIVE */ } void cMenuSetupReplay::Store(void) @@ -2787,13 +3847,48 @@ void cMenuSetupReplay::Store(void) // --- cMenuSetupMisc -------------------------------------------------------- class cMenuSetupMisc : public cMenuSetupBase { +#ifdef USE_VOLCTRL +private: + const char *lrChannelGroupsTexts[3]; + const char *lrForwardRewindTexts[3]; + void Setup(void); +#endif /* VOLCTRL */ public: cMenuSetupMisc(void); +#ifdef USE_VOLCTRL + virtual eOSState ProcessKey(eKeys Key); +#endif /* VOLCTRL */ }; cMenuSetupMisc::cMenuSetupMisc(void) { +#ifdef USE_VOLCTRL + lrChannelGroupsTexts[0] = tr("no"); + lrChannelGroupsTexts[1] = tr("Setup.Miscellaneous$only in channelinfo"); + lrChannelGroupsTexts[2] = tr("yes"); + lrForwardRewindTexts[0] = tr("no"); + lrForwardRewindTexts[1] = tr("Setup.Miscellaneous$only in progress display"); + lrForwardRewindTexts[2] = tr("yes"); +#endif /* VOLCTRL */ SetSection(tr("Miscellaneous")); +#ifdef USE_VOLCTRL + Setup(); +} + +eOSState cMenuSetupMisc::ProcessKey(eKeys Key) +{ + int newLRVolumeControl = data.LRVolumeControl; + eOSState state = cMenuSetupBase::ProcessKey(Key); + if (Key != kNone && data.LRVolumeControl != newLRVolumeControl) + Setup(); + return state; +} + +void cMenuSetupMisc::Setup(void) +{ + int current = Current(); + Clear(); +#endif /* VOLCTRL */ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout)); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity)); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout)); @@ -2801,9 +3896,77 @@ cMenuSetupMisc::cMenuSetupMisc(void) Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Channel entry timeout (ms)"), &data.ChannelEntryTimeout, 0)); Add(new cMenuEditChanItem(tr("Setup.Miscellaneous$Initial channel"), &data.InitialChannel, tr("Setup.Miscellaneous$as before"))); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Initial volume"), &data.InitialVolume, -1, 255, tr("Setup.Miscellaneous$as before"))); +#ifdef USE_VOLCTRL + Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Volume ctrl with left/right"), &data.LRVolumeControl)); + if (data.LRVolumeControl) { + Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Channelgroups with left/right"), &data.LRChannelGroups, 3, lrChannelGroupsTexts)); + Add(new cMenuEditStraItem(tr("Setup.Miscellaneous$Search fwd/back with left/right"), &data.LRForwardRewind, 3, lrForwardRewindTexts)); + } + SetCurrent(Get(current)); + Display(); +#endif /* VOLCTRL */ Add(new cMenuEditBoolItem(tr("Setup.Miscellaneous$Emergency exit"), &data.EmergencyExit)); +#ifdef USE_LIRCSETTINGS + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat delay"), &data.LircRepeatDelay, 0, 1000)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat freq"), &data.LircRepeatFreq, 0, 1000)); + Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Lirc repeat timeout"), &data.LircRepeatTimeout, 0, 5000)); +#endif /* LIRCSETTINGS */ +} + +#ifdef USE_LIVEBUFFER +// --- cMenuSetupLiveBuffer -------------------------------------------------- + +class cMenuSetupLiveBuffer : public cMenuSetupBase { +private: + void Setup(); +public: + eOSState ProcessKey(eKeys Key); + cMenuSetupLiveBuffer(void); + }; + +cMenuSetupLiveBuffer::cMenuSetupLiveBuffer(void) +{ + SetSection("permanentes Timeshift"); + Setup(); } +void cMenuSetupLiveBuffer::Setup(void) +{ + int current=Current(); + Clear(); + Add(new cMenuEditBoolItem(tr("Permanent Timeshift"), &data.LiveBuffer)); + if (data.LiveBuffer) { + Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Location"), &data.InRAM,tr("Setup.LiveBuffer$harddisk"),tr("Setup.LiveBuffer$memory"))); + if (data.InRAM) { + Add(new cMenuEditIntItem( tr("Setup.LiveBuffer$Buffer size in memory (MB)"), &data.MemBufSize, 5, 1000)); + Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Extend to harddisk if necessary"), &data.ExtendBuffer)); + Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Keep paused Buffer"), &data.KeepPaused)); + if (data.ExtendBuffer || data.KeepPaused) + Add(new cMenuEditIntItem(tr("Setup.LiveBuffer$Buffer size on harddisk (MB)"), &data.LiveBufferSize, 1, 100000)); + } + else { + Add(new cMenuEditIntItem( tr("Setup.LiveBuffer$Buffer size (MB)"), &data.LiveBufferSize, 1, 100000)); + Add(new cMenuEditBoolItem(tr("Setup.LiveBuffer$Keep paused Buffer"), &data.KeepPaused)); + } + } + SetCurrent(Get(current)); + Display(); +} + +eOSState cMenuSetupLiveBuffer::ProcessKey(eKeys Key) +{ + int oldLiveBuffer = data.LiveBuffer; + int oldInRAM = data.InRAM; + int oldExtendBuffer = data.ExtendBuffer; + int oldKeepPaused = data.KeepPaused; + eOSState state = cMenuSetupBase::ProcessKey(Key); + + if (Key != kNone && (data.LiveBuffer != oldLiveBuffer || data.InRAM != oldInRAM || data.ExtendBuffer != oldExtendBuffer || data.KeepPaused != oldKeepPaused)) + Setup(); + return state; +} + +#endif /* LIVEBUFFER */ // --- cMenuSetupPluginItem -------------------------------------------------- class cMenuSetupPluginItem : public cOsdItem { @@ -2826,6 +3989,9 @@ class cMenuSetupPlugins : public cMenuSe public: cMenuSetupPlugins(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuSetupPlugins"; } +#endif /* GRAPHTFT */ }; cMenuSetupPlugins::cMenuSetupPlugins(void) @@ -2875,6 +4041,9 @@ private: public: cMenuSetup(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuSetup"; } +#endif /* GRAPHTFT */ }; cMenuSetup::cMenuSetup(void) @@ -2898,6 +4067,9 @@ void cMenuSetup::Set(void) Add(new cOsdItem(hk(tr("Recording")), osUser6)); Add(new cOsdItem(hk(tr("Replay")), osUser7)); Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8)); +#ifdef USE_LIVEBUFFER + Add(new cOsdItem(hk(tr("Permanent Timeshift")),osLiveBuffer)); +#endif /* LIVEBUFFER */ if (cPluginManager::HasPlugins()) Add(new cOsdItem(hk(tr("Plugins")), osUser9)); Add(new cOsdItem(hk(tr("Restart")), osUser10)); @@ -2928,6 +4100,9 @@ eOSState cMenuSetup::ProcessKey(eKeys Ke case osUser8: return AddSubMenu(new cMenuSetupMisc); case osUser9: return AddSubMenu(new cMenuSetupPlugins); case osUser10: return Restart(); +#ifdef USE_LIVEBUFFER + case osLiveBuffer: return AddSubMenu(new cMenuSetupLiveBuffer); +#endif /* LIVEBUFFER */ default: ; } if (I18nCurrentLanguage() != osdLanguage) { @@ -2964,24 +4139,91 @@ cOsdObject *cMenuMain::pluginOsdObject = cMenuMain::cMenuMain(eOSState State) :cOsdMenu("") { +#ifdef USE_SETUP + // Load Menu Configuration + char *menuXML = NULL; + asprintf(&menuXML, "%s/setup/vdr-menu.%s.xml", cPlugin::ConfigDirectory(), Setup.OSDLanguage); + if (access(menuXML, 04) == -1) + asprintf(&menuXML, "%s/setup/vdr-menu.xml", cPlugin::ConfigDirectory()); + subMenu.LoadXml(menuXML); + free(menuXML); + nrDynamicMenuEntries=0; +#endif /* SETUP */ replaying = false; stopReplayItem = NULL; cancelEditingItem = NULL; stopRecordingItem = NULL; recordControlsState = 0; + +#ifdef USE_MENUORG + MenuOrgPatch::EnterRootMenu(); +#endif /* MENUORG */ + Set(); // Initial submenus: +#ifdef USE_MAINMENUHOOKS + cOsdMenu *menu = NULL; +#endif /* MAINMENUHOOKS */ switch (State) { +#ifdef USE_MAINMENUHOOKS + case osSchedule: + { + cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu); + if (p && !menu) + isyslog("MainMenuHook::osSchedule: plugin %s claims to support service but didn't return menu", p->Name()); + + if (!menu) + menu = new cMenuSchedule; + } + break; + case osChannels: + { + cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu); + if (p && !menu) + isyslog("MainMenuHook::osChannels: plugin %s claims to support service but didn't return menu", p->Name()); + + if (!menu) + menu = new cMenuChannels; + } + break; + case osTimers: + { + cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu); + if (p && !menu) + isyslog("MainMenuHook::osTimers: plugin %s claims to support service but didn't return menu", p->Name()); + + if (!menu) + menu = new cMenuTimers; + } + break; + case osRecordings: + { + cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu); + if (p && !menu) + isyslog("MainMenuHook::osRecordings: plugin %s claims to support service but didn't return menu", p->Name()); + + if (!menu) + menu = new cMenuRecordings(NULL, 0, true); + } + break; + case osSetup: menu = new cMenuSetup; break; + case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; +#else case osSchedule: AddSubMenu(new cMenuSchedule); break; case osChannels: AddSubMenu(new cMenuChannels); break; case osTimers: AddSubMenu(new cMenuTimers); break; case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break; case osSetup: AddSubMenu(new cMenuSetup); break; case osCommands: AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); break; +#endif /* MAINMENUHOOKS */ default: break; } +#ifdef USE_MAINMENUHOOKS + if (menu) + AddSubMenu(menu); +#endif /* MAINMENUHOOKS */ } cOsdObject *cMenuMain::PluginOsdObject(void) @@ -2991,38 +4233,155 @@ cOsdObject *cMenuMain::PluginOsdObject(v return o; } +#ifdef USE_SETUP +void cMenuMain::Set(int current) +#else void cMenuMain::Set(void) +#endif /* SETUP */ { Clear(); SetTitle("VDR"); SetHasHotkeys(); +#ifdef USE_MENUORG + if (MenuOrgPatch::IsCustomMenuAvailable()) { + MenuItemDefinitions* menuItems = MenuOrgPatch::MainMenuItems(); + for (MenuItemDefinitions::iterator i = menuItems->begin(); i != menuItems->end(); i++) { + cOsdItem* osdItem = NULL; + if ((*i)->IsCustomOsdItem()) { + osdItem = (*i)->CustomOsdItem(); + if (osdItem && !(*i)->IsSeparatorItem()) + osdItem->SetText(hk(osdItem->Text())); + } + else if ((*i)->IsPluginItem()) { + const char *item = (*i)->PluginMenuEntry(); + if (item) + osdItem = new cMenuPluginItem(hk(item), (*i)->PluginIndex()); + } + if (osdItem) { + Add(osdItem); + if ((*i)->IsSelected()) + SetCurrent(osdItem); + } + } + } + else { +#endif /* MENUORG */ + +#ifdef USE_SETUP + stopReplayItem = NULL; + cancelEditingItem = NULL; + stopRecordingItem = NULL; + + // remember initial dynamic MenuEntries added + nrDynamicMenuEntries = Count(); + for (cSubMenuNode *node = subMenu.GetMenuTree()->First(); node; node = subMenu.GetMenuTree()->Next(node)) { + cSubMenuNode::Type type = node->GetType(); + if (type==cSubMenuNode::PLUGIN) { + const char *item = node->GetPluginMainMenuEntry(); +#ifdef USE_PINPLUGIN + if (item && !cStatus::MsgPluginProtected(cPluginManager::GetPlugin(node->GetPluginIndex()), true)) +#else + if (item) +#endif /* PINPLUGIN */ + Add(new cMenuPluginItem(hk(item), node->GetPluginIndex())); + } + else if (type==cSubMenuNode::MENU) { + cString item = cString::sprintf("%s%s", node->GetName(), subMenu.GetMenuSuffix()); +#ifdef USE_PINPLUGIN + if (!cStatus::MsgMenuItemProtected(item, true)) + Add(new cOsdItem(hk(item), osUnknown, node)); +#else + Add(new cOsdItem(hk(item))); +#endif /* PINPLUGIN */ + } + else if ((type==cSubMenuNode::COMMAND) || (type==cSubMenuNode::THREAD)) { +#ifdef USE_PINPLUGIN + if (!cStatus::MsgMenuItemProtected(node->GetName(), true)) + Add(new cOsdItem(hk(node->GetName()), osUnknown, node)); +#else + Add(new cOsdItem(hk(node->GetName()))); +#endif /* PINPLUGIN */ + } + else if (type==cSubMenuNode::SYSTEM) { + const char *item = node->GetName(); +#ifdef USE_PINPLUGIN + if (cStatus::MsgMenuItemProtected(item, true)) + ; // nothing to do ;) + else +#endif /* PINPLUGIN */ + if (strcmp(item, "Schedule") == 0) + Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); + else if (strcmp(item, "Channels") == 0) + Add(new cOsdItem(hk(tr("Channels")), osChannels)); + else if (strcmp(item, "Timers") == 0) + Add(new cOsdItem(hk(tr("Timers")), osTimers)); + else if (strcmp(item, "Recordings") == 0) + Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); + else if (strcmp(item, "Setup") == 0) + Add(new cOsdItem(hk(tr("Setup")), osSetup)); + else if (strcmp(item, "Commands") == 0 && Commands.Count()>0) + Add(new cOsdItem(hk(tr("Commands")), osCommands)); + } + } + if (current >=0 && currentMainMenuEntry(); if (item) Add(new cMenuPluginItem(hk(item), i)); } +#ifdef USE_PINPLUGIN + } +#endif /* PINPLUGIN */ else break; } // More basic menu items: +#ifdef USE_PINPLUGIN + if (!cStatus::MsgMenuItemProtected("Setup", true)) Add(new cOsdItem(hk(tr("Setup")), osSetup)); +#else Add(new cOsdItem(hk(tr("Setup")), osSetup)); +#endif /* PINPLUGIN */ if (Commands.Count()) +#ifdef USE_PINPLUGIN + if (!cStatus::MsgMenuItemProtected("Commands", true)) +#endif /* PINPLUGIN */ Add(new cOsdItem(hk(tr("Commands")), osCommands)); +#endif /* SETUP */ + +#ifdef USE_MENUORG + } +#endif /* MENUORG */ + Update(true); Display(); @@ -3032,12 +4391,40 @@ bool cMenuMain::Update(bool Force) { bool result = false; +#ifdef USE_SETUP + cOsdItem *fMenu = NULL; + if (Force && subMenu.isTopMenu()) { + fMenu = First(); + nrDynamicMenuEntries = 0; + } + + if (subMenu.isTopMenu()) { +#endif /* SETUP */ +#ifdef USE_LIEMIEXT +// this extension is not included in the original Liemikuutio + if (Setup.MainMenuTitle) { + if (Setup.MainMenuTitle == 1) + SetTitle(cString::sprintf("%s - %s", tr("VDR"), Setup.CustomMainMenuTitle)); + else if (Setup.MainMenuTitle == 2) + SetTitle(cString::sprintf("%s", Setup.CustomMainMenuTitle)); + else if (Setup.MainMenuTitle == 3) + SetTitle(cString::sprintf("%s %s", tr("VDR"), VDRVERSION)); + } + else +#endif /* LIEMIEXT */ // Title with disk usage: if (FreeDiskSpace.HasChanged(Force)) { //XXX -> skin function!!! SetTitle(cString::sprintf("%s - %s", tr("VDR"), FreeDiskSpace.FreeDiskSpaceString())); result = true; } +#ifdef USE_SETUP + } + else { + SetTitle(cString::sprintf("%s - %s", tr("VDR"), subMenu.GetParentMenuTitel())); + result = true; + } +#endif /* SETUP */ bool NewReplaying = cControl::Control() != NULL; if (Force || NewReplaying != replaying) { @@ -3045,6 +4432,9 @@ bool cMenuMain::Update(bool Force) // Replay control: if (replaying && !stopReplayItem) // TRANSLATORS: note the leading blank! +#ifdef USE_LIEMIEXT + if (Setup.MenuCmdPosition) Ins(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); else +#endif /* LIEMIEXT */ Add(stopReplayItem = new cOsdItem(tr(" Stop replaying"), osStopReplay)); else if (stopReplayItem && !replaying) { Del(stopReplayItem->Index()); @@ -3059,6 +4449,9 @@ bool cMenuMain::Update(bool Force) bool CutterActive = cCutter::Active(); if (CutterActive && !cancelEditingItem) { // TRANSLATORS: note the leading blank! +#ifdef USE_LIEMIEXT + if (Setup.MenuCmdPosition) Ins(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); else +#endif /* LIEMIEXT */ Add(cancelEditingItem = new cOsdItem(tr(" Cancel editing"), osCancelEdit)); result = true; } @@ -3079,6 +4472,9 @@ bool cMenuMain::Update(bool Force) while ((s = cRecordControls::GetInstantId(s)) != NULL) { cOsdItem *item = new cOsdItem(osStopRecord); item->SetText(cString::sprintf("%s%s", tr(STOP_RECORDING), s)); +#ifdef USE_LIEMIEXT + if (Setup.MenuCmdPosition) Ins(item); else +#endif /* LIEMIEXT */ Add(item); if (!stopRecordingItem) stopRecordingItem = item; @@ -3086,6 +4482,12 @@ bool cMenuMain::Update(bool Force) result = true; } +#ifdef USE_SETUP + // adjust nrDynamicMenuEntries + if (fMenu != NULL) + nrDynamicMenuEntries = fMenu->Index(); +#endif /* SETUP */ + return result; } @@ -3096,13 +4498,69 @@ eOSState cMenuMain::ProcessKey(eKeys Key eOSState state = cOsdMenu::ProcessKey(Key); HadSubMenu |= HasSubMenu(); +#ifdef USE_PINPLUGIN + cOsdItem* item = Get(Current()); + + if (item && item->Text() && state != osBack && state != osContinue && Key != kNone) + if (cStatus::MsgMenuItemProtected(item->Text())) + return osContinue; +#endif /* PINPLUGIN */ + +#ifdef USE_MAINMENUHOOKS + cOsdMenu *menu = NULL; +#endif /* MAINMENUHOOKS */ switch (state) { +#ifdef USE_MAINMENUHOOKS + case osSchedule: + { + cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu); + if (p && !menu) + isyslog("MainMenuHook::osSchedule: plugin %s claims to support service but didn't return menu", p->Name()); + + if (!menu) + menu = new cMenuSchedule; + } + break; + case osChannels: + { + cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu); + if (p && !menu) + isyslog("MainMenuHook::osChannels: plugin %s claims to support service but didn't return menu", p->Name()); + + if (!menu) + menu = new cMenuChannels; + } + break; + case osTimers: + { + cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu); + if (p && !menu) + isyslog("MainMenuHook::osTimers: plugin %s claims to support service but didn't return menu", p->Name()); + + if (!menu) + menu = new cMenuTimers; + } + break; + case osRecordings: + { + cPlugin *p = cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu); + if (p && !menu) + isyslog("MainMenuHook::osRecordings: plugin %s claims to support service but didn't return menu", p->Name()); + + if (!menu) + menu = new cMenuRecordings; + } + break; + case osSetup: menu = new cMenuSetup; break; + case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; +#else case osSchedule: return AddSubMenu(new cMenuSchedule); case osChannels: return AddSubMenu(new cMenuChannels); case osTimers: return AddSubMenu(new cMenuTimers); case osRecordings: return AddSubMenu(new cMenuRecordings); case osSetup: return AddSubMenu(new cMenuSetup); case osCommands: return AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); +#endif /* MAINMENUHOOKS */ case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { cOsdItem *item = Get(Current()); if (item) { @@ -3121,6 +4579,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key if (item) { cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); if (p) { +#ifdef USE_PINPLUGIN + if (!cStatus::MsgPluginProtected(p)) { +#endif /* PINPLUGIN */ cOsdObject *menu = p->MainMenuAction(); if (menu) { if (menu->IsMenu()) @@ -3132,9 +4593,60 @@ eOSState cMenuMain::ProcessKey(eKeys Key } } } +#ifdef USE_PINPLUGIN + } +#endif /* PINPLUGIN */ state = osEnd; } break; +#ifdef USE_SETUP + case osBack: { + int newCurrent = 0; + if (subMenu.Up(&newCurrent)) { + Set(newCurrent); + return osContinue; + } + else + return osEnd; + } + break; +#endif /* SETUP */ +#ifdef USE_MENUORG + case osBack: { + if (MenuOrgPatch::IsCustomMenuAvailable()) { + bool leavingMenuSucceeded = MenuOrgPatch::LeaveSubMenu(); + Set(); + stopReplayItem = NULL; + cancelEditingItem = NULL; + stopRecordingItem = NULL; + recordControlsState = 0; + Update(true); + Display(); + if (leavingMenuSucceeded) + return osContinue; + else + return osEnd; + } + } + break; + case osUser1: { + if (MenuOrgPatch::IsCustomMenuAvailable()) { + MenuOrgPatch::EnterSubMenu(Get(Current())); + Set(); + return osContinue; + } + } + break; + case osUser2: { + if (MenuOrgPatch::IsCustomMenuAvailable()) { + cOsdMenu* osdMenu = MenuOrgPatch::Execute(Get(Current())); + if (osdMenu) + return AddSubMenu(osdMenu); + return osEnd; + } + } + break; +#endif /* MENUORG */ default: switch (Key) { case kRecord: case kRed: if (!HadSubMenu) @@ -3151,9 +4663,67 @@ eOSState cMenuMain::ProcessKey(eKeys Key case kBlue: if (!HadSubMenu) state = replaying ? osStopReplay : cReplayControl::LastReplayed() ? osReplay : osContinue; break; +#ifdef USE_SETUP + case kOk: if (state == osUnknown) { + cString buffer; +#ifdef USE_PINPLUGIN + cSubMenuNode *node = Get(Current())->SubMenu(); +#else + int index = Current()-nrDynamicMenuEntries; + cSubMenuNode *node = subMenu.GetNode(index); +#endif /* PINPLUGIN */ + + if (node != NULL) { + if (node->GetType() == cSubMenuNode::MENU) { +#ifdef USE_PINPLUGIN + subMenu.Down(node, Current()); +#else + subMenu.Down(index); +#endif /* PINPLUGIN */ + } + else if (node->GetType() == cSubMenuNode::COMMAND) { + bool confirmed = true; + if (node->CommandConfirm()) { + buffer = cString::sprintf("%s?", node->GetName()); + confirmed = Interface->Confirm(buffer); + } + if (confirmed) { + const char *Result = subMenu.ExecuteCommand(node->GetCommand()); + if (Result) + return AddSubMenu(new cMenuText(node->GetName(), Result, fontFix)); + return osEnd; + } + } + else if (node->GetType() == cSubMenuNode::THREAD) { + bool confirmed = true; + if (node->CommandConfirm()) { + buffer = cString::sprintf("%s?", node->GetName()); + confirmed = Interface->Confirm(buffer); + } + if (confirmed) { + buffer = cString::sprintf("%s", node->GetCommand()); + cExecCmdThread *execcmd = new cExecCmdThread(node->GetCommand()); + if (execcmd->Start()) + dsyslog("executing command '%s'", *buffer); + else + esyslog("ERROR: can't execute command '%s'", *buffer); + return osEnd; + } + } + } + + Set(); + return osContinue; + } + break; +#endif /* SETUP */ default: break; } } +#ifdef USE_MAINMENUHOOKS + if (menu) + return AddSubMenu(menu); +#endif /* MAINMENUHOOKS */ if (!HasSubMenu() && Update(HadSubMenu)) Display(); if (Key != kNone) { @@ -3297,7 +4867,14 @@ cChannel *cDisplayChannel::NextAvailable if (Direction) { while (Channel) { Channel = Direction > 0 ? Channels.Next(Channel) : Channels.Prev(Channel); +#ifdef USE_PINPLUGIN + if (cStatus::MsgChannelProtected(0, Channel) == false) +#endif /* PINPLUGIN */ +#ifdef USE_LNBSHARE + if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true) && cDevice::PrimaryDevice()->GetMaxBadPriority(Channel) < 0) +#else if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, 0, true)) +#endif /* LNBSHARE */ return Channel; } } @@ -3355,6 +4932,13 @@ eOSState cDisplayChannel::ProcessKey(eKe case kLeft: case kRight|k_Repeat: case kRight: +#ifdef USE_VOLCTRL + if (Setup.LRVolumeControl && !Setup.LRChannelGroups) { + cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); + break; + } + // else fall through +#endif /* VOLCTRL */ case kNext|k_Repeat: case kNext: case kPrev|k_Repeat: @@ -3514,6 +5098,17 @@ void cDisplayVolume::Process(eKeys Key) eOSState cDisplayVolume::ProcessKey(eKeys Key) { switch (Key) { +#ifdef USE_VOLCTRL + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: + if (Setup.LRVolumeControl) { + cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); + break; + } + // else fall through +#endif /* VOLCTRL */ case kVolUp|k_Repeat: case kVolUp: case kVolDn|k_Repeat: @@ -3763,6 +5358,10 @@ eOSState cDisplaySubtitleTracks::Process cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause) { +#ifdef USE_DVLRECSCRIPTADDON + const cChannel *recChan = NULL; + char *chanName = NULL; +#endif /* DVLRECSCRIPTADDON */ // We're going to manipulate an event here, so we need to prevent // others from modifying any EPG data: cSchedulesLock SchedulesLock; @@ -3807,12 +5406,57 @@ cRecordControl::cRecordControl(cDevice * return; } +#ifdef USE_DVLRECSCRIPTADDON + if (timer) + if ((recChan = timer->Channel()) != NULL) + chanName = strdup(recChan->Name()); + if (chanName != NULL) { + cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName, chanName); + free(chanName); + } + else +#endif /* DVLRECSCRIPTADDON */ cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); isyslog("record %s", fileName); if (MakeDirs(fileName, true)) { const cChannel *ch = timer->Channel(); +#if defined (USE_LIVEBUFFER) || defined (USE_TTXTSUBS) +#ifdef USE_LIVEBUFFER + int startFrame=-1; + int endFrame=0; + cLiveBuffer *liveBuffer = cLiveBufferManager::InLiveBuffer(timer, &startFrame, &endFrame); + if (liveBuffer) { + timer->SetFlags(tfhasLiveBuf); + liveBuffer->SetStartFrame(startFrame); + if (endFrame) { + liveBuffer->CreateIndexFile(fileName, 0, endFrame); + Timers.Del(timer); + Timers.SetModified(); + timer = NULL; + Recording.WriteInfo(); + Recordings.AddByName(fileName); + return; + } + } +#endif /* LIVEBUFFER */ +#ifdef USE_TTXTSUBS + cTtxtSubsRecorderBase *subsRecorder = cVDRTtxtsubsHookListener::Hook()->NewTtxtSubsRecorder(device, ch); +#endif /* TTXTSUBS */ + recorder = new cRecorder(fileName, ch->GetChannelID(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids() +#ifdef USE_TTXTSUBS + ,subsRecorder +#endif /* TTXTSUBS */ +#ifdef USE_LIVEBUFFER + ,liveBuffer +#endif /* LIVEBUFFER */ + ); +#else recorder = new cRecorder(fileName, ch->GetChannelID(), timer->Priority(), ch->Vpid(), ch->Apids(), ch->Dpids(), ch->Spids()); +#endif /* LIVEBUFFER || TTXTSUBS */ if (device->AttachReceiver(recorder)) { +#ifdef USE_TTXTSUBS + if (subsRecorder) subsRecorder->DeviceAttach(); +#endif /* TTXTSUBS */ Recording.WriteInfo(); cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true); if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo() @@ -3869,11 +5513,25 @@ bool cRecordControl::GetEvent(void) void cRecordControl::Stop(void) { if (timer) { +#ifdef USE_DVLRECSCRIPTADDON + char *chanName = NULL; + const cChannel *recChan = NULL; + + recChan = timer -> Channel(); + if (recChan != NULL) + chanName = strdup(recChan -> Name()); +#endif /* DVLRECSCRIPTADDON */ DELETENULL(recorder); timer->SetRecording(false); timer = NULL; cStatus::MsgRecording(device, NULL, fileName, false); +#ifdef USE_DVLRECSCRIPTADDON + cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName, chanName); + if (chanName != NULL) + free(chanName); +#else cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName); +#endif /* DVLRECSCRIPTADDON */ } } @@ -3920,15 +5578,35 @@ bool cRecordControls::Start(cTimer *Time int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority; cDevice *device = cDevice::GetDevice(channel, Priority, false); if (device) { +#ifdef USE_LNBSHARE + cDevice *tmpDevice; + while ((tmpDevice = device->GetBadDevice(channel))) { + if (tmpDevice->Replaying() == false) { +// Stop(tmpDevice); + if (tmpDevice->IsPrimaryDevice() ) + tmpDevice->SwitchChannelForced(channel, true); + else + tmpDevice->SwitchChannelForced(channel, false); + } else + tmpDevice->SwitchChannelForced(channel, false); + } +#endif /* LNBSHARE */ dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number()); if (!device->SwitchChannel(channel, false)) { ShutdownHandler.RequestEmergencyExit(); return false; } +#ifdef USE_LIVEBUFFER + if (!Timer || Timer->Matches() || cLiveBufferManager::InLiveBuffer(Timer)) { +#else if (!Timer || Timer->Matches()) { +#endif /* LIVEBUFFER */ for (int i = 0; i < MAXRECORDCONTROLS; i++) { if (!RecordControls[i]) { RecordControls[i] = new cRecordControl(device, Timer, Pause); +#ifdef USE_PINPLUGIN + cStatus::MsgRecordingFile(RecordControls[i]->FileName()); +#endif /* PINPLUGIN */ return RecordControls[i]->Process(time(NULL)); } } @@ -4059,12 +5737,22 @@ bool cRecordControls::StateChanged(int & // --- cReplayControl -------------------------------------------------------- +#ifdef USE_LIEMIEXT +#define REPLAYCONTROLSKIPLIMIT 9 // s +#define REPLAYCONTROLSKIPSECONDS 90 // s +#define REPLAYCONTROLSKIPTIMEOUT 5000 // ms +#endif /* LIEMIEXT */ + cReplayControl *cReplayControl::currentReplayControl = NULL; char *cReplayControl::fileName = NULL; char *cReplayControl::title = NULL; cReplayControl::cReplayControl(void) +#ifdef USE_JUMPPLAY +:cDvbPlayerControl(fileName), marks(fileName) +#else :cDvbPlayerControl(fileName) +#endif /* JUMPPLAY */ { currentReplayControl = this; displayReplay = NULL; @@ -4072,10 +5760,28 @@ cReplayControl::cReplayControl(void) lastCurrent = lastTotal = -1; lastPlay = lastForward = false; lastSpeed = -2; // an invalid value +#ifdef USE_LIEMIEXT + lastSkipKey = kNone; + lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; + lastSkipTimeout.Set(0); +#endif /* LIEMIEXT */ timeoutShow = 0; timeSearchActive = false; +#ifndef USE_JUMPPLAY marks.Load(fileName); +#endif /* JUMPPLAY */ cRecording Recording(fileName); +#ifdef USE_DVDARCHIVE + canJumpChapters = (Recording.GetDvdType() == DVD_VIDEO_ARCHIVE_TYPE); + dvdchapters = NULL; + if (canJumpChapters) { + const char *ret = Recording.GetDvdChapters(); + if (ret) + dvdchapters = strdup(ret); + else + canJumpChapters=false; + } +#endif /* DVDARCHIVE */ cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true); SetTrackDescriptions(false); } @@ -4083,12 +5789,67 @@ cReplayControl::cReplayControl(void) cReplayControl::~cReplayControl() { Hide(); +#ifdef USE_DVDARCHIVE + free(dvdchapters); +#endif /* DVDARCHIVE */ cStatus::MsgReplaying(this, NULL, fileName, false); Stop(); if (currentReplayControl == this) currentReplayControl = NULL; } +#ifdef USE_DELTIMESHIFTREC +void cReplayControl::Stop(void) +{ + int dummy; + bool playing = GetIndex(dummy, dummy, false); + cRecordControl* rc = cRecordControls::GetRecordControl(fileName); + + if (playing && rc && rc->InstantId()) { + isyslog("found Timeshiftrecording"); + + if ((Setup.DelTimeshiftRec != 0 ) || (Interface->Confirm(tr("Delete recording?")))) { + cRecordControl *rc = cRecordControls::GetRecordControl(fileName); + if (rc) { + cTimer *timer = rc->Timer(); + if (timer) { + const char* reccmd_backup = cRecordingUserCommand::GetCommand(); + cRecordingUserCommand::SetCommand(NULL); + + timer->Skip(); + cRecordControls::Process(time(NULL)); + if (timer->IsSingleEvent()) { + isyslog("deleting timer %s", *timer->ToDescr()); + Timers.Del(timer); + } + Timers.SetModified(); + + // restore reccmd + cRecordingUserCommand::SetCommand(reccmd_backup); + } + } + isyslog("stop replaying %s", fileName); + cDvbPlayerControl::Stop(); + + if (Setup.DelTimeshiftRec != 1) { + cRecording *recording = Recordings.GetByName(fileName);; + if (recording) { + if (recording->Delete()) { + Recordings.DelByName(fileName); + ClearLastReplayed(fileName); + return; + } + else + Skins.Message(mtError, tr("Error while deleting recording!")); + } + } + } + else + cDvbPlayerControl::Stop(); + } +} +#endif /* DELTIMESHIFTREC */ + void cReplayControl::SetRecording(const char *FileName, const char *Title) { free(fileName); @@ -4183,6 +5944,9 @@ bool cReplayControl::ShowProgress(bool I if (Initial) { if (title) displayReplay->SetTitle(title); +#ifdef USE_OSDMAXITEMS + displayReplay->SetButtons(tr("Jump"), tr("Skip +60s"), tr("Skip -60s"), tr("Button$Stop")); +#endif /* OSDMAXITEMS */ lastCurrent = lastTotal = -1; } if (Total != lastTotal) { @@ -4304,8 +6068,15 @@ void cReplayControl::MarkToggle(void) ShowTimed(2); bool Play, Forward; int Speed; +#ifdef USE_JUMPPLAY + if (GetReplayMode(Play, Forward, Speed) && !Play) { + Goto(Current, true); + displayFrames = true; + } +#else if (GetReplayMode(Play, Forward, Speed) && !Play) Goto(Current, true); +#endif /* JUMPPLAY */ } marks.Save(); } @@ -4318,8 +6089,22 @@ void cReplayControl::MarkJump(bool Forwa if (GetIndex(Current, Total)) { cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); if (m) { +#ifdef USE_JUMPPLAY + bool Play2, Forward2; + int Speed; + if (Setup.JumpPlay && GetReplayMode(Play2, Forward2, Speed) && + Play2 && Forward && m->position < Total - SecondsToFrames(3)) { + Goto(m->position); + Play(); + } + else { + Goto(m->position, true); + displayFrames = true; + } +#else Goto(m->position, true); displayFrames = true; +#endif /* JUMPPLAY */ } } } @@ -4348,11 +6133,43 @@ void cReplayControl::MarkMove(bool Forwa } } +#ifdef USE_DVDARCHIVE +void cReplayControl::ChaptersJump(bool Forward) +{ + int Current, Total; + if (GetIndex(Current, Total)) { + int position = -1; + char *buf, *pos; + cString old1("-1"); + cString old2("-1"); + buf = strdup(dvdchapters); + pos = strtok(buf, ","); + while (pos != NULL && position == -1) { + if (pos && atoi(pos) > Current) + position = Forward ? atoi(pos) : ((Current - atoi(old1)) <= (3*FRAMESPERSEC)) ? atoi(old2) : atoi(old1); + old2 = old1; + old1 = strdup(pos); + if(position == -1) pos = strtok(NULL, ","); + } + if (!pos && !Forward) + position = ((Current - atoi(old1)) <= (3*FRAMESPERSEC)) ? atoi(old2) : atoi(old1); + if (position >= 0) { + Goto(position); + Play(); + } + } +} + +#endif /* DVDARCHIVE */ void cReplayControl::EditCut(void) { if (fileName) { Hide(); +#ifdef USE_CUTTERQUEUE + if (!cCutter::Active() || Interface->Confirm(tr("Cutter already running - Add to cutting queue?"))) { +#else if (!cCutter::Active()) { +#endif /* CUTTERQUEUE */ if (!marks.Count()) Skins.Message(mtError, tr("No editing marks defined!")); else if (!cCutter::Start(fileName)) @@ -4374,7 +6191,11 @@ void cReplayControl::EditTest(void) if (!m) m = marks.GetNext(Current); if (m) { +#ifdef USE_JUMPPLAY + if ((m->Index() & 0x01) != 0 && !Setup.PlayJump) +#else if ((m->Index() & 0x01) != 0) +#endif /* JUMPPLAY */ m = marks.Next(m); if (m) { Goto(m->position - SecondsToFrames(3)); @@ -4396,6 +6217,9 @@ eOSState cReplayControl::ProcessKey(eKey { if (!Active()) return osEnd; +#ifdef USE_JUMPPLAY + marks.Reload(); +#endif /* JUMPPLAY */ if (visible) { if (timeoutShow && time(NULL) > timeoutShow) { Hide(); @@ -4413,7 +6237,32 @@ eOSState cReplayControl::ProcessKey(eKey TimeSearchProcess(Key); return osContinue; } +#ifdef USE_DVDARCHIVE + bool isOnMark = false; + if (canJumpChapters) { + int Current, Total; + GetIndex(Current, Total); + cMark *m = marks.Get(Current); + if (m && (m->position == Current)) isOnMark = true; + } +#endif /* DVDARCHIVE */ bool DoShowMode = true; +#ifdef USE_VOLCTRL + if (Setup.LRVolumeControl && (!Setup.LRForwardRewind || (Setup.LRForwardRewind == 1 && !visible))) { + switch (Key) { + // Left/Right volume control + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: + cRemote::Put(NORMALKEY(Key) == kLeft ? kVolDn : kVolUp, true); + return osContinue; + break; + default: + break; + } + } +#endif /* VOLCTRL */ switch (Key) { // Positioning: case kPlay: @@ -4431,25 +6280,82 @@ eOSState cReplayControl::ProcessKey(eKey case kFastFwd: case kRight: Forward(); break; case kRed: TimeSearch(); break; +#ifdef USE_LIEMIEXT + case kGreen|k_Repeat: + case kGreen: SkipSeconds(-Setup.JumpSeconds); break; + case kYellow|k_Repeat: + case kYellow: SkipSeconds( Setup.JumpSeconds); break; + case k1|k_Repeat: + case k1: SkipSeconds(-Setup.JumpSecondsSlow); break; + case k3|k_Repeat: + case k3: SkipSeconds( Setup.JumpSecondsSlow); break; + case kPrev|k_Repeat: + case kPrev: if (lastSkipTimeout.TimedOut()) { + lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; + lastSkipKey = kPrev; + } + else if (RAWKEY(lastSkipKey) != kPrev && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { + lastSkipSeconds /= 2; + lastSkipKey = kNone; + } + lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); + SkipSeconds(-lastSkipSeconds); break; + case kNext|k_Repeat: + case kNext: if (lastSkipTimeout.TimedOut()) { + lastSkipSeconds = REPLAYCONTROLSKIPSECONDS; + lastSkipKey = kNext; + } + else if (RAWKEY(lastSkipKey) != kNext && lastSkipSeconds > (2 * REPLAYCONTROLSKIPLIMIT)) { + lastSkipSeconds /= 2; + lastSkipKey = kNone; + } + lastSkipTimeout.Set(REPLAYCONTROLSKIPTIMEOUT); + SkipSeconds(lastSkipSeconds); break; +#else case kGreen|k_Repeat: case kGreen: SkipSeconds(-60); break; case kYellow|k_Repeat: case kYellow: SkipSeconds( 60); break; +#endif /* LIEMIEXT */ case kStop: case kBlue: Hide(); Stop(); return osEnd; +#ifdef USE_DVDARCHIVE + case kDvdChapterJumpForward|k_Repeat: + case kDvdChapterJumpForward: if (canJumpChapters && !isOnMark) { + ChaptersJump(true); + } + else { + DoShowMode = false; + MarkMove(true); + } + break; + case kDvdChapterJumpBack|k_Repeat: + case kDvdChapterJumpBack: if (canJumpChapters && !isOnMark) { + ChaptersJump(false); + } + else { + DoShowMode = false; + MarkMove(false); + } + break; +#endif /* DVDARCHIVE */ default: { DoShowMode = false; switch (Key) { // Editing: case kMarkToggle: MarkToggle(); break; +#ifndef USE_LIEMIEXT case kPrev|k_Repeat: case kPrev: +#endif /* LIEMIEXT */ case kMarkJumpBack|k_Repeat: case kMarkJumpBack: MarkJump(false); break; +#ifndef USE_LIEMIEXT case kNext|k_Repeat: case kNext: +#endif /* LIEMIEXT */ case kMarkJumpForward|k_Repeat: case kMarkJumpForward: MarkJump(true); break; case kMarkMoveBack|k_Repeat: @@ -4469,7 +6375,16 @@ eOSState cReplayControl::ProcessKey(eKey else Show(); break; +#ifdef USE_DELTIMESHIFTREC + case kBack: { cRecordControl* rc = cRecordControls::GetRecordControl(fileName); + if (rc && rc->InstantId()) + return osEnd; + else + return osRecordings; + } +#else case kBack: return osRecordings; +#endif /* DELTIMESHIFTREC */ default: return osUnknown; } } diff -ruNp vdr-1.6.0-2/menu.h vdr-1.6.0-2-extensions/menu.h --- vdr-1.6.0-2/menu.h 2008-02-10 17:01:53.000000000 +0100 +++ vdr-1.6.0-2-extensions/menu.h 2009-04-09 20:48:26.000000000 +0200 @@ -18,6 +18,9 @@ #include "menuitems.h" #include "recorder.h" #include "skins.h" +#ifdef USE_SETUP +#include "submenu.h" +#endif /* SETUP */ class cMenuText : public cOsdMenu { private: @@ -29,12 +32,19 @@ public: void SetText(const char *Text); virtual void Display(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuText"; } +#endif /* GRAPHTFT */ }; class cMenuEditTimer : public cOsdMenu { private: cTimer *timer; cTimer data; +#ifdef USE_LIEMIEXT + char name[MaxFileName]; + char path[MaxFileName]; +#endif /* LIEMIEXT */ int channel; bool addIfConfirmed; cMenuEditDateItem *firstday; @@ -43,6 +53,9 @@ public: cMenuEditTimer(cTimer *Timer, bool New = false); virtual ~cMenuEditTimer(); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuTimerEdit"; } +#endif /* GRAPHTFT */ }; class cMenuEvent : public cOsdMenu { @@ -52,22 +65,37 @@ public: cMenuEvent(const cEvent *Event, bool CanSwitch = false, bool Buttons = false); virtual void Display(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuEvent"; } +#endif /* GRAPHTFT */ }; class cMenuMain : public cOsdMenu { private: +#ifdef USE_SETUP + int nrDynamicMenuEntries; +#endif /* SETUP */ bool replaying; cOsdItem *stopReplayItem; cOsdItem *cancelEditingItem; cOsdItem *stopRecordingItem; int recordControlsState; static cOsdObject *pluginOsdObject; +#ifdef USE_SETUP + void Set(int current=0); + bool Update(bool Force = false); + cSubMenu subMenu; +#else void Set(void); bool Update(bool Force = false); +#endif /* SETUP */ public: cMenuMain(eOSState State = osUnknown); virtual eOSState ProcessKey(eKeys Key); static cOsdObject *PluginOsdObject(void); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuMain"; } +#endif /* GRAPHTFT */ }; class cDisplayChannel : public cOsdObject { @@ -163,12 +191,18 @@ private: eOSState Delete(void); eOSState Info(void); eOSState Commands(eKeys Key = kNone); +#ifdef USE_LIEMIEXT + eOSState Rename(void); +#endif /* LIEMIEXT */ protected: cRecording *GetRecording(cMenuRecordingItem *Item); public: cMenuRecordings(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false); ~cMenuRecordings(); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuRecordings"; } +#endif /* GRAPHTFT */ }; class cRecordControl { @@ -212,11 +246,21 @@ public: class cReplayControl : public cDvbPlayerControl { private: cSkinDisplayReplay *displayReplay; +#ifdef USE_JUMPPLAY + cMarksReload marks; +#else cMarks marks; +#endif /* JUMPPLAY */ bool visible, modeOnly, shown, displayFrames; int lastCurrent, lastTotal; bool lastPlay, lastForward; int lastSpeed; +#ifdef USE_LIEMIEXT + int lastSkipSeconds; + int lastSkipSecondsSlow; + eKeys lastSkipKey; + cTimeMs lastSkipTimeout; +#endif /* LIEMIEXT */ time_t timeoutShow; bool timeSearchActive, timeSearchHide; int timeSearchTime, timeSearchPos; @@ -234,9 +278,17 @@ private: void MarkMove(bool Forward); void EditCut(void); void EditTest(void); +#ifdef USE_DVDARCHIVE + void ChaptersJump(bool Forward); + bool canJumpChapters; + char *dvdchapters; +#endif /* DVDARCHIVE */ public: cReplayControl(void); virtual ~cReplayControl(); +#ifdef USE_DELTIMESHIFTREC + void Stop(void); +#endif /* DELTIMESHIFTREC */ virtual cOsdObject *GetInfo(void); virtual eOSState ProcessKey(eKeys Key); virtual void Show(void); diff -ruNp vdr-1.6.0-2/menuitems.c vdr-1.6.0-2-extensions/menuitems.c --- vdr-1.6.0-2/menuitems.c 2008-02-10 17:03:30.000000000 +0100 +++ vdr-1.6.0-2-extensions/menuitems.c 2009-04-09 20:48:26.000000000 +0200 @@ -32,9 +32,20 @@ cMenuEditItem::~cMenuEditItem() free(name); } +#ifdef USE_VALIDINPUT +void cMenuEditItem::SetValue(const char *Value, bool HasPre, bool HasSucc) +#else void cMenuEditItem::SetValue(const char *Value) +#endif /* VALIDINPUT */ { cString buffer = cString::sprintf("%s:\t%s", name, Value); +#ifdef USE_VALIDINPUT + if (Setup.ShowValidInput) { + if (HasPre && HasSucc) buffer = cString::sprintf("%s:\t<%s>", name, Value); + else if (HasPre) buffer = cString::sprintf("%s:\t<%s", name, Value); + else if (HasSucc) buffer = cString::sprintf("%s:\t%s>", name, Value); + } +#endif /* VALIDINPUT */ SetText(buffer); cStatus::MsgOsdCurrentItem(buffer); } @@ -126,7 +137,11 @@ void cMenuEditBoolItem::Set(void) { char buf[16]; snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString); +#ifdef USE_VALIDINPUT + SetValue(buf, *value, !*value); +#else SetValue(buf); +#endif /* VALIDINPUT */ } // --- cMenuEditBitItem ------------------------------------------------------ @@ -619,6 +634,171 @@ eOSState cMenuEditStrItem::ProcessKey(eK return osContinue; } +#ifdef USE_LIEMIEXT +// --- cMenuEditRecPathItem -------------------------------------------------- + +cMenuEditRecPathItem::cMenuEditRecPathItem(const char* Name, char* Path, + int Length): cMenuEditStrItem(Name, Path, Length, tr(FileNameChars)) +{ + SetBase(Path); +} + +cMenuEditRecPathItem::~cMenuEditRecPathItem() +{ +} + +void cMenuEditRecPathItem::SetBase(const char* Path) +{ + if (!Path) + base[0] = 0; + Utf8Strn0Cpy(base, Path, sizeof(base)); + char* p = strrchr(base, '~'); + if (p) + p[0] = 0; + else + base[0] = 0; +} + +void cMenuEditRecPathItem::FindNextLevel() +{ + char item[MaxFileName]; + + for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) + { + char* p; + Utf8Strn0Cpy(item, recording->Name(), sizeof(item)); + stripspace(value); + lengthUtf8 = Utf8ToArray(value, valueUtf8, length); + if (!lengthUtf8) + p = strchr(item, '~'); + else { + if (strstr(item, value) != item) + continue; + if (item[strlen(value)] != '~') + continue; + p = strchr(item + strlen(value) + 1, '~'); + } + if (!p) + continue; + p[0] = 0; + Utf8Strn0Cpy(base, value, length); + Utf8Strn0Cpy(value, item, length); + lengthUtf8 = Utf8ToArray(value, valueUtf8, length); + return; + } +} + +void cMenuEditRecPathItem::Find(bool Next) +{ + char item[MaxFileName]; + char lastItem[MaxFileName] = ""; + + for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) + { + const char* recName = recording->Name(); + if (Utf8StrLen(base) && strstr(recName, base) != recName) + continue; + if (strlen(base) && recName[strlen(base)] != '~') + continue; + Utf8Strn0Cpy(item, recName, sizeof(item)); + char* p = strchr(item + strlen(base) + 1, '~'); + if (!p) + continue; + p[0] = 0; + if (!Next && (strcmp(item, value) == 0)) { + if (strlen(lastItem)) + Utf8Strn0Cpy(value, lastItem, length); + lengthUtf8 = Utf8ToArray(value, valueUtf8, length); + return; + } + if (strcmp(lastItem, item) != 0) { + if(Next && Utf8StrLen(lastItem) && strcmp(lastItem, value) == 0) { + Utf8Strn0Cpy(value, item, length); + lengthUtf8 = Utf8ToArray(value, valueUtf8, length); + return; + } + Utf8Strn0Cpy(lastItem, item, sizeof(lastItem)); + } + } +} + +void cMenuEditRecPathItem::SetHelpKeys(void) +{ + cSkinDisplay::Current()->SetButtons(tr("Rename$Up"), tr("Rename$Down"), tr("Rename$Previous"), tr("Rename$Next")); +} + +eOSState cMenuEditRecPathItem::ProcessKey(eKeys Key) +{ + switch (Key) { + case kLeft: + case kRed: // one level up + if (!InEditMode()) + return cMenuEditItem::ProcessKey(Key); + Utf8Strn0Cpy(value, base, lengthUtf8); + lengthUtf8 = Utf8ToArray(value, valueUtf8, length); + SetBase(base); + pos = Utf8StrLen(base); + if (pos) + pos++; + if (!lengthUtf8) { + Utf8Strn0Cpy(value, " ", length); + lengthUtf8 = Utf8ToArray(value, valueUtf8, length); + } + break; + case kRight: + case kGreen: // one level down + if (InEditMode()) + FindNextLevel(); + else + EnterEditMode(); + + if (!lengthUtf8) { + Utf8Strn0Cpy(value, " ", length); + lengthUtf8 = Utf8ToArray(value, valueUtf8, length); + } + pos = Utf8StrLen(base); + if (pos) + pos++; + SetHelpKeys(); + break; + case kUp|k_Repeat: + case kUp: + case kYellow|k_Repeat: + case kYellow: // previous directory in list + if (!InEditMode()) + return cMenuEditItem::ProcessKey(Key); + Find(false); + pos = Utf8StrLen(base); + if (pos) + pos++; + break; + case kDown|k_Repeat: + case kDown: + case kBlue|k_Repeat: + case kBlue: // next directory in list + if (!InEditMode()) + return cMenuEditItem::ProcessKey(Key); + Find(true); + pos = Utf8StrLen(base); + if (pos) + pos++; + break; + case kOk: // done + if (!InEditMode()) + return cMenuEditItem::ProcessKey(Key); + stripspace(value); + lengthUtf8 = Utf8ToArray(value, valueUtf8, length); + cSkinDisplay::Current()->SetButtons(NULL); + LeaveEditMode(Key == kOk); + break; + default: + return cMenuEditItem::ProcessKey(Key); + } + Set(); + return osContinue; +} +#endif /* LIEMIEXT */ + // --- cMenuEditStraItem ----------------------------------------------------- cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings) @@ -630,7 +810,11 @@ cMenuEditStraItem::cMenuEditStraItem(con void cMenuEditStraItem::Set(void) { +#ifdef USE_VALIDINPUT + SetValue(strings[*value], (*value > min), (*value < max)); +#else SetValue(strings[*value]); +#endif /* VALIDINPUT */ } // --- cMenuEditChanItem ----------------------------------------------------- diff -ruNp vdr-1.6.0-2/menuitems.h vdr-1.6.0-2-extensions/menuitems.h --- vdr-1.6.0-2/menuitems.h 2008-02-16 17:09:58.000000000 +0100 +++ vdr-1.6.0-2-extensions/menuitems.h 2009-04-09 20:48:26.000000000 +0200 @@ -21,7 +21,11 @@ private: public: cMenuEditItem(const char *Name); ~cMenuEditItem(); +#ifdef USE_VALIDINPUT + void SetValue(const char *Value, bool HasPre=false, bool HasSucc=false); +#else void SetValue(const char *Value); +#endif /* VALIDINPUT */ }; class cMenuEditIntItem : public cMenuEditItem { @@ -78,26 +82,46 @@ public: class cMenuEditStrItem : public cMenuEditItem { private: +#ifdef USE_LIEMIEXT + int offset; +#else char *value; int length; const char *allowed; int pos, offset; +#endif /* LIEMIEXT */ bool insert, newchar, uppercase; +#ifndef USE_LIEMIEXT int lengthUtf8; uint *valueUtf8; +#endif /* LIEMIEXT */ uint *allowedUtf8; uint *charMapUtf8; uint *currentCharUtf8; eKeys lastKey; cTimeMs autoAdvanceTimeout; +#ifndef USE_LIEMIEXT void SetHelpKeys(void); +#endif /* LIEMIEXT */ uint *IsAllowed(uint c); void AdvancePos(void); +#ifndef USE_LIEMIEXT virtual void Set(void); +#endif /* LIEMIEXT */ uint Inc(uint c, bool Up); void Insert(void); void Delete(void); protected: +#ifdef USE_LIEMIEXT + char *value; + int length; + uint *valueUtf8; + int lengthUtf8; + const char *allowed; + int pos; + void SetHelpKeys(void); + virtual void Set(void); +#endif /* LIEMIEXT */ void EnterEditMode(void); void LeaveEditMode(bool SaveValue = false); bool InEditMode(void) { return valueUtf8 != NULL; } @@ -107,6 +131,21 @@ public: virtual eOSState ProcessKey(eKeys Key); }; +#ifdef USE_LIEMIEXT +class cMenuEditRecPathItem : public cMenuEditStrItem { +protected: + char base[MaxFileName]; + virtual void SetHelpKeys(void); + void SetBase(const char* Path); + void FindNextLevel(); + void Find(bool Next); +public: + cMenuEditRecPathItem(const char* Name, char* Path, int Length); + ~cMenuEditRecPathItem(); + virtual eOSState ProcessKey(eKeys Key); + }; +#endif /* LIEMIEXT */ + class cMenuEditStraItem : public cMenuEditIntItem { private: const char * const *strings; @@ -174,6 +213,9 @@ public: cMenuSetupPage(void); virtual eOSState ProcessKey(eKeys Key); void SetPlugin(cPlugin *Plugin); +#ifdef USE_GRAPHTFT + const char* MenuKind() { return "MenuSetupPage"; } +#endif /* GRAPHTFT */ }; #endif //__MENUITEMS_H diff -ruNp vdr-1.6.0-2/menuorgpatch.h vdr-1.6.0-2-extensions/menuorgpatch.h --- vdr-1.6.0-2/menuorgpatch.h 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/menuorgpatch.h 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,102 @@ +#ifdef USE_MENUORG +/* + * vdr-menuorg - A plugin for the Linux Video Disk Recorder + * Copyright (c) 2007 - 2008 Tobias Grimm + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * $Id$ + * + */ + +#ifndef __MENUORGPATCH_H +#define __MENUORGPATCH_H + +#include "mainmenuitemsprovider.h" + +class MenuOrgPatch +{ + private: + static IMainMenuItemsProvider* _mainMenuItemsProvider; + + private: + static IMainMenuItemsProvider* MainMenuItemsProvider() + { + if (!_mainMenuItemsProvider) + { + IMainMenuItemsProvider* mainMenuItemsProvider; + + if (cPluginManager::CallFirstService(MENU_ITEMS_PROVIDER_SERVICE_ID, &mainMenuItemsProvider)) + { + _mainMenuItemsProvider = mainMenuItemsProvider; + } + } + return _mainMenuItemsProvider; + } + + public: + static bool IsCustomMenuAvailable() + { + return (MainMenuItemsProvider() != NULL) && (MainMenuItemsProvider()->IsCustomMenuAvailable()); + } + + static void EnterRootMenu() + { + if (MainMenuItemsProvider()) + { + MainMenuItemsProvider()->EnterRootMenu(); + } + } + + static bool LeaveSubMenu() + { + if (MainMenuItemsProvider()) + { + return MainMenuItemsProvider()->LeaveSubMenu(); + } + return false; + } + + static void EnterSubMenu(cOsdItem* item) + { + if (MainMenuItemsProvider()) + { + MainMenuItemsProvider()->EnterSubMenu(item); + } + } + + static MenuItemDefinitions* MainMenuItems() + { + if (MainMenuItemsProvider()) + { + return MainMenuItemsProvider()->MainMenuItems(); + } + return NULL; + } + + static cOsdMenu* Execute(cOsdItem* item) + { + if (MainMenuItemsProvider()) + { + return MainMenuItemsProvider()->Execute(item); + } + return NULL; + } +}; + +IMainMenuItemsProvider* MenuOrgPatch::_mainMenuItemsProvider = NULL; + +#endif //__MENUORGPATCH_H +#endif /* MENUORG */ diff -ruNp vdr-1.6.0-2/osdbase.c vdr-1.6.0-2-extensions/osdbase.c --- vdr-1.6.0-2/osdbase.c 2008-02-17 12:33:04.000000000 +0100 +++ vdr-1.6.0-2-extensions/osdbase.c 2009-04-09 20:48:26.000000000 +0200 @@ -22,6 +22,9 @@ cOsdItem::cOsdItem(eOSState State) state = State; selectable = true; fresh = true; +#if defined (USE_SETUP) && defined (USE_PINPLUGIN) + subMenu = 0; +#endif /* SETUP & PINPLUGIN */ } cOsdItem::cOsdItem(const char *Text, eOSState State, bool Selectable) @@ -31,8 +34,23 @@ cOsdItem::cOsdItem(const char *Text, eOS selectable = Selectable; fresh = true; SetText(Text); +#if defined (USE_SETUP) && defined (USE_PINPLUGIN) + subMenu = 0; +#endif /* SETUP & PINPLUGIN */ } +#if defined (USE_SETUP) && defined (USE_PINPLUGIN) +cOsdItem::cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu) +{ + text = NULL; + state = State; + selectable = true; + fresh = true; + SetText(Text); + subMenu = SubMenu; +} +#endif /* SETUP & PINPLUGIN */ + cOsdItem::~cOsdItem() { free(text); @@ -77,6 +95,9 @@ cOsdMenu::cOsdMenu(const char *Title, in { isMenu = true; digit = 0; +#ifdef USE_LIEMIEXT + key_nr = -1; +#endif /* LIEMIEXT */ hasHotkeys = false; title = NULL; SetTitle(Title); @@ -97,6 +118,9 @@ cOsdMenu::~cOsdMenu() free(status); displayMenu->Clear(); cStatus::MsgOsdClear(); +#ifdef USE_GRAPHTFT + cStatus::MsgOsdMenuDestroy(); +#endif /* GRAPHTFT */ if (!--displayMenuCount) DELETENULL(displayMenu); } @@ -119,7 +143,11 @@ const char *cOsdMenu::hk(const char *s) digit = -1; // prevents automatic hotkeys - input already has them if (digit >= 0) { digit++; +#ifdef USE_LIEMIEXT + buffer = cString::sprintf(" %2d%s %s", digit, (digit > 9) ? "" : " ", s); +#else buffer = cString::sprintf(" %c %s", (digit < 10) ? '0' + digit : ' ' , s); +#endif /* LIEMIEXT */ s = buffer; } } @@ -199,9 +227,15 @@ void cOsdMenu::Display(void) subMenu->Display(); return; } +#ifdef USE_OSDMAXITEMS + displayMenuItems = displayMenu->MaxItems(); +#endif /* OSDMAXITEMS */ displayMenu->SetMessage(mtStatus, NULL); displayMenu->Clear(); cStatus::MsgOsdClear(); +#ifdef USE_GRAPHTFT + cStatus::MsgOsdMenuDisplay(MenuKind()); +#endif /* GRAPHTFT */ displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX displayMenu->SetTitle(title); cStatus::MsgOsdTitle(title); @@ -296,6 +330,9 @@ bool cOsdMenu::SelectableItem(int idx) void cOsdMenu::CursorUp(void) { +#ifdef USE_OSDMAXITEMS + displayMenuItems = displayMenu->MaxItems(); +#endif /* OSDMAXITEMS */ int tmpCurrent = current; int lastOnScreen = first + displayMenuItems - 1; int last = Count() - 1; @@ -334,6 +371,9 @@ void cOsdMenu::CursorUp(void) void cOsdMenu::CursorDown(void) { +#ifdef USE_OSDMAXITEMS + displayMenuItems = displayMenu->MaxItems(); +#endif /* OSDMAXITEMS */ int tmpCurrent = current; int lastOnScreen = first + displayMenuItems - 1; int last = Count() - 1; @@ -374,6 +414,9 @@ void cOsdMenu::CursorDown(void) void cOsdMenu::PageUp(void) { +#ifdef USE_OSDMAXITEMS + displayMenuItems = displayMenu->MaxItems(); +#endif /* OSDMAXITEMS */ int oldCurrent = current; int oldFirst = first; current -= displayMenuItems; @@ -408,6 +451,9 @@ void cOsdMenu::PageUp(void) void cOsdMenu::PageDown(void) { +#ifdef USE_OSDMAXITEMS + displayMenuItems = displayMenu->MaxItems(); +#endif /* OSDMAXITEMS */ int oldCurrent = current; int oldFirst = first; current += displayMenuItems; @@ -448,6 +494,64 @@ void cOsdMenu::Mark(void) } } +#ifdef USE_LIEMIEXT +#define MENUKEY_TIMEOUT 1500 + +eOSState cOsdMenu::HotKey(eKeys Key) +{ + bool match = false; + bool highlight = false; + int item_nr; + int i; + + if (Key == kNone) { + if (lastActivity.TimedOut()) + Key = kOk; + else + return osContinue; + } + else { + lastActivity.Set(MENUKEY_TIMEOUT); + } + for (cOsdItem *item = Last(); item; item = Prev(item)) { + const char *s = item->Text(); + i = 0; + item_nr = 0; + if (s && (s = skipspace(s)) != '\0' && '0' <= s[i] && s[i] <= '9') { + do { + item_nr = item_nr * 10 + (s[i] - '0'); + } + while (!((s[++i] == '\t')||(s[i] == ' ')) && (s[i] != '\0') && ('0' <= s[i]) && (s[i] <= '9')); + if ((Key == kOk) && (item_nr == key_nr)) { + current = item->Index(); + RefreshCurrent(); + Display(); + cRemote::Put(kOk, true); + key_nr = -1; + break; + } + else if (Key != kOk) { + if (!highlight && (item_nr == (Key - k0))) { + highlight = true; + current = item->Index(); + } + if (!match && (key_nr == -1) && ((item_nr / 10) == (Key - k0))) { + match = true; + key_nr = (Key - k0); + } + else if (((key_nr == -1) && (item_nr == (Key - k0))) || (!match && (key_nr >= 0) && (item_nr == (10 * key_nr + Key - k0)))) { + current = item->Index(); + cRemote::Put(kOk, true); + key_nr = -1; + break; + } + } + } + } + if ((!match) && (Key != kNone)) { + key_nr = -1; + } +#else eOSState cOsdMenu::HotKey(eKeys Key) { for (cOsdItem *item = First(); item; item = Next(item)) { @@ -462,6 +566,7 @@ eOSState cOsdMenu::HotKey(eKeys Key) } } } +#endif /* LIEMIEXT */ return osContinue; } @@ -500,8 +605,13 @@ eOSState cOsdMenu::ProcessKey(eKeys Key) } } switch (Key) { +#ifdef USE_LIEMIEXT + case kNone: + case k0...k9: return hasHotkeys ? HotKey(Key) : osUnknown; +#else case k0: return osUnknown; case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown; +#endif /* LIEMIEXT */ case kUp|k_Repeat: case kUp: CursorUp(); break; case kDown|k_Repeat: diff -ruNp vdr-1.6.0-2/osdbase.h vdr-1.6.0-2-extensions/osdbase.h --- vdr-1.6.0-2/osdbase.h 2007-11-03 15:50:52.000000000 +0100 +++ vdr-1.6.0-2-extensions/osdbase.h 2009-04-09 20:48:26.000000000 +0200 @@ -15,6 +15,10 @@ #include "skins.h" #include "tools.h" +#if defined (USE_SETUP) && defined (USE_PINPLUGIN) +#include "submenu.h" +#endif /* SETUP & PINPLUGIN */ + enum eOSState { osUnknown, osContinue, osSchedule, @@ -44,6 +48,9 @@ enum eOSState { osUnknown, osUser8, osUser9, osUser10, +#ifdef USE_LIVEBUFFER + osLiveBuffer, +#endif /* LIVEBUFFER */ }; class cOsdItem : public cListObject { @@ -51,16 +58,26 @@ private: char *text; eOSState state; bool selectable; +#if defined (USE_SETUP) && defined (USE_PINPLUGIN) + cSubMenuNode* subMenu; +#endif /* SETUP & PINPLUGIN */ protected: bool fresh; public: cOsdItem(eOSState State = osUnknown); cOsdItem(const char *Text, eOSState State = osUnknown, bool Selectable = true); +#if defined (USE_SETUP) && defined (USE_PINPLUGIN) + cOsdItem(const char *Text, eOSState State, cSubMenuNode* SubMenu); +#endif /* SETUP & PINPLUGIN */ virtual ~cOsdItem(); bool Selectable(void) const { return selectable; } void SetText(const char *Text, bool Copy = true); void SetSelectable(bool Selectable); void SetFresh(bool Fresh); +#if defined (USE_SETUP) && defined (USE_PINPLUGIN) + void SetSubMenu(cSubMenuNode* SubMenu) { subMenu = SubMenu; } + cSubMenuNode* SubMenu() { return subMenu; } +#endif /* SETUP & PINPLUGIN */ const char *Text(void) const { return text; } virtual void Set(void) {} virtual eOSState ProcessKey(eKeys Key); @@ -95,6 +112,10 @@ private: char *status; int digit; bool hasHotkeys; +#ifdef USE_LIEMIEXT + int key_nr; + cTimeMs lastActivity; +#endif /* LIEMIEXT */ protected: void SetDisplayMenu(void); cSkinDisplayMenu *DisplayMenu(void) { return displayMenu; } @@ -129,6 +150,9 @@ public: void Ins(cOsdItem *Item, bool Current = false, cOsdItem *Before = NULL); virtual void Display(void); virtual eOSState ProcessKey(eKeys Key); +#ifdef USE_GRAPHTFT + virtual const char* MenuKind() { return "MenuUnknown"; } +#endif /* GRAPHTFT */ }; #endif //__OSDBASE_H diff -ruNp vdr-1.6.0-2/osd.c vdr-1.6.0-2-extensions/osd.c --- vdr-1.6.0-2/osd.c 2007-10-12 14:38:36.000000000 +0200 +++ vdr-1.6.0-2-extensions/osd.c 2009-04-09 20:48:26.000000000 +0200 @@ -15,6 +15,9 @@ #include #include #include "tools.h" +#ifdef USE_TTXTSUBS +#include "vdrttxtsubshooks.h" +#endif /* TTXTSUBS */ // --- cPalette -------------------------------------------------------------- @@ -720,6 +723,9 @@ int cOsd::osdTop = 0; int cOsd::osdWidth = 0; int cOsd::osdHeight = 0; cVector cOsd::Osds; +#ifdef USE_PINPLUGIN +bool cOsd::pinValid = false; +#endif /* PINPLUGIN */ cOsd::cOsd(int Left, int Top, uint Level) { @@ -730,6 +736,9 @@ cOsd::cOsd(int Left, int Top, uint Level width = height = 0; level = Level; active = false; +#ifdef USE_YAEPG + vidWin.bpp = 0; +#endif /* YAEPG */ for (int i = 0; i < Osds.Size(); i++) { if (Osds[i]->level > level) { Osds.Insert(this, i); diff -ruNp vdr-1.6.0-2/osd.h vdr-1.6.0-2-extensions/osd.h --- vdr-1.6.0-2/osd.h 2007-10-12 16:28:44.000000000 +0200 +++ vdr-1.6.0-2-extensions/osd.h 2009-04-09 20:48:26.000000000 +0200 @@ -400,6 +400,12 @@ public: ///< 7: vertical, falling, upper virtual void Flush(void); ///< Actually commits all data to the OSD hardware. +#ifdef USE_PINPLUGIN + static bool pinValid; +#endif /* PINPLUGIN */ +#ifdef USE_YAEPG + tArea vidWin; +#endif /* YAEPG */ }; class cOsdProvider { diff -ruNp vdr-1.6.0-2/player.c vdr-1.6.0-2-extensions/player.c --- vdr-1.6.0-2/player.c 2007-07-20 17:25:24.000000000 +0200 +++ vdr-1.6.0-2-extensions/player.c 2009-04-09 20:48:26.000000000 +0200 @@ -60,10 +60,18 @@ cOsdObject *cControl::GetInfo(void) return NULL; } +#ifdef USE_LIVEBUFFER +cControl *cControl::Control(bool Hidden) +#else cControl *cControl::Control(void) +#endif /* LIVEBUFFER */ { cMutexLock MutexLock(&mutex); +#ifdef USE_LIVEBUFFER + return (control && (!control->hidden || Hidden)) ? control : NULL; +#else return (control && !control->hidden) ? control : NULL; +#endif /* LIVEBUFFER */ } void cControl::Launch(cControl *Control) diff -ruNp vdr-1.6.0-2/player.h vdr-1.6.0-2-extensions/player.h --- vdr-1.6.0-2/player.h 2008-02-16 14:50:11.000000000 +0100 +++ vdr-1.6.0-2-extensions/player.h 2009-04-09 20:48:26.000000000 +0200 @@ -83,7 +83,11 @@ public: static void Launch(cControl *Control); static void Attach(void); static void Shutdown(void); +#ifdef USE_LIVEBUFFER + static cControl *Control(bool Hidden = false); +#else static cControl *Control(void); +#endif /* LIVEBUFFER */ }; #endif //__PLAYER_H diff -ruNp vdr-1.6.0-2/plugin.c vdr-1.6.0-2-extensions/plugin.c --- vdr-1.6.0-2/plugin.c 2008-02-17 14:32:12.000000000 +0100 +++ vdr-1.6.0-2-extensions/plugin.c 2009-04-09 20:48:26.000000000 +0200 @@ -316,6 +316,14 @@ void cPluginManager::AddPlugin(const cha char *p = strchr(s, ' '); if (p) *p = 0; +#ifdef USE_PLUGINMISSING + struct stat st; + if (stat (cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), &st) && errno == ENOENT) { + esyslog("WARN: missing plugin '%s'", s); + fprintf(stderr, "vdr: missing plugin '%s'\n", s); + } + else +#endif /* PLUGINMISSING */ dlls.Add(new cDll(cString::sprintf("%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, APIVERSION), Args)); free(s); } @@ -324,7 +332,11 @@ bool cPluginManager::LoadPlugins(bool Lo { for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) { if (!dll->Load(Log)) +#ifdef USE_PLUGINMISSING + ; +#else return false; +#endif /* PLUGINMISSING */ } return true; } diff -ruNp vdr-1.6.0-2/po/ca_ES.po vdr-1.6.0-2-extensions/po/ca_ES.po --- vdr-1.6.0-2/po/ca_ES.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/ca_ES.po 2009-04-09 20:48:26.000000000 +0200 @@ -1001,3 +1001,270 @@ msgstr "Prem qualsevol tecla per cancel· #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR s'apagarà en %s minuts" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/cs_CZ.po vdr-1.6.0-2-extensions/po/cs_CZ.po --- vdr-1.6.0-2/po/cs_CZ.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/cs_CZ.po 2009-04-09 20:48:26.000000000 +0200 @@ -999,3 +999,270 @@ msgstr "Jakákoliv klávesa zru¹í restart" #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR se vypne za %s minut" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/da_DK.po vdr-1.6.0-2-extensions/po/da_DK.po --- vdr-1.6.0-2/po/da_DK.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/da_DK.po 2009-04-09 20:48:26.000000000 +0200 @@ -998,3 +998,270 @@ msgstr "Tryk vilkårlig knap for at annul #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR slukker om %s minutter" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/de_DE.po vdr-1.6.0-2-extensions/po/de_DE.po --- vdr-1.6.0-2/po/de_DE.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/de_DE.po 2009-04-09 20:48:26.000000000 +0200 @@ -785,6 +785,30 @@ msgstr "Lautstärke beim Einschalten" msgid "Setup.Miscellaneous$Emergency exit" msgstr "Notausstieg" +msgid "Setup.Miscellaneous$Volume ctrl with left/right" +msgstr "Lautstärke mit Rechts/Links regeln" + +msgid "Setup.Miscellaneous$Channelgroups with left/right" +msgstr "Kanalgruppen mit Rechts/Links" + +msgid "Setup.Miscellaneous$only in channelinfo" +msgstr "nur in Kanalinfo" + +msgid "Setup.Miscellaneous$Search fwd/back with left/right" +msgstr "Vor-/Rücklauf mit Rechts/Links" + +msgid "Setup.Miscellaneous$only in progress display" +msgstr "nur in Fortschrittsanzeige" + +msgid "Setup.Miscellaneous$Lirc repeat delay" +msgstr "Lirc Verzögerung" + +msgid "Setup.Miscellaneous$Lirc repeat freq" +msgstr "Lirc Frequenz" + +msgid "Setup.Miscellaneous$Lirc repeat timeout" +msgstr "Lirc Zeitbeschränkung" + msgid "Plugins" msgstr "Plugins" @@ -998,3 +1022,327 @@ msgstr "Taste drücken, um Neustart abzub #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR wird in %s Minuten ausschalten" + +msgid "Parameters" +msgstr "Parameter" + +msgid "Channel locked by LNB!" +msgstr "Kanal durch LNB gesperrt!" + +msgid "Childlock" +msgstr "Kindersicherung" + +msgid "Path" +msgstr "Pfad" + +msgid "Timer commands" +msgstr "Befehle für Aufzeichnungen" + +msgid "Rename recording" +msgstr "Aufzeichnung umbenennen" + +msgid "Date" +msgstr "Datum" + +msgid "Length" +msgstr "Länge" + +msgid "Size" +msgstr "Größe" + +msgid "Delete marks information?" +msgstr "Marks löschen?" + +msgid "Delete resume information?" +msgstr "Resume löschen?" + +msgid "DVD plugin is not installed!" +msgstr "Das DVD-Plugin ist nicht installiert!" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "Alphabet für Haupt-, flexibel für Unterverzeichnisse" + +msgid "main dir by date, subdirs flexible" +msgstr "Datum für Haupt-, flexibel für Unterverzeichnisse" + +msgid "all alphabetically" +msgstr "Alles alphabetisch" + +msgid "all by date" +msgstr "Alles nach Datum" + +msgid "Sorting" +msgstr "Sortierung" + +msgid "Setup.OSD$WarEagle icons" +msgstr "WarEagle icons verwenden" + +msgid "Setup.OSD$Main menu title" +msgstr "Hauptmenü Titel" + +msgid "Setup.OSD$- Text" +msgstr "- Text" + +msgid "default" +msgstr "Voreinstellung" + +msgid "VDR - text" +msgstr "VDR - Text" + +msgid "text" +msgstr "Text" + +msgid "VDR - version" +msgstr "VDR - Version" + +msgid "Setup.OSD$Main menu command position" +msgstr "Befehle Position im Hauptmenü" + +msgid "Setup.OSD$Show valid input" +msgstr "Zeige gültige Eingabe" + +msgid "Setup.EPG$Show progress bar" +msgstr "Zeitbalken anzeigen" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "Zeitspanne für dop. EPG-Suche (min)" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "Doppelten externen EPG-Eintrag" + +msgid "Setup.EPG$Mode of noEPG-Patch" +msgstr "Art des noEPG-Patches" + +msgid "adjust" +msgstr "anwenden" + +msgid "delete" +msgstr "löschen" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "Internes und externes EPG mischen" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "Erk. des lauf. VPS-Events abschalten" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "AC3-Transfer Fix benutzen" + +msgid "Setup.DVB$Channel Blocker" +msgstr "Sperre Kanäle" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "Kanal Sperren Filter" + +msgid "qam256" +msgstr "qam256" + +msgid "dvb-c" +msgstr "dvb-c" + +msgid "dvb-s" +msgstr "dvb-s" + +msgid "all" +msgstr "alle" + +msgid "blacklist" +msgstr "Blacklist" + +msgid "whitelist" +msgstr "Whitelist" + +msgid "has decoder" +msgstr "mit Decoder" + +msgid "is primary" +msgstr "ist primär" + +msgid "has decoder + is primary" +msgstr "mit Decoder und primär" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "Sync Early Patch benutzen" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "DVB-Empfänger %d nutzt LNB Nr." + +msgid "Setup.LNB$Log LNB usage" +msgstr "LNB-Nutzung protokollieren" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "Dolby Digital Ton aufzeichnen" + +msgid "Setup.Recording$Video directory policy" +msgstr "Videoverzeichnispolitik" + +msgid "Setup.Recording$Number of video directories" +msgstr "Anzahl der Videoverzeichnisse" + +msgid "Setup.Recording$Video %d priority" +msgstr "Video %d Priorität" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "Video %d min. MB frei" + +msgid "Setup.Recording$Friendly filenames" +msgstr "Freundliche Dateinamen" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "Max. Aufnahmengröße (GB)" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "Hard Link Cutter" + +msgid "Setup.Recording$Delete timeshift recording" +msgstr "Zeitversetzte Aufnahme löschen" + +msgid "request" +msgstr "abfragen" + +msgid "Setup.Recording$Show date" +msgstr "Aufnahmedatum anzeigen" + +msgid "Setup.Recording$Show time" +msgstr "Aufnahmezeit anzeigen" + +msgid "Setup.Recording$Show length" +msgstr "Länge der Aufnahme anzeigen" + +msgid "Setup.Recording$Show end of timer" +msgstr "Ende für Timer anzeigen" + +msgid "Setup.Recording$Sort recordings by" +msgstr "Aufnahmen sortieren nach" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "Verzeichnisse vor Aufnahmen einsortieren" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "Aufnahmen nach dem Schneiden löschen" + +msgid "Setup.Recording$Cutter adjust starttime" +msgstr "Startzeit beim Schneiden anpassen" + +msgid "Setup.Replay$Jump&Play" +msgstr "Wiedergabe nach Sprung" + +msgid "Setup.Replay$Play&Jump" +msgstr "Sprung bei Schnittmarke" + +msgid "Setup.Replay$Pause at last mark" +msgstr "Pause bei letzter Marke" + +msgid "Setup.Replay$Reload marks" +msgstr "Marken aktualisieren" + +msgid "Setup.Replay$Skip Seconds" +msgstr "Sprungweite in Sekunden" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "Sprungweite in Sekunden Langsam" + +msgid "Setup.Replay$Length" +msgstr "Länge" + +msgid "Setup.Replay$Length / Number" +msgstr "Länge / Nummer" + +msgid "Setup.Replay$Number" +msgstr "Nummer" + +msgid "Setup.Replay$DVD display mode" +msgstr "DVD Anzeige" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "DVD führende Nullen anzeigen" + +msgid "Setup.Replay$never" +msgstr "nie" + +msgid "Setup.Replay$on begin" +msgstr "am Anfang" + +msgid "Setup.Replay$on end" +msgstr "am Ende" + +msgid "Setup.Replay$on begin and end" +msgstr "am Anfang und Ende" + +msgid "Setup.Replay$Tray open" +msgstr "DVD-Schublade öffnen" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "DVD drosseln auf" + +msgid "Jump" +msgstr "Springen: " + +msgid "Skip +60s" +msgstr "Sprung +60s" + +msgid "Skip -60s" +msgstr "Sprung -60s" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "Schnitt bereits aktiv - zur Schnitt-Liste hinzufügen?" + +msgid "Rename$Up" +msgstr "Höher" + +msgid "Rename$Down" +msgstr "Tiefer" + +msgid "Rename$Previous" +msgstr "Vorheriger" + +msgid "Rename$Next" +msgstr "Nächster" + +msgid "Please mount %s" +msgstr "Bitte %s einlegen!" + +msgid "Please mount DVD %04d" +msgstr "Bitte DVD %04d einlegen!" + +msgid "Please mount DVD %d" +msgstr "Bitte DVD %d einlegen!" + +msgid "Please wait. Checking DVD..." +msgstr "Bitte warten. Überprüfe DVD..." + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "Keine Index-Datei gefunden. Erstellung kann Minuten dauern. Erstellen?" + +msgid "Please wait. Creating index-file..." +msgstr "Bitte warten. Index-Datei wird erstellt..." + +msgid "Wrong DVD!" +msgstr "Falsche DVD!" + +msgid "Permanent Timeshift" +msgstr "Permanentes Timeshift" + +msgid "Setup.LiveBuffer$Location" +msgstr "Speicherort" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "Festplatte" + +msgid "Setup.LiveBuffer$memory" +msgstr "Arbeitsspeicher" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "Puffergröße im Arbeitsspeicher (MB)" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "Auf Festplatte ausweiten wenn nötig" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "Pausierten Puffer beibehalten" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "Puffergröße auf Festplatte (MB)" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "Puffergröße (MB)" diff -ruNp vdr-1.6.0-2/po/el_GR.po vdr-1.6.0-2-extensions/po/el_GR.po --- vdr-1.6.0-2/po/el_GR.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/el_GR.po 2009-04-09 20:48:26.000000000 +0200 @@ -998,3 +998,270 @@ msgstr "" #, c-format msgid "VDR will shut down in %s minutes" msgstr "" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/es_ES.po vdr-1.6.0-2-extensions/po/es_ES.po --- vdr-1.6.0-2/po/es_ES.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/es_ES.po 2009-04-09 20:48:26.000000000 +0200 @@ -999,3 +999,270 @@ msgstr "Pulse cualquier tecla para cance #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR se apagará en %s minutos" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/et_EE.po vdr-1.6.0-2-extensions/po/et_EE.po --- vdr-1.6.0-2/po/et_EE.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/et_EE.po 2009-04-09 20:48:26.000000000 +0200 @@ -998,3 +998,270 @@ msgstr "Restardi katkestamiseks vajuta s #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR lülitub välja %s minuti pärast" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "Ümbernimetamine" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "Käsu asukoht peamenüüs" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "Edenemisriba" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "Salvestuse kuupäev" + +msgid "Setup.Recording$Show time" +msgstr "Salvestuse kellaaeg" + +msgid "Setup.Recording$Show length" +msgstr "Salvestuse pikkus" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "Üles" + +msgid "Rename$Down" +msgstr "Alla" + +msgid "Rename$Previous" +msgstr "Eelmine" + +msgid "Rename$Next" +msgstr "Järgmine" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/fi_FI.po vdr-1.6.0-2-extensions/po/fi_FI.po --- vdr-1.6.0-2/po/fi_FI.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/fi_FI.po 2009-04-09 20:48:26.000000000 +0200 @@ -30,6 +30,253 @@ msgstr "Siirtotilan aloitus epäonnistui! msgid "Starting EPG scan" msgstr "Ohjelmaoppaan päivitys aloitettu" +msgid "Content$Movie/Drama" +msgstr "Elokuva/draama" + +msgid "Content$Detective/Thriller" +msgstr "Etsivä/trilleri" + +msgid "Content$Adventure/Western/War" +msgstr "Seikkailu/western/sota" + +msgid "Content$Science Fiction/Fantasy/Horror" +msgstr "Scifi/fantasia/kauhu" + +msgid "Content$Comedy" +msgstr "Komedia" + +msgid "Content$Soap/Melodrama/Folkloric" +msgstr "Saippua/melodraama/kansanperinne" + +msgid "Content$Romance" +msgstr "Romanssi" + +msgid "Content$Serious/Classical/Religious/Historical Movie/Drama" +msgstr "Vakava/klassinen/uskonnollinen/historiallinen elokuva/draama" + +msgid "Content$Adult Movie/Drama" +msgstr "Aikuiselokuva/draama" + +msgid "Content$News/Current Affairs" +msgstr "Uutiset/ajankohtaisohjelma" + +msgid "Content$News/Weather Report" +msgstr "Uutiset/säätiedot" + +msgid "Content$News Magazine" +msgstr "Uutismakasiini" + +msgid "Content$Documentary" +msgstr "Dokumentti" + +msgid "Content$Discussion/Inverview/Debate" +msgstr "Keskustelu/haastattelu/väittely" + +msgid "Content$Show/Game Show" +msgstr "Show/visailu" + +msgid "Content$Game Show/Quiz/Contest" +msgstr "Visailu/kilpailu" + +msgid "Content$Variety Show" +msgstr "Varietee" + +msgid "Content$Talk Show" +msgstr "Keskusteluohjelma" + +msgid "Content$Sports" +msgstr "Urheilua" + +msgid "Content$Special Event" +msgstr "Erikoistapahtuma" + +msgid "Content$Sport Magazine" +msgstr "Urheilumakasiini" + +msgid "Content$Football" +msgstr "Jalkapallo" + +msgid "Content$Tennis/Squash" +msgstr "Tennis/Squash" + +msgid "Content$Team Sports" +msgstr "Joukkueurheilua" + +msgid "Content$Athletics" +msgstr "Yleisurheilua" + +msgid "Content$Motor Sport" +msgstr "Moottoriurheilua" + +msgid "Content$Water Sport" +msgstr "Vesiurheilua" + +msgid "Content$Winter Sports" +msgstr "Talviurheilua" + +msgid "Content$Equestrian" +msgstr "Ratsastusta" + +msgid "Content$Martial Sports" +msgstr "Kamppailu-urheilua" + +msgid "Content$Children's/Youth Programmes" +msgstr "Lasten ja nuorten ohjelma" + +msgid "Content$Pre-school Children's Programmes" +msgstr "Alle kouluikäisten ohjelma" + +msgid "Content$Entertainment Programmes for 6 to 14" +msgstr "Viihdeohjelma 6-14 vuotiaille" + +msgid "Content$Entertainment Programmes for 10 to 16" +msgstr "Viihdeohjelma 10-16 vuotiaille" + +msgid "Content$Informational/Educational/School Programme" +msgstr "Opetus/kouluohjelma" + +msgid "Content$Cartoons/Puppets" +msgstr "Piirretty/nukke-esitys" + +msgid "Content$Music/Ballet/Dance" +msgstr "Musiikki/baletti/tanssi" + +msgid "Content$Rock/Pop" +msgstr "Rock/pop" + +msgid "Content$Serious/Classical Music" +msgstr "Vakava/klassinen musiikki" + +msgid "Content$Folk/Tradional Music" +msgstr "Folk/kansanmusiikki" + +msgid "Content$Jazz" +msgstr "Jazz" + +msgid "Content$Musical/Opera" +msgstr "Musikaali/ooppera" + +msgid "Content$Ballet" +msgstr "Baletti" + +msgid "Content$Arts/Culture" +msgstr "Taide/kulttuuri" + +msgid "Content$Performing Arts" +msgstr "Performanssitaide" + +msgid "Content$Fine Arts" +msgstr "Kuvataide" + +msgid "Content$Religion" +msgstr "Uskonto" + +msgid "Content$Popular Culture/Traditional Arts" +msgstr "Populaarikulttuuri/perinnetaiteet" + +msgid "Content$Literature" +msgstr "Kirjallisuus" + +msgid "Content$Film/Cinema" +msgstr "Elokuvataide" + +msgid "Content$Experimental Film/Video" +msgstr "Kokeellinen elokuva/video" + +msgid "Content$Broadcasting/Press" +msgstr "Televisio/radio/lehdistö" + +msgid "Content$New Media" +msgstr "Uusmedia" + +msgid "Content$Arts/Culture Magazines" +msgstr "Taide/kulttuurimakasiini" + +msgid "Content$Fashion" +msgstr "Muoti" + +msgid "Content$Social/Political/Economics" +msgstr "Yhteiskunta/politiikka/talous" + +msgid "Content$Magazines/Reports/Documentary" +msgstr "Makasiini/reportaasi/dokumentti" + +msgid "Content$Economics/Social Advisory" +msgstr "Talous/yhteiskunnallinen neuvonta" + +msgid "Content$Remarkable People" +msgstr "Merkittävät henkilöt" + +msgid "Content$Education/Science/Factual" +msgstr "Koulutus/tiede" + +msgid "Content$Nature/Animals/Environment" +msgstr "Luonto/eläimet/ympäristö" + +msgid "Content$Technology/Natural Sciences" +msgstr "Teknologia/luonnontiede" + +msgid "Content$Medicine/Physiology/Psychology" +msgstr "Lääketiede/fysiologia/psykologia" + +msgid "Content$Foreign Countries/Expeditions" +msgstr "Vieraat maat/tutkimusretket" + +msgid "Content$Social/Spiritual Sciences" +msgstr "Yhteiskunta/hengelliset tieteet" + +msgid "Content$Further Education" +msgstr "Jatkokoulutus" + +msgid "Content$Languages" +msgstr "Kielet" + +msgid "Content$Leisure/Hobbies" +msgstr "Vapaa-aika ja harrastukset" + +msgid "Content$Tourism/Travel" +msgstr "Turismi/matkustaminen" + +msgid "Content$Handicraft" +msgstr "Käsityöt" + +msgid "Content$Motoring" +msgstr "Autoilu" + +msgid "Content$Fitness & Health" +msgstr "Kuntoilu & terveys" + +msgid "Content$Cooking" +msgstr "Ruuanlaitto" + +msgid "Content$Advertisement/Shopping" +msgstr "Mainostaminen/ostaminen" + +msgid "Content$Gardening" +msgstr "Puutarhanhoito" + +msgid "Content$Original Language" +msgstr "Alkuperäiskieli" + +msgid "Content$Black & White" +msgstr "Mustavalkoinen" + +msgid "Content$Unpublished" +msgstr "Julkaisematon" + +msgid "Content$Live Broadcast" +msgstr "Suoralähetys" + +msgid "Content$Special Characteristics" +msgstr "Erikoisominaisuus" + +msgid "Content$Drama" +msgstr "Draama" + +#, c-format +msgid "Suitable for those aged %d and over" +msgstr "Kielletty alle %d vuotiailta" + msgid "No title" msgstr "Ei esitystä" @@ -1001,3 +1248,273 @@ msgstr "Peru uudelleenkäynnistys painama #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR sammuu %s minuutin kuluttua" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "Polku" + +msgid "Timer commands" +msgstr "Ajastinkomennot" + +msgid "Rename recording" +msgstr "Nimeä tallenne" + +msgid "Date" +msgstr "Päiväys" + +msgid "Length" +msgstr "Pituus" + +msgid "Size" +msgstr "Koko" + +msgid "Delete marks information?" +msgstr "Poista tallenteen merkinnät" + +msgid "Delete resume information?" +msgstr "Poista tallenteen paluutiedot" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "Komentojen sijainti päävalikossa" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "Näytä aikajana" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "Dolby Digital tallennus" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "Näytä tallenteen päiväys" + +msgid "Setup.Recording$Show time" +msgstr "Näytä tallenteen ajankohta" + +msgid "Setup.Recording$Show length" +msgstr "Näytä tallenteen kesto" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "Ylemmäs" + +msgid "Rename$Down" +msgstr "Alemmas" + +msgid "Rename$Previous" +msgstr "Edellinen" + +msgid "Rename$Next" +msgstr "Seuraava" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Parameters" +msgstr "Parametrit" + +msgid "Permanent Timeshift" +msgstr "Jatkuva ajansiirto" + +msgid "Setup.LiveBuffer$Location" +msgstr "Puskurin sijainti" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "kovalevyllä" + +msgid "Setup.LiveBuffer$memory" +msgstr "muistissa" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "Puffergröße im Arbeitsspeicher (MB)" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "Käytä kovalevyä tarvittaessa" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "Pidä pysäytetty puskuri" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "Puffergröße auf Festplatte (MB)" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "Puskurin koko (MB)" diff -ruNp vdr-1.6.0-2/po/fr_FR.po vdr-1.6.0-2-extensions/po/fr_FR.po --- vdr-1.6.0-2/po/fr_FR.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/fr_FR.po 2009-04-09 20:48:26.000000000 +0200 @@ -8,6 +8,7 @@ # Pierre Briec , 2006 # Bruno Roussel , 2007 # Michael Nival , 2007 +# Patrice Staudt , 2007, 2008 # msgid "" msgstr "" @@ -1004,3 +1005,270 @@ msgstr "Appuyer sur une touche pour annu #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR s'arrêtera dans %s minutes" + +msgid "Channel locked by LNB!" +msgstr "Chaîne interdite par la LNB" + +msgid "Childlock" +msgstr "Adulte" + +msgid "Path" +msgstr "Dossiers" + +msgid "Timer commands" +msgstr "Commandes de programmation" + +msgid "Rename recording" +msgstr "Renommer l'enregistrement" + +msgid "Date" +msgstr "Date" + +msgid "Length" +msgstr "Longeur" + +msgid "Size" +msgstr "Taille" + +msgid "Delete marks information?" +msgstr "Effacer marque d'information?" + +msgid "Delete resume information?" +msgstr "Effacer resume information?" + +msgid "DVD plugin is not installed!" +msgstr "Le plugin de DVD n'est pas installé!" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "Dir principal alphabétiquement, subdirs flexibles" + +msgid "main dir by date, subdirs flexible" +msgstr "Dir principal à la date, subdirs flexibles" + +msgid "all alphabetically" +msgstr "tous alphabétiquement" + +msgid "all by date" +msgstr "tous à la date" + +msgid "Sorting" +msgstr "Triage" + +msgid "Setup.OSD$WarEagle icons" +msgstr "Icônes WarEagle" + +msgid "Setup.OSD$Main menu command position" +msgstr "Position des commandes dans le menu" + +msgid "Setup.OSD$Show valid input" +msgstr "Afficher l'entrée valide" + +msgid "Setup.EPG$Show progress bar" +msgstr "Montrer la barre de progression" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "Intervalle de recherche EPG de double(min)" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "Double entrée EPG externe" + +msgid "adjust" +msgstr "ajuster" + +msgid "delete" +msgstr "effacer" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "Mélanger les EPG interne et externe" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "Arreter la reconnaissance des événements VPS" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "Utiliser le correctif AC3-Transfer" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "Utilisez Sync début patch" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "La carte DVB %d utilise la LNB No." + +msgid "Setup.LNB$Log LNB usage" +msgstr "Protocoller l'utilisation du LNB" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "Enregistrer en Dolby Digital" + +msgid "Setup.Recording$Video directory policy" +msgstr "Régles de répertoires vidéo" + +msgid "Setup.Recording$Number of video directories" +msgstr "Nombre de répertoires vidéo" + +msgid "Setup.Recording$Video %d priority" +msgstr "Video %d prioritaires" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "Video %d min. librei Mo" + +msgid "Setup.Recording$Friendly filenames" +msgstr "Noms de fichiers facile" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "Taille max. de l'enregistrement (GB)" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "Découpe Hard links" + +msgid "Setup.Recording$Show date" +msgstr "Montrer la date d'enregistrement" + +msgid "Setup.Recording$Show time" +msgstr "Montrer l'heure d'enregistrement" + +msgid "Setup.Recording$Show length" +msgstr "Monter la longueur de l'enregistrement" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "Montrer la fin du temporisateur" + +msgid "Setup.Recording$Sort recordings by" +msgstr "Ordonner les enregistrement suivant" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "Les dossiers devant les enregistrements" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "Effacer l'enregistrement après la découpe" + +msgid "Setup.Replay$Jump&Play" +msgstr "Lecture après saut" + +msgid "Setup.Replay$Play&Jump" +msgstr "Saut sur les marques de découpes" + +msgid "Setup.Replay$Pause at last mark" +msgstr "Pause après la dernière marque" + +msgid "Setup.Replay$Reload marks" +msgstr "Actualiser les marques" + +msgid "Setup.Replay$Skip Seconds" +msgstr "Longueur de saut en secondes" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "Longueur de saut lent en secondes" + +msgid "Setup.Replay$Length" +msgstr "Longueur" + +msgid "Setup.Replay$Length / Number" +msgstr "Longueur / Numéro" + +msgid "Setup.Replay$Number" +msgstr "Numéro" + +msgid "Setup.Replay$DVD display mode" +msgstr "Afficher le DVD" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "Afficher les zéros devant le numéro du DVD" + +msgid "Setup.Replay$never" +msgstr "jamais" + +msgid "Setup.Replay$on begin" +msgstr "au début" + +msgid "Setup.Replay$on end" +msgstr "à la fin" + +msgid "Setup.Replay$on begin and end" +msgstr "au début et à la fin" + +msgid "Setup.Replay$Tray open" +msgstr "Ouvrir le tiroir du lecteur DVD" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "Ralentir la vitesse du DVD à" + +msgid "Jump" +msgstr "Saut" + +msgid "Skip +60s" +msgstr "Avance +60s" + +msgid "Skip -60s" +msgstr "Recule -60s" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "Découpe déjà active - l'ajouter à la liste de découpe?" + +msgid "Rename$Up" +msgstr "Haut" + +msgid "Rename$Down" +msgstr "Bas" + +msgid "Rename$Previous" +msgstr "Précédent" + +msgid "Rename$Next" +msgstr "Suivant" + +msgid "Please mount %s" +msgstr "Mettez %s dans le lecteur" + +msgid "Please mount DVD %04d" +msgstr "Mettez le DVD %04d dans le lecteur" + +msgid "Please mount DVD %d" +msgstr "Mettez le DVD %d dans le lecteur" + +msgid "Please wait. Checking DVD..." +msgstr "Un moment SVP. Vérification du DVD..." + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "Pas trouvé de fichiers index. La création de ce ficher prends quelques minutes. Créer?" + +msgid "Please wait. Creating index-file..." +msgstr "Attendez, svp. Le fichier index est en cours de création..." + +msgid "Wrong DVD!" +msgstr "Mauvais DVD!" + +msgid "Permanent Timeshift" +msgstr "Timeshift permanent" + +msgid "Setup.LiveBuffer$Location" +msgstr "Localisation" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "disque dur" + +msgid "Setup.LiveBuffer$memory" +msgstr "mémoire" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "Taille de la mémoire tampon dans la mémoire (Mo)" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "Ètendre au disque dur, si nécessaire" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "Gardez en veille la mémoire tampon" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "Taille de la mémoire tampon sur le disque dur (Mo)" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "Taille de la mémoire tampon (Mo)" diff -ruNp vdr-1.6.0-2/po/hr_HR.po vdr-1.6.0-2-extensions/po/hr_HR.po --- vdr-1.6.0-2/po/hr_HR.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/hr_HR.po 2009-04-09 20:48:26.000000000 +0200 @@ -1000,3 +1000,270 @@ msgstr "Pritisnite jednu tipku za poni¹t #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR æe se iskljuèiti za %s minuta" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/hu_HU.po vdr-1.6.0-2-extensions/po/hu_HU.po --- vdr-1.6.0-2/po/hu_HU.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/hu_HU.po 2009-04-09 20:48:26.000000000 +0200 @@ -1002,3 +1002,270 @@ msgstr "Nyomj egy gombot az újraindítás #, c-format msgid "VDR will shut down in %s minutes" msgstr "A VDR leáll %s perc múlva" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/it_IT.po vdr-1.6.0-2-extensions/po/it_IT.po --- vdr-1.6.0-2/po/it_IT.po 2008-09-11 13:29:43.000000000 +0200 +++ vdr-1.6.0-2-extensions/po/it_IT.po 2009-04-09 20:48:26.000000000 +0200 @@ -11,8 +11,8 @@ msgid "" msgstr "" "Project-Id-Version: VDR 1.6.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-02-10 12:22+0100\n" -"PO-Revision-Date: 2008-04-17 01:07+0100\n" +"POT-Creation-Date: 2008-10-05 05:55+0200\n" +"PO-Revision-Date: 2008-10-05 05:57+0100\n" "Last-Translator: Diego Pierotto \n" "Language-Team: Italian\n" "MIME-Version: 1.0\n" @@ -22,6 +22,9 @@ msgstr "" msgid "*** Invalid Channel ***" msgstr "*** Canale NON valido ***" +msgid "Channel locked by LNB!" +msgstr "Canale bloccato dal LNB!" + msgid "Channel not available!" msgstr "Canale non disponibile!" @@ -31,6 +34,253 @@ msgstr "Impossibile avviare mod. trasfer msgid "Starting EPG scan" msgstr "Inizio scansione EPG" +msgid "Content$Movie/Drama" +msgstr "Film/Dramma" + +msgid "Content$Detective/Thriller" +msgstr "Investigativo/Giallo" + +msgid "Content$Adventure/Western/War" +msgstr "Avventura/Western/Guerra" + +msgid "Content$Science Fiction/Fantasy/Horror" +msgstr "Finzione/Fantasia/Horror" + +msgid "Content$Comedy" +msgstr "Commedia" + +msgid "Content$Soap/Melodrama/Folkloric" +msgstr "Telenovella/Melodramma/Folcloristico" + +msgid "Content$Romance" +msgstr "Romanzo" + +msgid "Content$Serious/Classical/Religious/Historical Movie/Drama" +msgstr "Serio/Classico/Religioso/Film storico/Dramma" + +msgid "Content$Adult Movie/Drama" +msgstr "Film per adulti/Dramma" + +msgid "Content$News/Current Affairs" +msgstr "Notizie/Ultima ora" + +msgid "Content$News/Weather Report" +msgstr "Notizie/Previsioni meteo" + +msgid "Content$News Magazine" +msgstr "Rivista di notizie" + +msgid "Content$Documentary" +msgstr "Documentario" + +msgid "Content$Discussion/Inverview/Debate" +msgstr "Discussione/Intervista/Dibattito" + +msgid "Content$Show/Game Show" +msgstr "Spettacolo/Gioco a premi" + +msgid "Content$Game Show/Quiz/Contest" +msgstr "Gioco a premi/Quiz/Gara" + +msgid "Content$Variety Show" +msgstr "Spettacolo di varietà" + +msgid "Content$Talk Show" +msgstr "Talk Show" + +msgid "Content$Sports" +msgstr "Sport" + +msgid "Content$Special Event" +msgstr "Evento speciale" + +msgid "Content$Sport Magazine" +msgstr "Rivista di sport" + +msgid "Content$Football" +msgstr "Calcio" + +msgid "Content$Tennis/Squash" +msgstr "Tennis/Squash" + +msgid "Content$Team Sports" +msgstr "Sport di squadra" + +msgid "Content$Athletics" +msgstr "Atletica" + +msgid "Content$Motor Sport" +msgstr "Sport motoristici" + +msgid "Content$Water Sport" +msgstr "Sport acquatici" + +msgid "Content$Winter Sports" +msgstr "Sport invernali" + +msgid "Content$Equestrian" +msgstr "Equitazione" + +msgid "Content$Martial Sports" +msgstr "Arti marziali" + +msgid "Content$Children's/Youth Programmes" +msgstr "Programmi per ragazzi/giovani" + +msgid "Content$Pre-school Children's Programmes" +msgstr "Programmi per ragazzi prescolastici" + +msgid "Content$Entertainment Programmes for 6 to 14" +msgstr "Programmi di intrattenimento da 6 a 14" + +msgid "Content$Entertainment Programmes for 10 to 16" +msgstr "Programmi di intrattenimento da 10 a 16" + +msgid "Content$Informational/Educational/School Programme" +msgstr "Informativo/Educativo/Programma scolastico" + +msgid "Content$Cartoons/Puppets" +msgstr "Cartoni/Pupazzi" + +msgid "Content$Music/Ballet/Dance" +msgstr "Musica/Balletto/Danza" + +msgid "Content$Rock/Pop" +msgstr "Rock/Pop" + +msgid "Content$Serious/Classical Music" +msgstr "Serio/Musica classica" + +msgid "Content$Folk/Tradional Music" +msgstr "Folclore/Musica tradizionale" + +msgid "Content$Jazz" +msgstr "Jazz" + +msgid "Content$Musical/Opera" +msgstr "Musical/Opera" + +msgid "Content$Ballet" +msgstr "Balletto" + +msgid "Content$Arts/Culture" +msgstr "Arte/Cultura" + +msgid "Content$Performing Arts" +msgstr "Arti di rendimento" + +msgid "Content$Fine Arts" +msgstr "Arti fine" + +msgid "Content$Religion" +msgstr "Religione" + +msgid "Content$Popular Culture/Traditional Arts" +msgstr "Cultura popolare/Arti tradizionali" + +msgid "Content$Literature" +msgstr "Letteratura" + +msgid "Content$Film/Cinema" +msgstr "Film/Cinema" + +msgid "Content$Experimental Film/Video" +msgstr "Film esperimentale/Video" + +msgid "Content$Broadcasting/Press" +msgstr "Trasmissione/Stampa" + +msgid "Content$New Media" +msgstr "Nuovo programma" + +msgid "Content$Arts/Culture Magazines" +msgstr "Arte/Riviste di cultura" + +msgid "Content$Fashion" +msgstr "Moda" + +msgid "Content$Social/Political/Economics" +msgstr "Società/Politica/Economia" + +msgid "Content$Magazines/Reports/Documentary" +msgstr "Riviste/Reportage/Documentari" + +msgid "Content$Economics/Social Advisory" +msgstr "Economia/Consulenza sociale" + +msgid "Content$Remarkable People" +msgstr "Personaggi importanti" + +msgid "Content$Education/Science/Factual" +msgstr "Educazione/Scienza/Fatti" + +msgid "Content$Nature/Animals/Environment" +msgstr "Natura/Animali/Ambiente" + +msgid "Content$Technology/Natural Sciences" +msgstr "Tecnologia/Scienze naturali" + +msgid "Content$Medicine/Physiology/Psychology" +msgstr "Medicina/Filosofia/Psicologia" + +msgid "Content$Foreign Countries/Expeditions" +msgstr "Paesi esteri/Spedizioni" + +msgid "Content$Social/Spiritual Sciences" +msgstr "Società/Scienze spirituali" + +msgid "Content$Further Education" +msgstr "Altra educazione" + +msgid "Content$Languages" +msgstr "Lingua" + +msgid "Content$Leisure/Hobbies" +msgstr "Tempo libero/Hobby" + +msgid "Content$Tourism/Travel" +msgstr "Turismo/Viaggi" + +msgid "Content$Handicraft" +msgstr "Artigianato" + +msgid "Content$Motoring" +msgstr "Motori" + +msgid "Content$Fitness & Health" +msgstr "Culturismo & Salute" + +msgid "Content$Cooking" +msgstr "Cucina" + +msgid "Content$Advertisement/Shopping" +msgstr "Pubblicità/Acquisti" + +msgid "Content$Gardening" +msgstr "Giardinaggio" + +msgid "Content$Original Language" +msgstr "Lingua madre" + +msgid "Content$Black & White" +msgstr "Bianco & Nero" + +msgid "Content$Unpublished" +msgstr "Non pubblicato" + +msgid "Content$Live Broadcast" +msgstr "ys" + +msgid "Content$Special Characteristics" +msgstr "Caratteristiche speciali" + +msgid "Content$Drama" +msgstr "Dramma" + +#, c-format +msgid "Suitable for those aged %d and over" +msgstr "Adatto per coloro con %d di età e oltre" + msgid "No title" msgstr "Senza titolo" @@ -217,6 +467,9 @@ msgstr "Utente8" msgid "Key$User9" msgstr "Utente9" +msgid "Recording started" +msgstr "Registrazione avviata" + msgid "Disk" msgstr "Disco" @@ -313,6 +566,9 @@ msgstr "Guard" msgid "Hierarchy" msgstr "Gerarchia" +msgid "Parameters" +msgstr "Parametri" + msgid "Channel settings are not unique!" msgstr "Parametri canale non univoci!" @@ -364,9 +620,21 @@ msgstr "Priorità" msgid "Lifetime" msgstr "Durata" +msgid "Childlock" +msgstr "Filtro fam." + +msgid "yes" +msgstr "sì" + +msgid "no" +msgstr "no" + msgid "File" msgstr "Nome" +msgid "Path" +msgstr "Percorso" + msgid "First day" msgstr "1° giorno" @@ -385,6 +653,9 @@ msgstr "Eliminare il timer?" msgid "Timer still recording - really delete?" msgstr "Timer in registrazione - eliminare?" +msgid "Timer commands" +msgstr "Comandi timer" + msgid "Event" msgstr "Evento" @@ -445,6 +716,27 @@ msgstr "Riproduci" msgid "Button$Rewind" msgstr "Riavvolgi" +msgid "Rename recording" +msgstr "Rinomina registrazione" + +msgid "Date" +msgstr "Data" + +msgid "Length" +msgstr "Durata" + +msgid "Size" +msgstr "Dimensione" + +msgid "Delete marks information?" +msgstr "Eliminare informazione marcatori?" + +msgid "Delete resume information?" +msgstr "Eliminare informazione ripristino?" + +msgid "Error while accessing recording!" +msgstr "Errore accesso alla registrazione!" + msgid "Recordings" msgstr "Registrazioni" @@ -454,8 +746,8 @@ msgstr "Apri" msgid "Commands" msgstr "Comandi" -msgid "Error while accessing recording!" -msgstr "Errore accesso alla registrazione!" +msgid "DVD plugin is not installed!" +msgstr "Il plugin DVD non è installato!" msgid "Delete recording?" msgstr "Eliminare la registrazione?" @@ -466,6 +758,21 @@ msgstr "Errore eliminazione registrazion msgid "Recording commands" msgstr "Comandi di registrazione" +msgid "main dir alphabetically, subdirs flexible" +msgstr "Dir. princ. in ordine alfabetico, sottodir. flessibili" + +msgid "main dir by date, subdirs flexible" +msgstr "Dir. princ. per data, sottodir. flessibili" + +msgid "all alphabetically" +msgstr "Tutte in ordine alfabetico" + +msgid "all by date" +msgstr "Tutte per data" + +msgid "Sorting" +msgstr "Ordinamento" + msgid "never" msgstr "mai" @@ -475,6 +782,18 @@ msgstr "in base allo stile interfaccia" msgid "always" msgstr "sempre" +msgid "default" +msgstr "predefinito" + +msgid "VDR - text" +msgstr "VDR - Testo" + +msgid "text" +msgstr "Testo" + +msgid "VDR - version" +msgstr "VDR - Versione" + msgid "OSD" msgstr "OSD" @@ -487,6 +806,9 @@ msgstr "Stile interfaccia" msgid "Setup.OSD$Theme" msgstr "Tema colori" +msgid "Setup.OSD$WarEagle icons" +msgstr "Icone WarEagle" + msgid "Setup.OSD$Left" msgstr "Sinistra" @@ -556,12 +878,30 @@ msgstr "Tasto Menu per chiudere" msgid "Setup.OSD$Recording directories" msgstr "Directory di registrazione" +msgid "Setup.OSD$Main menu title" +msgstr "Titolo menu principale" + +msgid "Setup.OSD$- Text" +msgstr "- Testo" + +msgid "Setup.OSD$Main menu command position" +msgstr "Posizione comandi menu princ." + +msgid "Setup.OSD$Show valid input" +msgstr "Mostra ingresso valido" + msgid "EPG" msgstr "Guida programmi EPG" msgid "Button$Scan" msgstr "Scansione" +msgid "blacklist" +msgstr "lista nera" + +msgid "whitelist" +msgstr "elenco autorizzati" + msgid "Setup.EPG$EPG scan timeout (h)" msgstr "Scadenza aggiorn. EPG (ore)" @@ -571,6 +911,9 @@ msgstr "Livello correzione EPG" msgid "Setup.EPG$EPG linger time (min)" msgstr "Mostra vecchi dati EPG (min)" +msgid "Setup.EPG$Show progress bar" +msgstr "Mostra barra avanzamento" + msgid "Setup.EPG$Set system time" msgstr "Imposta orario di sistema" @@ -585,6 +928,27 @@ msgstr "Lingue preferite" msgid "Setup.EPG$Preferred language" msgstr "Lingua preferita" +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "Tempo doppia ricerca EPG (min)" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "Doppio valore EPG esterno" + +msgid "adjust" +msgstr "regola" + +msgid "delete" +msgstr "elimina" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "Mescola EPG interno e esterno" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "Disabilita esec. evento VPS" + +msgid "Setup.EPG$Mode of noEPG-Patch" +msgstr "Modalità di noEPG-Patch" + msgid "pan&scan" msgstr "pan&scan" @@ -594,9 +958,6 @@ msgstr "letterbox" msgid "center cut out" msgstr "center cut out" -msgid "no" -msgstr "no" - msgid "names only" msgstr "solo nomi" @@ -615,6 +976,27 @@ msgstr "nuovi transponder" msgid "DVB" msgstr "Scheda DVB" +msgid "qam256" +msgstr "qam256" + +msgid "dvb-c" +msgstr "dvb-c" + +msgid "dvb-s" +msgstr "dvb-s" + +msgid "all" +msgstr "tutti" + +msgid "has decoder" +msgstr "con decoder" + +msgid "is primary" +msgstr "primaria" + +msgid "has decoder + is primary" +msgstr "con decoder e primaria" + msgid "Setup.DVB$Primary DVB interface" msgstr "Scheda DVB primaria" @@ -654,9 +1036,28 @@ msgstr "Trasparenza sottotitoli" msgid "Setup.DVB$Subtitle background transparency" msgstr "Trasparenza sfondo sottotitoli" +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "Utilizza correzione AC3-Transfer" + +msgid "Setup.DVB$Channel Blocker" +msgstr "Blocco canale" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "Modalità filtro blocco canale" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "Utilizza correzione Early Sync" + msgid "LNB" msgstr "LNB" +#, c-format +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "La scheda DVB %d utilizza LNB No." + +msgid "Setup.LNB$Log LNB usage" +msgstr "Registra utilizzo LNB" + msgid "Setup.LNB$Use DiSEqC" msgstr "Utilizza DiSEqC" @@ -699,6 +1100,9 @@ msgstr "La CAM è in uso - vuoi reimposta msgid "Can't reset CAM!" msgstr "Impossibile reimpostare il modulo CAM!" +msgid "request" +msgstr "chiedi" + msgid "Recording" msgstr "Registrazione" @@ -723,9 +1127,29 @@ msgstr "Priorità di pausa" msgid "Setup.Recording$Pause lifetime (d)" msgstr "Durata pausa (gg)" +msgid "Setup.Recording$Record Dolby Digital" +msgstr "Registra Dolby Digital" + +msgid "Setup.Recording$Video directory policy" +msgstr "Regole directory video" + +msgid "Setup.Recording$Number of video directories" +msgstr "Numero di directory video" + +#, c-format +msgid "Setup.Recording$Video %d priority" +msgstr "Priorità video %d " + +#, c-format +msgid "Setup.Recording$Video %d min. free MB" +msgstr "Min. MB disponibili video %d " + msgid "Setup.Recording$Use episode name" msgstr "Utilizza nome episodio" +msgid "Setup.Recording$Friendly filenames" +msgstr "Nomi file semplici" + msgid "Setup.Recording$Use VPS" msgstr "Utilizza VPS" @@ -744,9 +1168,39 @@ msgstr "Durata reg. immediata (min)" msgid "Setup.Recording$Max. video file size (MB)" msgstr "Dim. massima file video (MB)" +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "Dim. massima reg. (GB)" + msgid "Setup.Recording$Split edited files" msgstr "Dividi i file modificati" +msgid "Setup.Recording$Hard Link Cutter" +msgstr "Taglia collegamenti Hard" + +msgid "Setup.Recording$Delete timeshift recording" +msgstr "Elimina reg. timeshift" + +msgid "Setup.Recording$Show date" +msgstr "Mostra data registrazione" + +msgid "Setup.Recording$Show time" +msgstr "Mostra ora registrazione" + +msgid "Setup.Recording$Show length" +msgstr "Mostra durata registrazione" + +msgid "Setup.Recording$Show end of timer" +msgstr "Mostra fine del timer" + +msgid "Setup.Recording$Sort recordings by" +msgstr "Ordina registrazioni per" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "Ordina directory prima di reg." + +msgid "Setup.Recording$Cutter auto delete" +msgstr "Elimina taglio automatico" + msgid "Replay" msgstr "Riproduzione" @@ -759,6 +1213,63 @@ msgstr "Mostra modalità riproduzione" msgid "Setup.Replay$Resume ID" msgstr "ID di ripristino" +msgid "Setup.Replay$Jump&Play" +msgstr "Vai a & Riproduci" + +msgid "Setup.Replay$Play&Jump" +msgstr "Riproduci & Vai a" + +msgid "Setup.Replay$Pause at last mark" +msgstr "Pausa all'ultimo marcatore" + +msgid "Setup.Replay$Reload marks" +msgstr "Ricarica marcatori" + +msgid "Setup.Replay$Skip Seconds" +msgstr "Salta secondi" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "Salta secondi lentamente" + +msgid "Setup.Replay$Length" +msgstr "Durata" + +msgid "Setup.Replay$Length / Number" +msgstr "Durata / Numero" + +msgid "Setup.Replay$Number" +msgstr "Numero" + +msgid "Setup.Replay$DVD display mode" +msgstr "Mod. visualizzazione DVD" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "Mostra zeri davanti al DVD" + +msgid "Setup.Replay$never" +msgstr "mai" + +msgid "Setup.Replay$on begin" +msgstr "all'inizio" + +msgid "Setup.Replay$on end" +msgstr "alla fine" + +msgid "Setup.Replay$on begin and end" +msgstr "all'inizio e alla fine" + +msgid "Setup.Replay$Tray open" +msgstr "Apri vassoio" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "Limita velocità DVD a" + +msgid "Setup.Miscellaneous$only in channelinfo" +msgstr "solo nelle info canale" + +msgid "Setup.Miscellaneous$only in progress display" +msgstr "solo nel canale in esec." + msgid "Miscellaneous" msgstr "Generici" @@ -786,9 +1297,54 @@ msgstr "come prima" msgid "Setup.Miscellaneous$Initial volume" msgstr "Volume iniziale" +msgid "Setup.Miscellaneous$Volume ctrl with left/right" +msgstr "Controllo volume con Sinistra/Destra" + +msgid "Setup.Miscellaneous$Channelgroups with left/right" +msgstr "Gruppi canali con Sinistra/Destra" + +msgid "Setup.Miscellaneous$Search fwd/back with left/right" +msgstr "Cerca avanti/indietro con Sinistra/Destra" + msgid "Setup.Miscellaneous$Emergency exit" msgstr "Uscita di emergenza" +msgid "Setup.Miscellaneous$Lirc repeat delay" +msgstr "Ritardo ripetizione LIRC" + +msgid "Setup.Miscellaneous$Lirc repeat freq" +msgstr "Frequenza ripetizione LIRC" + +msgid "Setup.Miscellaneous$Lirc repeat timeout" +msgstr "Scadenza ripetizione LIRC" + +msgid "Permanent Timeshift" +msgstr "Timeshift permanente" + +msgid "Setup.LiveBuffer$Location" +msgstr "Posizione" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "Disco fisso" + +msgid "Setup.LiveBuffer$memory" +msgstr "Memoria" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "Dim. buffer in memoria (MB)" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "Utilizza disco fisso se necessario" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "Mantieni buffer di pausa" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "Dim. buffer nel disco fisso (MB)" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "Dimensione buffer (MB)" + msgid "Plugins" msgstr "Plugins" @@ -814,7 +1370,6 @@ msgstr "Programmi" msgid "VDR" msgstr "VDR" -#. TRANSLATORS: note the leading blank! msgid " Stop replaying" msgstr " Ferma riproduzione" @@ -830,7 +1385,6 @@ msgstr "Ferma" msgid "Button$Resume" msgstr "Riprendi" -#. TRANSLATORS: note the leading blank! msgid " Cancel editing" msgstr " Annulla modifiche" @@ -861,10 +1415,22 @@ msgstr "Nessuna periferica DVB disponibi msgid "Pausing live video..." msgstr "Pausa del canale in visione..." +msgid "Jump" +msgstr "Vai a" + +msgid "Skip +60s" +msgstr "Salta +60s" + +msgid "Skip -60s" +msgstr "Salta - 60s" + #. TRANSLATORS: note the trailing blank! msgid "Jump: " msgstr "Vai a: " +msgid "Cutter already running - Add to cutting queue?" +msgstr "Taglio in esecuzione - Aggiungere alla coda tagli?" + msgid "No editing marks defined!" msgstr "Nessun marcatore di modifica definito!" @@ -880,9 +1446,6 @@ msgstr "Processo di modifica già attivo! msgid "FileNameChars$ abcdefghijklmnopqrstuvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&" msgstr " aáàbcdeéèfghiìîjklmnoòpqrstuùvwxyz0123456789-.,#~\\^$[]|()*+?{}/:%@&°" -msgid "yes" -msgstr "sì" - msgid "CharMap$ 0\t-.,1#~\\^$[]|()*+?{}/:%@&\tabc2\tdef3\tghi4\tjkl5\tmno6\tpqrs7\ttuv8\twxyz9" msgstr " 0\t-.,1#~\\^$[]|()*+°?{}/:%@&\taàbc2\tdeèf3\tghiì4\tjkl5\tmnoò6\tpqrs7\ttuùv8\twxyz9" @@ -895,6 +1458,18 @@ msgstr "Sovrascrivi" msgid "Button$Insert" msgstr "Inserisci" +msgid "Rename$Up" +msgstr "Su" + +msgid "Rename$Down" +msgstr "Giù" + +msgid "Rename$Previous" +msgstr "Precedente" + +msgid "Rename$Next" +msgstr "Successivo" + msgid "Plugin" msgstr "Plugin" @@ -907,6 +1482,30 @@ msgstr "Canale bloccato (in registrazion msgid "Low disk space!" msgstr "Poco spazio su disco!" +#, c-format +msgid "Please mount %s" +msgstr "Monta %s" + +#, c-format +msgid "Please mount DVD %04d" +msgstr "Monta il DVD %04d" + +#, c-format +msgid "Please mount DVD %d" +msgstr "Monta il DVD %d" + +msgid "Please wait. Checking DVD..." +msgstr "Attendere prego. Verifica DVD..." + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "Nessun indice trovato. La creazione può impiegare alcuni minuti. Crearne uno?" + +msgid "Please wait. Creating index-file..." +msgstr "Attendere prego. Creazione indice..." + +msgid "Wrong DVD!" +msgstr "DVD errato!" + msgid "Can't shutdown - option '-s' not given!" msgstr "Impossibile spegnere - parametro '-s' non assegnato!" @@ -978,9 +1577,6 @@ msgstr "Domenica" msgid "Upcoming recording!" msgstr "Registrazione imminente!" -msgid "Recording started" -msgstr "Registrazione avviata" - msgid "VDR will shut down later - press Power to force" msgstr "VDR si spegnerà più tardi - premi Power per forzare" @@ -1002,3 +1598,4 @@ msgstr "Premi un tasto per annullare il #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR si spegnerà tra %s minuti" + diff -ruNp vdr-1.6.0-2/po/nl_NL.po vdr-1.6.0-2-extensions/po/nl_NL.po --- vdr-1.6.0-2/po/nl_NL.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/nl_NL.po 2009-04-09 20:48:26.000000000 +0200 @@ -1002,3 +1002,270 @@ msgstr "Druk een willekeurige toets om h #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR zal na %s minuten uitschakelen" + +msgid "Channel locked by LNB!" +msgstr "Kanaal geblokkeerd door LNB" + +msgid "Childlock" +msgstr "Kinderslot" + +msgid "Path" +msgstr "Pad" + +msgid "Timer commands" +msgstr "Timer commando's" + +msgid "Rename recording" +msgstr "Hernoem opnamen" + +msgid "Date" +msgstr "Datum" + +msgid "Length" +msgstr "Lengte" + +msgid "Size" +msgstr "Grootte" + +msgid "Delete marks information?" +msgstr "Verwijder informatiemarkeringen?" + +msgid "Delete resume information?" +msgstr "Verwijder hervattingsmarkeringen?" + +msgid "DVD plugin is not installed!" +msgstr "DVd plugin is niet geÃnstalleerd!" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "hoofdmap alfabetisch, submappen flexibel" + +msgid "main dir by date, subdirs flexible" +msgstr "hoofdmap op datum, submappen flexibel" + +msgid "all alphabetically" +msgstr "alles alfabetisch" + +msgid "all by date" +msgstr "alles op datum" + +msgid "Sorting" +msgstr "Sortering" + +msgid "Setup.OSD$WarEagle icons" +msgstr "WarEagle symbolen" + +msgid "Setup.OSD$Main menu command position" +msgstr "Positie commandobalk in hoofdmenu" + +msgid "Setup.OSD$Show valid input" +msgstr "Toon geldige invoer" + +msgid "Setup.EPG$Show progress bar" +msgstr "Toon voortschreidingsbalk" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "Tijdsduur starten dubbele EPG zoekactie (min)" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "externe dubbele EPG invoer" + +msgid "adjust" +msgstr "afstellen" + +msgid "delete" +msgstr "verwijderen" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "Mix in- en externe EPG" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "Schakel aktieve VPS uitzending uit" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "Gebruik AC3-Transfer Fix" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "Gebruik 'Sync Early' Patch" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "LNB kaart %d gebruikt LNB Nr." + +msgid "Setup.LNB$Log LNB usage" +msgstr "Houd LNB gebruik bij" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "Neem Dolby Digital spoor op" + +msgid "Setup.Recording$Video directory policy" +msgstr "Omgang m.b.t. Videomappen" + +msgid "Setup.Recording$Number of video directories" +msgstr "Aantal videomappen" + +msgid "Setup.Recording$Video %d priority" +msgstr "Video %d prioriteit" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "Video %d min. vrij MB" + +msgid "Setup.Recording$Friendly filenames" +msgstr "Handzame bestandsnamen" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "Max. opnamegrootte (GB)" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "'Hard link' bestandsbewerker" + +msgid "Setup.Recording$Show date" +msgstr "Toon datum" + +msgid "Setup.Recording$Show time" +msgstr "Toon tijd" + +msgid "Setup.Recording$Show length" +msgstr "Toon lengte" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "Toon einde van timers" + +msgid "Setup.Recording$Sort recordings by" +msgstr "Sorteer opnames op" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "Sorteer mappen vÃÃr opnames" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "Bestandsbewerker automatisch wissen" + +msgid "Setup.Replay$Jump&Play" +msgstr "Spring&Speel" + +msgid "Setup.Replay$Play&Jump" +msgstr "Speel&Spring" + +msgid "Setup.Replay$Pause at last mark" +msgstr "Pauzeer bij laatste markering" + +msgid "Setup.Replay$Reload marks" +msgstr "Herlaadt markeringen" + +msgid "Setup.Replay$Skip Seconds" +msgstr "Spring seconden" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "Spring seconden langzaam" + +msgid "Setup.Replay$Length" +msgstr "Lengte" + +msgid "Setup.Replay$Length / Number" +msgstr "Lengte / Nummer" + +msgid "Setup.Replay$Number" +msgstr "Nummer" + +msgid "Setup.Replay$DVD display mode" +msgstr "DVD displayinstellingen" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "DVD toon voorloopnullen" + +msgid "Setup.Replay$never" +msgstr "nooit" + +msgid "Setup.Replay$on begin" +msgstr "aan het begin" + +msgid "Setup.Replay$on end" +msgstr "bij het einde" + +msgid "Setup.Replay$on begin and end" +msgstr "bij het begin en aan het einde" + +msgid "Setup.Replay$Tray open" +msgstr "Open DVD lade" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "Beperk DVD omw. snelheid" + +msgid "Jump" +msgstr "Spring" + +msgid "Skip +60s" +msgstr "Spring +60s verder" + +msgid "Skip -60s" +msgstr "Spring -60s terug" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "Bestandsbewerker aktief - aan wachtrij toeveogen?" + +msgid "Rename$Up" +msgstr "Boven" + +msgid "Rename$Down" +msgstr "Onder" + +msgid "Rename$Previous" +msgstr "Vorige" + +msgid "Rename$Next" +msgstr "Volgende" + +msgid "Please mount %s" +msgstr "Koppel %s aan a.u.b." + +msgid "Please mount DVD %04d" +msgstr "Koppel DVD %04d aan a.u.b." + +msgid "Please mount DVD %d" +msgstr "Koppel DVD %d aan a.u.b." + +msgid "Please wait. Checking DVD..." +msgstr "Even wachten, DVD wordt gecontroleerd..." + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "Geen indexbestand gevonden. Aanmaken duurt even, doorgaan?" + +msgid "Please wait. Creating index-file..." +msgstr "Even wachten indexbestand wordt aangemaakt..." + +msgid "Wrong DVD!" +msgstr "Verkeerde DVD!" + +msgid "Permanent Timeshift" +msgstr "Permanente livebuffer" + +msgid "Setup.LiveBuffer$Location" +msgstr "Opslaglocatie" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "hardeschijf" + +msgid "Setup.LiveBuffer$memory" +msgstr "geheugen" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "Buffergrootte in geheugen (MB)" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "Overlopen naar hardeschijf indien noodzakelijk" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "Bewaar gepauzeerde buffer" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "Buffergrootte op harddisk (MB)" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "Buffergrootte (MB)" diff -ruNp vdr-1.6.0-2/po/nn_NO.po vdr-1.6.0-2-extensions/po/nn_NO.po --- vdr-1.6.0-2/po/nn_NO.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/nn_NO.po 2009-04-09 20:48:26.000000000 +0200 @@ -999,3 +999,270 @@ msgstr "" #, c-format msgid "VDR will shut down in %s minutes" msgstr "" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/pl_PL.po vdr-1.6.0-2-extensions/po/pl_PL.po --- vdr-1.6.0-2/po/pl_PL.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/pl_PL.po 2009-04-09 20:48:26.000000000 +0200 @@ -999,3 +999,270 @@ msgstr "Naci¶nij dowolny klawisz aby nie #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR zostanie wy³±czony za %s minut" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/pt_PT.po vdr-1.6.0-2-extensions/po/pt_PT.po --- vdr-1.6.0-2/po/pt_PT.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/pt_PT.po 2009-04-09 20:48:26.000000000 +0200 @@ -998,3 +998,270 @@ msgstr "Pressione qualquer tecla para nã #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR vai desligar em %s minutos" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/ro_RO.po vdr-1.6.0-2-extensions/po/ro_RO.po --- vdr-1.6.0-2/po/ro_RO.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/ro_RO.po 2009-04-09 20:48:26.000000000 +0200 @@ -1001,3 +1001,270 @@ msgstr "Apãsaþi orice tastã pentru a anu #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR se va închide în %s minute" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/ru_RU.po vdr-1.6.0-2-extensions/po/ru_RU.po --- vdr-1.6.0-2/po/ru_RU.po 2008-03-23 11:31:29.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/ru_RU.po 2009-04-09 20:48:26.000000000 +0200 @@ -999,3 +999,271 @@ msgstr "½ÐÖÜØâÕ ÛîÑãî ÚÝÞßÚã ÔÛï ÞâÜÕÝë #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR ÒëÚÛîçØâáï çÕàÕ× %s ÜØÝãâ" + +msgid "Channel locked by LNB!" +msgstr "ºÞÝÒÕàâÕà ÑÛÞÚØàãÕâ ÚÐÝÐÛ" + +msgid "Childlock" +msgstr "´ÕâáÚÐï ÑÛÞÚØàÞÒÚÐ" + +msgid "Path" +msgstr "¿ãâì" + +msgid "Timer commands" +msgstr "ºÞÜÜÐÝÔë âÐÙÜÕàÐ" + +msgid "Rename recording" +msgstr "¿ÕàÕØÜÕÝÞÒÐâì ×Ðߨáì" + +msgid "Date" +msgstr "´ÐâÐ" + +msgid "Length" +msgstr "´ÛØÝÐ" + +msgid "Size" +msgstr "ÀÐ×ÜÕà" + +msgid "Delete marks information?" +msgstr "ÃÔÐÛØâì ÜÕâÚØ?" + +msgid "Delete resume information?" +msgstr "²ÞááâÐÝÞÒØâì ÜÕâÚØ?" + +msgid "DVD plugin is not installed!" +msgstr "¼ÞÔãÛì DVD ÝÕ ãáâÐÝÞÒÛÕÝ!" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "ÓÛÐÒÝÐï ÔØàÕÚâÞàØï ßÞ ÐÛäÐÒØâã, ßÞÔÔØàÕÚâÞàØØ ÓØÑÚÞ" + +msgid "main dir by date, subdirs flexible" +msgstr "ÓÛÐÒÝÐï ÔØàÕÚâÞàØï ßÞ ÒàÕÜÕÝØ, ßÞÔÔØàÕÚâÞàØØ ÓØÑÚÞ" + +msgid "all alphabetically" +msgstr "ÒáÕ ßÞ ÐÛäÐÒØâã" + +msgid "all by date" +msgstr "ÒáÕ ßÞ ÒàÕÜÕÝØ" + +msgid "Sorting" +msgstr "ÁÞàâØàÞÒÚÐ" + +msgid "Setup.OSD$WarEagle icons" +msgstr "WarEagle ØÚÞÝÚØ" + +msgid "Setup.OSD$Main menu command position" +msgstr "ÀÐ×ÜÕéÕÝØÕ ÚÞÜÐÝÔ Ò ÓÛÐÒÝÞÜ ÜÕÝî" + +msgid "Setup.OSD$Show valid input" +msgstr "¿ÞÚÐ× ßàÐÒØÛìÝÞÓÞ ÒÒÞÔÐ" + +msgid "Setup.EPG$Show progress bar" +msgstr "¿ÞÚÐ× ÑÐÛÚØ ßàÞÓàÕááÐ" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "¿ÕàØÞÔ ÔÛï ßÞØáÚÐ ÔÒÞÙÝëå EPG(min)" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "²ÝÕèÝØÙ ØáâÞçÝØÚ ÔÒÞÙÝÞÓÞ EPG" + +msgid "adjust" +msgstr "ÝÐáâàÞØâì" + +msgid "delete" +msgstr "ãÔÐÛØâì" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "ÁÜÕèØÒÐÝØÕ ÒÝãâàÕÝÝÕÓÞ Ø ÒÝÕèÝÕÓÞ EPG" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "·ÐßàÕâ VPS áÞÑëâØï" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "¸áßÞÛì×ÞÒÐâì ÚÞààÕÚâØàÞÒÚã AC3-Transfer" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "¸áßÞÛì×ÞÒÐâì Sync Early " + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "DVB ãáâàÞÙáâÒÞ %d ØáßÞÛì×ãÕâ LNB No." + +msgid "Setup.LNB$Log LNB usage" +msgstr "»ÞÓØàÞÒÐÝØÕ ØáßÞÛì×ÞÒÐÝØï LNB" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "·Ðߨáì Dolby Digital" + +msgid "Setup.Recording$Video directory policy" +msgstr "¿ÞàïÔÞÚ ÒØÔÕÞ ÔØàÕÚâÞàØØ" + +msgid "Setup.Recording$Number of video directories" +msgstr "ºÞÛØçÕáâÒÞ ÒØÔÕÞ ÔØàÕÚâÞàØÙ" + +msgid "Setup.Recording$Video %d priority" +msgstr "Video %d ßàØÞàØâÕâ" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "Video %d ÜØÝ. áÒÞÑÞÔÝÞ MB" + +msgid "Setup.Recording$Friendly filenames" +msgstr "ÇØâÐÑÕÛìÝëÕ ØÜÕÝÐ äÐÙÛÞÒ" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "¼ÐÚá. àÐ×ÜÕà ×ÐßØáØ (GB)" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "¼ÞÝâÐÖ á hard link" + +msgid "Setup.Recording$Show date" +msgstr "¿ÞÚÐ×ëÒÐâì ÔÐâã" + +msgid "Setup.Recording$Show time" +msgstr "¿ÞÚÐ×ëÒÐâì ÒàÕÜï ×ÐߨáØ" + +msgid "Setup.Recording$Show length" +msgstr "¿ÞÚÐ×ëÒÐâì ßàÞÔÞÛÖØâÕÛìÝÞáâì ×ÐߨáØ" + +msgid "Setup.OSD$Main menu title" +msgstr "½Ð×ÒÐÝØÕ ÓÛÐÒÝÞÓÞ ÜÕÝî" + +msgid "Setup.Recording$Show end of timer" +msgstr "¿ÞÚÐ× ÞÚÞÝçÐÝØï âÐÙÜÕàÐ" + +msgid "Setup.Recording$Sort recordings by" +msgstr "ÁÞàâØàÞÒÚÐ ×ÐߨáÕÙ ßÞ" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "ÁÞàâØàÞÒÚÐ ÔØàÕÚâÞàØÙ ÔÞ ×ÐߨáØ" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "°ÒâÞÜÐâØçÕáÚÞÕ ãÔÐÛÕÝØÕ ÜÞÝâÐÖÐ" + +msgid "Setup.Replay$Jump&Play" +msgstr "Jump&Play" + +msgid "Setup.Replay$Play&Jump" +msgstr "Play&Jump" + +msgid "Setup.Replay$Pause at last mark" +msgstr "¿Ðã×Ð ÝÐ ßÞáÛÕÔÝÕÙ ÜÕâÚÕ" + +msgid "Setup.Replay$Reload marks" +msgstr "¿ÕàÕÓàãרâì ÜÕâÚØ" + +msgid "Setup.Replay$Skip Seconds" +msgstr "¿àÞßãáÚ áÕÚãÝÔ" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "¿àÞßãáÚ áÕÚãÝÔ ÜÕÔÛÕÝÝÞ" + +msgid "Setup.Replay$Length" +msgstr "´ÛØÝÐ" + +msgid "Setup.Replay$Length / Number" +msgstr "´ÛØÝÐ / ½ÞÜÕà" + +msgid "Setup.Replay$Number" +msgstr "½ÞÜÕà" + +msgid "Setup.Replay$DVD display mode" +msgstr "ÀÕÖØÜ ßÞÚÐ×Ð DVD" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "ßÞÚÐ× ÒÕÔãéØå ÝãÛÕÙ" + +msgid "Setup.Replay$never" +msgstr "ÝØÚÞÓÔÐ" + +msgid "Setup.Replay$on begin" +msgstr "Ò ÝÐçÐÛÕ" + +msgid "Setup.Replay$on end" +msgstr "² ÚÞÝæÕ" + +msgid "Setup.Replay$on begin and end" +msgstr "Ò ÝÐçÐÛÕ Ø Ò ÚÞÝæÕ" + +msgid "Setup.Replay$Tray open" +msgstr "¾âÚàëâì" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "¿àÕÔÕÛ áÚÞàÞáâØ DVD" + +msgid "Jump" +msgstr "¿àëÖÞÚ" + +msgid "Skip +60s" +msgstr "¿àÞßãáÚ +60s" + +msgid "Skip -60s" +msgstr "¿àÞßãáÚ -60s" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "¼ÞÝâÐÖÕà àÐÑÞâÐÕâ - ´ÞÑÐÒØâì Ò ÞçÕàÕÔì?" + +msgid "Rename$Up" +msgstr "²ÒÕàå" + +msgid "Rename$Down" +msgstr "²ÝØ×" + +msgid "Rename$Previous" +msgstr "¿àÕÔëÔãéØÙ" + +msgid "Rename$Next" +msgstr "ÁÛÕÔãîéØÙ" + +msgid "Please mount %s" +msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ %s" + +msgid "Please mount DVD %04d" +msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ DVD %04d" + +msgid "Please mount DVD %d" +msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÜÞÝâØàãÙâÕ DVD %d" + +msgid "Please wait. Checking DVD..." +msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÞÖÔØâÕ. ¿àÞÒÕàÚÐ DVD..." + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "¸ÝÔÕÚá äÐÙÛ ÝÕ ÝÐÙÔÕÝ. ÁÞ×ÔÐÝØÕ âàÕÑãÕâ ÒàÕÜÕÝØ. ÁÞ×ÔÐâì?" + +msgid "Please wait. Creating index-file..." +msgstr "¿ÞÖÐÛãÙáâÐ ßÞÔÞÖÔØâÕ. ÁÞ×ÔÐÝØÕ ØÝÔÕÚá äÐÙÛÐ..." + +msgid "Wrong DVD!" +msgstr "¾èØÑÚÐ DVD!" + +msgid "Permanent Timeshift" +msgstr "¿ÞáâÞïÝÝëÙ âÐÙÜèØäâ" + +msgid "Setup.LiveBuffer$Location" +msgstr "¼ÕáâÞÝÐåÞÖÔÕÝØï" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "ÖÕáâÚØÙ ÔØáÚ" + +msgid "Setup.LiveBuffer$memory" +msgstr "ßÐÜïâì" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "ÀÐ×ÜÕà ÑãäÕàÐ Ò ßÐÜïâØ (MB)" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "´ÞÑÐÒÛïâì ÖÕáâÚØÙ ÔØáÚ ÕáÛØ ÝÕÞÑåÞÔØÜÞ" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "ÅàÐÝÕÝØÕ ÑãäÕàÐ ßÐã×ë" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "ÀÐ×ÜÕà ÑãäÕàÐ ÝÐ ÖÕáâÚÞÜ ÔØáÚÕ (MB)" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "ÀÐ×ÜÕà ÑãäÕàÐ (MB)" + diff -ruNp vdr-1.6.0-2/po/sl_SI.po vdr-1.6.0-2-extensions/po/sl_SI.po --- vdr-1.6.0-2/po/sl_SI.po 2008-03-23 11:31:30.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/sl_SI.po 2009-04-09 20:48:26.000000000 +0200 @@ -999,3 +999,270 @@ msgstr "Pritisni katerokoli tipko za pre #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR se bo zaustavil v %s minutah" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/sv_SE.po vdr-1.6.0-2-extensions/po/sv_SE.po --- vdr-1.6.0-2/po/sv_SE.po 2008-03-23 11:31:30.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/sv_SE.po 2009-04-09 20:48:26.000000000 +0200 @@ -1001,3 +1001,270 @@ msgstr "Tryck valfri knapp för att återk #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR kommer att stängas ned om %s minuter" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/po/tr_TR.po vdr-1.6.0-2-extensions/po/tr_TR.po --- vdr-1.6.0-2/po/tr_TR.po 2008-03-23 11:31:30.000000000 +0100 +++ vdr-1.6.0-2-extensions/po/tr_TR.po 2009-04-09 20:48:26.000000000 +0200 @@ -998,3 +998,270 @@ msgstr "Yeniden baþlatmayý iptal etmek i #, c-format msgid "VDR will shut down in %s minutes" msgstr "VDR %s dakikada kapanacak" + +msgid "Channel locked by LNB!" +msgstr "" + +msgid "Childlock" +msgstr "" + +msgid "Path" +msgstr "" + +msgid "Timer commands" +msgstr "" + +msgid "Rename recording" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "Length" +msgstr "" + +msgid "Size" +msgstr "" + +msgid "Delete marks information?" +msgstr "" + +msgid "Delete resume information?" +msgstr "" + +msgid "DVD plugin is not installed!" +msgstr "" + +msgid "main dir alphabetically, subdirs flexible" +msgstr "" + +msgid "main dir by date, subdirs flexible" +msgstr "" + +msgid "all alphabetically" +msgstr "" + +msgid "all by date" +msgstr "" + +msgid "Sorting" +msgstr "" + +msgid "Setup.OSD$WarEagle icons" +msgstr "" + +msgid "Setup.OSD$Main menu command position" +msgstr "" + +msgid "Setup.OSD$Show valid input" +msgstr "" + +msgid "Setup.EPG$Show progress bar" +msgstr "" + +msgid "Setup.EPG$Period for double EPG search(min)" +msgstr "" + +msgid "Setup.EPG$Extern double Epg entry" +msgstr "" + +msgid "adjust" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "Setup.EPG$Mix intern and extern EPG" +msgstr "" + +msgid "Setup.EPG$Disable running VPS event" +msgstr "" + +msgid "Setup.DVB$Use AC3-Transfer Fix" +msgstr "" + +msgid "Setup.DVB$Channel Blocker" +msgstr "" + +msgid "Setup.DVB$Channel Blocker Filter Mode" +msgstr "" + +msgid "Setup.DVB$Use Sync Early Patch" +msgstr "" + +msgid "Setup.LNB$DVB device %d uses LNB No." +msgstr "" + +msgid "Setup.LNB$Log LNB usage" +msgstr "" + +msgid "Setup.Recording$Record Dolby Digital" +msgstr "" + +msgid "Setup.Recording$Video directory policy" +msgstr "" + +msgid "Setup.Recording$Number of video directories" +msgstr "" + +msgid "Setup.Recording$Video %d priority" +msgstr "" + +msgid "Setup.Recording$Video %d min. free MB" +msgstr "" + +msgid "Setup.Recording$Friendly filenames" +msgstr "" + +msgid "Setup.Recording$Max. recording size (GB)" +msgstr "" + +msgid "Setup.Recording$Hard Link Cutter" +msgstr "" + +msgid "Setup.Recording$Show date" +msgstr "" + +msgid "Setup.Recording$Show time" +msgstr "" + +msgid "Setup.Recording$Show length" +msgstr "" + +msgid "Setup.OSD$Main menu title" +msgstr "" + +msgid "Setup.Recording$Show end of timer" +msgstr "" + +msgid "Setup.Recording$Sort recordings by" +msgstr "" + +msgid "Setup.Recording$Sort directories before recordings" +msgstr "" + +msgid "Setup.Recording$Cutter auto delete" +msgstr "" + +msgid "Setup.Replay$Jump&Play" +msgstr "" + +msgid "Setup.Replay$Play&Jump" +msgstr "" + +msgid "Setup.Replay$Pause at last mark" +msgstr "" + +msgid "Setup.Replay$Reload marks" +msgstr "" + +msgid "Setup.Replay$Skip Seconds" +msgstr "" + +msgid "Setup.Replay$Skip Seconds Slow" +msgstr "" + +msgid "Setup.Replay$Length" +msgstr "" + +msgid "Setup.Replay$Length / Number" +msgstr "" + +msgid "Setup.Replay$Number" +msgstr "" + +msgid "Setup.Replay$DVD display mode" +msgstr "" + +msgid "Setup.Replay$DVD display leading zeros" +msgstr "" + +msgid "Setup.Replay$never" +msgstr "" + +msgid "Setup.Replay$on begin" +msgstr "" + +msgid "Setup.Replay$on end" +msgstr "" + +msgid "Setup.Replay$on begin and end" +msgstr "" + +msgid "Setup.Replay$Tray open" +msgstr "" + +msgid "Setup.Replay$Limit DVD to speed" +msgstr "" + +msgid "Jump" +msgstr "" + +msgid "Skip +60s" +msgstr "" + +msgid "Skip -60s" +msgstr "" + +msgid "Cutter already running - Add to cutting queue?" +msgstr "" + +msgid "Rename$Up" +msgstr "" + +msgid "Rename$Down" +msgstr "" + +msgid "Rename$Previous" +msgstr "" + +msgid "Rename$Next" +msgstr "" + +msgid "Please mount %s" +msgstr "" + +msgid "Please mount DVD %04d" +msgstr "" + +msgid "Please mount DVD %d" +msgstr "" + +msgid "Please wait. Checking DVD..." +msgstr "" + +msgid "No index-file found. Creating may take minutes. Create one?" +msgstr "" + +msgid "Please wait. Creating index-file..." +msgstr "" + +msgid "Wrong DVD!" +msgstr "" + +msgid "Permanent Timeshift" +msgstr "" + +msgid "Setup.LiveBuffer$Location" +msgstr "" + +msgid "Setup.LiveBuffer$harddisk" +msgstr "" + +msgid "Setup.LiveBuffer$memory" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size in memory (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Extend to harddisk if necessary" +msgstr "" + +msgid "Setup.LiveBuffer$Keep paused Buffer" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size on harddisk (MB)" +msgstr "" + +msgid "Setup.LiveBuffer$Buffer size (MB)" +msgstr "" diff -ruNp vdr-1.6.0-2/README.cmdsubmenu vdr-1.6.0-2-extensions/README.cmdsubmenu --- vdr-1.6.0-2/README.cmdsubmenu 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/README.cmdsubmenu 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,54 @@ +CmdSubmenu patch for VDR +------------------------ + +With this patch the commands and recording commands menus can be organised +hierarchically. To create a submenu entry, prefix the name by one ore more "-". + + +Standard: + +description_1 : cmd_1 +description_2 : cmd_2 + + +A submenu with two entries: + +Submenu title ... : echo "submenu" +-description_1 : cmd_1 +-description_2 : cmd_2 + +The dummy command in the title row is necessary. + + +* History + + 2003-10-08: Version 0.1 - Albu at vdrportal.de + http://vdrportal.de/board/thread.php?threadid=6319 + + 2003-10-09: Version 0.2 - Tobias Grimm + - Added Define CMD_SUBMENUS in Makefile + + 2004-05-28: Version 0.3 - Thomas Günther + - Fixed compilation with gcc-3.3.3 + - Added new virtual method AddConfig in cConfig + - Redefining of method Add in cListBase to virtual no longer necessary + - Improved code in menu.c + http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.3.diff + + 2004-12-20: Version 0.4 - Thomas Günther + - Solved conflict with jumpplay patch 0.6 + http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.4.diff + + 2006-04-22: Version 0.5 - Thomas Günther + - Added version define CMDSUBMENUVERSNUM + - Reformated to VDR style indentions + - Added description in README.cmdsubmenu + http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.5-1.3.47.diff + + 2006-04-23: Version 0.6 - Thomas Günther + - Fixed menus with more than one level + http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.6-1.3.47.diff + + 2006-05-15: Version 0.7 - Thomas Günther + - Fixed build with G++ 4.1 (extra qualification) + http://toms-cafe.de/vdr/download/vdr-cmdsubmenu-0.7-1.4.0.diff diff -ruNp vdr-1.6.0-2/README-HLCUTTER vdr-1.6.0-2-extensions/README-HLCUTTER --- vdr-1.6.0-2/README-HLCUTTER 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/README-HLCUTTER 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,117 @@ + + VDR-HLCUTTER README + + +Written by: Udo Richter +Available at: http://www.udo-richter.de/vdr/patches.html#hlcutter + http://www.udo-richter.de/vdr/patches.en.html#hlcutter +Contact: udo_richter@gmx.de + + + +About +----- + +The hard link cutter patch changes the recording editing algorithms of VDR to +use filesystem hard links to 'copy' recording files whenever possible to speed +up editing recordings noticeably. + +The patch has matured to be quite stable, at least I'm using it without issues. +Nevertheless the patch is still in development and should be used with caution. +The patch is EXPERIMENTAL for multiple /videoxx folders. The safety checks +should prevent data loss, but you should always carefully check the results. + +While editing a recording, the patch searches for any 00x.vdr files that dont +contain editing marks and would normally be copied 1:1 unmodified to the edited +recording. In this case the current target 00x.vdr file will be aborted, and +the cutter process attempts to duplicate the source file as a hard link, so +that both files share the same disk space. If this succeeds, the editing +process fast-forwards through the duplicated file and continues normally +beginning with the next source file. If hard linking fails, the cutter process +continues with plain old copying. (but does not take up the aborted last file.) + +After editing, the un-edited recording can be deleted as usual, the hard linked +copies will continue to exist as the only remaining copy. + +To be effective, the default 'Max. video file size (MB)' should be lowered. +The patch lowers the smallest possible file size to 1mb. Since VDR only +supports up to 255 files, this would limit the recording size to 255Mb or +10 minutes, in other words: This setting is insane! + +To make sure that the 255 file limit will not be reached, the patch also +introduces "Max. recording size (GB)" with a default of 100Gb (66 hours), and +increases the file size to 2000Mb early enough, so that 100Gb-recordings will +fit into the 255 files. + +Picking the right parameters can be tricky. The smaller the file size, the +faster the editing process works. However, with a small file size, long +recordings will fall back to 2000Mb files soon, that are slow on editing again. + +Here are some examples: + +Max file size: 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb +Max recording size: 1Mb 10Mb 20Mb 30Mb 40Mb 50Mb 100Mb + +Small files: 1-203 1-204 1-205 1-206 1-207 1-209 1-214 + GBytes: 0.2 2.0 4.0 6.0 8.1 10.2 20.9 + Hours: 0.13 1.3 2.65 4 5.4 6.8 13.9 + +Big (2000mb) files: 204-255 204-255 206-255 207-255 208-255 210-255 215-255 + GBytes: 101.5 99.6 97.7 95.7 93.8 89.8 80.1 + Hours: 67 66 65 63 62 60 53 + +A recording limit of 100Gb keeps plenty of reserve without blocking too much +file numbers. And with a file size of 30-40Mb, recordings of 4-5 hours fit into +small files completely. (depends on bit rate of course) + + + +The patch must be enabled in Setup-> Recordings-> Hard Link Cutter. When +disabled, the cutter process behaves identical to VDR's default cutter. + +There's a //#define HARDLINK_TEST_ONLY in the videodir.c file that enables a +test-mode that hard-links 00x.vdr_ files only, and continues the classic +editing. The resulting 00x.vdr and 00x.vdr_ files should be identical. If you +delete the un-edited recording, dont forget to delete the *.vdr_ files too, +they will now eat real disk space. + +Note: 'du' displays the disk space of hard links only on first appearance, and +usually you will see a noticeably smaller size on the edited recording. + + +History +------- +Version 0.2.0 + + New: Support for multiple /videoXX recording folders, using advanced searching + for matching file systems where a hard link can be created. + Also supports deep mounted file systems. + Fix: Do not fail if last mark is a cut-in. (Again.) + +Version 0.1.4 + New: Dynamic increase of file size before running out of xxx.vdr files + Fix: Last edit mark is not a cut-out + Fix: Write error if link-copied file is smaller than allowed file size + Fix: Broken index/marks if cut-in is at the start of a new file + Fix: Clear dangeling pointer to free'd cUnbufferedFile, + thx to Matthias Schwarzott + +Version 0.1.0 + Initial release + + + + +Future plans +------------ + +Since original and edited copy share disk space, free space is wrong if one of +them is moved to *.del. Free space should only count files with hard link +count = 1. This still goes wrong if all copies get deleted. + + +For more safety, the hard-linked files may be made read-only, as modifications +to one copy will affect the other copy too. (except deleting, of course) + + +SetBrokenLink may get lost on rare cases, this needs some more thoughts.Index: vdr-1.5.9/README.jumpplay diff -ruNp vdr-1.6.0-2/README.jumpplay vdr-1.6.0-2-extensions/README.jumpplay --- vdr-1.6.0-2/README.jumpplay 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/README.jumpplay 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,92 @@ +JumpPlay patch for VDR +---------------------- + +This patch changes the replay behaviour for recordings that contain editing +marks. It allows to immediately continue the replay after jumping forward to +the next mark, and to automatically jump over the commercial break to the next +"start" mark, if an "end" mark is reached. + +The features of this patch can be turned on or off with parameters in the replay +setup. See MANUAL for description of this parameters: "Jump&Play", "Play&Jump", +"Pause at last mark" and "Reload marks". + + +* History + + 2003-07-04: jumpandrun.diff - the Noad + Jump&Play + + 2003-12-06: Version 0.0 - Torsten Kunkel + Play&Jump (only if progressbar is visible) + Setup parameters Jump&Play and Play&Jump in the replay setup + + 2004-01-20: Version 0.1 - Thomas Günther + Jump&Play: + - fixed speed after jump + - fixed removing of marks + Play&Jump: + - jump only on "end" marks + + 2004-01-27: Version 0.2 - Thomas Günther + Jump&Play: + - fixed double jump + Play&Jump: + - fixed mark detection: fuzzy detection (until 3 seconds after mark) + - jump without progressbar + - mode "progressbar only" for old behaviour + + 2004-01-31: Version 0.3 - Thomas Günther + Jump&Play: + - fixed display frames + Play&Jump: + - fixed end of playing at last mark + + 2004-07-11: Version 0.4 - Thomas Günther + Jump&Play: + - don't play after jump to end + Play&Jump: + - don't prevent jumping after hide or show + Less conflicts with other patches (Elchi/AutoPID) + + 2004-08-21: Version 0.5 - Thomas Günther + Play&Jump: + - exact jumps, replay like edited recording (no fuzzy mark detection) + - jump to first mark if replay starts at the beginning + - check jump marks with '8' key + - mode "progressbar only" removed + Description in README.jumpplay + + 2004-12-28: Version 0.6 - Thomas Günther + Adapted noad extensions (from the Noad ) to + jumpplay-0.5: + - cyclic reloading of marks found by noad online-scan + - don't stop after the last mark in case of live-recordings + New setup parameter "Load marks interval (s)" + Updated description in README.jumpplay + + 2006-04-14: Version 0.7 - Thomas Günther + Fixed jump to first mark (crashed with plugin extrecmenu-0.9) + Added version define JUMPPLAYVERSNUM + Added placeholders for Czech language texts + Cleaned up i18n entries (support only VDR >= 1.3.29) + Improved description of i18n placeholders - hoping for real language texts + + 2006-05-12: Version 0.8 - Thomas Günther + Fixed segfault in dvbplayer thread while the replaycontrol thread is + reloading the marks (thanks to horchi at vdrportal.de for reporting this - + see http://vdrportal.de/board/thread.php?postid=450463#post450463): + New class cMarksReload checks the timestamp of marks.vdr in 10 seconds + intervals, so the marks in the threads dvbplayer and replaycontrol can be + reloaded independently + Changed setup parameter "Load marks interval (s)" to "Reload marks" + Updated description in README.jumpplay + + 2006-05-28: Version 0.9 - Thomas Günther + New setup parameter "Pause at last mark" + Updated description in README.jumpplay + Moved parameters description to MANUAL + + 2009-03-31: Version 1.0 - Thomas Günther + Play&Jump: + - set resume position to 0 if replay stops at the first mark + Added French language texts (thanks to Michaël Nival) diff -ruNp vdr-1.6.0-2/README.MainMenuHooks vdr-1.6.0-2-extensions/README.MainMenuHooks --- vdr-1.6.0-2/README.MainMenuHooks 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/README.MainMenuHooks 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,55 @@ +This is a "patch" for the Video Disk Recorder (VDR). + +* Authors: +Tobias Grimm +Martin Prochnow +Frank Schmirler +Christian Wieninger + +* Description: +This patch allows plugins to replace the VDR mainmenus "Schedule", +"Channels", "Timers" and "Recordings" by a different implementation. + +The patch is based on a suggestion of Christian Wieninger back in 2006 +(http://www.linuxtv.org/pipermail/vdr/2006-March/008234.html). It is +meant to be an interim solution for VDR 1.4 until (maybe) VDR 1.5 +introduces an official API for this purpose. + +* Installation +Change into the VDR source directory, then issue + patch -p1 < path/to/MainMenuHooks-v1_0.patch +and recompile. + +* Notes for plugin authors +The following code sample shows the required plugin code for replacing +the original Schedule menu: + +bool cMyPlugin::Service(const char *Id, void *Data) +{ + cOsdMenu **menu = (cOsdMenu**) Data; + if (MySetup.replaceSchedule && + strcmp(Id, "MainMenuHooksPatch-v1.0::osSchedule") == 0) { + if (menu) + *menu = (cOsdMenu*) MainMenuAction(); + return true; + } + return false; +} + +A plugin can replace more than one menu at a time. Simply replace the +call to MainMenuAction() in the sample above by appropriate code. + +Note that a plugin *should* offer a setup option which allows the user +to enable or disable the replacement. "Disabled" would be a reasonable +default setting. By testing for define MAINMENUHOOKSVERSNUM, a plugin +can leave the setup option out at compiletime. + +In case there is an internal problem when trying to open the replacement +menu, it is safe to return true even though Data is NULL. However an +OSD message should indicate the problem to the user. + +Feel free to ship this patch along with your plugin. However if you +think you need to modify the patch, we'd encourage you to contact the +authors first or at least use a service id which differs in more than +just the version number. + diff -ruNp vdr-1.6.0-2/README.sortrec vdr-1.6.0-2-extensions/README.sortrec --- vdr-1.6.0-2/README.sortrec 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/README.sortrec 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,48 @@ +Sort Recordings patch for VDR +----------------------------- +Copyright (C) 2005 Frank99 @vdr-portal.de +Copyright (C) 2006-2008 Christoph Haubrich + +Released under the same license as VDR itself, for details see vdr.c or +http://firefly.vdr-developer.org/patches + +This patch changes the sort behaviour of the recordings menu. It is based +on the patch available here: http://www.vdr-portal.de/board/thread.php?threadid=36031 +Required for this patch is the liemikuutio-patch for VDR which can be found here: +http://www.saunalahti.fi/%7Erahrenbe/vdr/patches/ + +There are four sorting modes available after this patch is applied: + +mode behaviour for behaviour for + main directory sub directories +-------------------------------------------------------------------------- + 0 alphabetically if special character(*) is found alphabetically, + else by date + 1 by date if special character(*) is found alphabetically, + else by date + 2 alphabetically alphabetically + 3 by date by date + +(*) if the name of a subdirectory ends with one of ".-$" (dot, hyphen, dollar sign) + it is sorted alphabetically in sort mode 0 and 1 + +Sort mode 0 with none of the special characters at the end of any subdir +corresponds to the default sorting mode of the original VDR. + +The sorting mode can be switched through in the recording menu with the '0' key +(0->1->2->3->0->...), a default for startup can be set in the setup->recordings menu. + +Additionally the sort order (ascending/descending) can be toggled by the '9' key +(which is always set to ascending after a restart) + +If you like the to see subdirectories before recordings you can select to put +directories first in the setup->recordings menu. + +If you would like the sorting to ignore a leading '%' (as normally displayed before +cutted recordings) you can achive this by setting the environment variable LC_COLLATE +properly (eg. LC_COLLATE=de_DE@euo in runvdr for germany). + +History: +2006-08-13 v3, sortrec release for VDR 1.4.1 and liemikuutio 1.8 +2007-01-28 v3a, moved #ifdef from optimized-rename-patch to sortrec +2008-03-29 v3b, removed ASCII-170 and ASCII-183 to make sortrec Utf8-ready diff -ruNp vdr-1.6.0-2/README.timer-info vdr-1.6.0-2-extensions/README.timer-info --- vdr-1.6.0-2/README.timer-info 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/README.timer-info 2009-04-09 20:48:26.000000000 +0200 @@ -0,0 +1,53 @@ ++------------------------------------------------------------------------------+ +| Info about the timer-info-patch by Brougs78 | +| brougs78@gmx.net / home.pages.at/brougs78 | ++------------------------------------------------------------------------------+ + + +README timer-info: +------------------ + +Features: + - Shows info, if it is possible to record an event in the timer menu of vdr. + For calculations the free space incl. the deleted recordings is used, + considering an average consumtion of 25.75 MB/min (also used by vdr itself). + The first column in the timer-list shows: + ( + ) recording will be most probably possible (enough space) + (+/-) recording may be possible + ( - ) recording will most probably fail (to less space) + The calculations also consider repeating timers. + - It is possible to deactivate the patch in the OSD-menu of VDR. + + +HISTORY timer-info: +------------------- + +25.11.2004: v0.1 + - Initial release + +11.01.2005: v0.1b + - Bugfixes for vdr-1.3.18 + - In the menu the free recording-time no longer includes the space of the + deleted recordings, because this slowed the vdr down to much. + +08.07.2005: v0.1c + - Made the patch configurable + +29.01.2006: v0.2 - Thomas Günther + - Rewritten great parts for vdr-1.3.38+ + http://toms-cafe.de/vdr/download/vdr-timer-info-0.2-1.3.38+.diff + +05.02.2006: v0.3 - Thomas Günther + - Fixed refresh of timer menu in cMenuTimers::OnOff + - Fixed check of repeating timers + - Syslog debug messages can be enabled with Define DEBUG_TIMER_INFO + http://toms-cafe.de/vdr/download/vdr-timer-info-0.3-1.3.38+.diff + +03.03.2006: v0.4 - Thomas Günther + - Adapted to vdr-1.3.44 + - Removed setup parameter "Show timer-info" + http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.44.diff + +03.03.2006: v0.5 - Tobias Grimm + - Adapted to vdr-1.3.45 + http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.45.diff diff -ruNp vdr-1.6.0-2/recorder.c vdr-1.6.0-2-extensions/recorder.c --- vdr-1.6.0-2/recorder.c 2007-02-24 17:36:24.000000000 +0100 +++ vdr-1.6.0-2-extensions/recorder.c 2009-04-09 20:48:27.000000000 +0200 @@ -11,6 +11,9 @@ #include #include #include +#ifdef USE_TTXTSUBS +#include +#endif /* TTXTSUBS */ #include "shutdown.h" #define RECORDERBUFSIZE MEGABYTE(5) @@ -26,6 +29,9 @@ class cFileWriter : public cThread { private: +#ifdef USE_TTXTSUBS + cTtxtSubsRecorderBase *ttxtSubsRecorder; +#endif /* TTXTSUBS */ cRemux *remux; cFileName *fileName; cIndexFile *index; @@ -38,13 +44,24 @@ private: protected: virtual void Action(void); public: +#ifdef USE_TTXTSUBS + cFileWriter(const char *FileName, cRemux *Remux, cTtxtSubsRecorderBase *tsr); +#else cFileWriter(const char *FileName, cRemux *Remux); +#endif /* TTXTSUBS */ virtual ~cFileWriter(); }; +#ifdef USE_TTXTSUBS +cFileWriter::cFileWriter(const char *FileName, cRemux *Remux, cTtxtSubsRecorderBase *tsr) +#else cFileWriter::cFileWriter(const char *FileName, cRemux *Remux) +#endif /* TTXTSUBS */ :cThread("file writer") { +#ifdef USE_TTXTSUBS + ttxtSubsRecorder = tsr; +#endif /* TTXTSUBS */ fileName = NULL; remux = Remux; index = NULL; @@ -67,6 +84,10 @@ cFileWriter::~cFileWriter() Cancel(3); delete index; delete fileName; +#ifdef USE_TTXTSUBS + if (ttxtSubsRecorder) + delete ttxtSubsRecorder; +#endif /* TTXTSUBS */ } bool cFileWriter::RunningLowOnDiskSpace(void) @@ -85,7 +106,11 @@ bool cFileWriter::RunningLowOnDiskSpace( bool cFileWriter::NextFile(void) { if (recordFile && pictureType == I_FRAME) { // every file shall start with an I_FRAME +#ifndef USE_HARDLINKCUTTER if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) { +#else + if (fileSize > fileName->MaxFileSize() || RunningLowOnDiskSpace()) { +#endif /* HARDLINKCUTTER */ recordFile = fileName->NextFile(); fileSize = 0; } @@ -111,6 +136,18 @@ void cFileWriter::Action(void) } fileSize += Count; remux->Del(Count); +#ifdef USE_TTXTSUBS + // not sure if the pictureType test is needed, but it seems we can get + // incomplete pes packets from remux if we are not getting pictures? + if (ttxtSubsRecorder && pictureType != NO_PICTURE) { + uint8_t *subsp; + size_t len; + if (ttxtSubsRecorder->GetPacket(&subsp, &len)) { + recordFile->Write(subsp, len); + fileSize += len; + } + } +#endif /* TTXTSUBS */ } else break; @@ -126,8 +163,23 @@ void cFileWriter::Action(void) // --- cRecorder ------------------------------------------------------------- +#if defined (USE_LIVEBUFFER) || defined (USE_TTXTSUBS) +cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids +#ifdef USE_TTXTSUBS + ,cTtxtSubsRecorderBase *tsr +#endif /* TTXTSUBS */ +#ifdef USE_LIVEBUFFER + ,cLiveBuffer *LiveBuffer +#endif /* LIVEBUFFER */ + ) +#else cRecorder::cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids) +#endif /* LIVEBUFFER || TTXTSUBS */ +#ifdef USE_DOLBYINREC +:cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyInRecordings ? DPids : NULL, SPids) +#else :cReceiver(ChannelID, Priority, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids) +#endif /* DOLBYINREC */ ,cThread("recording") { // Make sure the disk is up and running: @@ -136,8 +188,22 @@ cRecorder::cRecorder(const char *FileNam ringBuffer = new cRingBufferLinear(RECORDERBUFSIZE, TS_SIZE * 2, true, "Recorder"); ringBuffer->SetTimeouts(0, 100); +#ifdef USE_DOLBYINREC + remux = new cRemux(VPid, APids, Setup.UseDolbyInRecordings ? DPids : NULL, SPids, true); +#else remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, true); +#endif /* DOLBYINREC */ +#ifdef USE_LIVEBUFFER + fileName = strdup(FileName); + writer = NULL; + liveBuffer = LiveBuffer; + if (!LiveBuffer) +#endif /* LIVEBUFFER */ +#ifdef USE_TTXTSUBS + writer = new cFileWriter(FileName, remux, tsr); +#else writer = new cFileWriter(FileName, remux); +#endif /* TTXTSUBS */ } cRecorder::~cRecorder() @@ -146,11 +212,17 @@ cRecorder::~cRecorder() delete writer; delete remux; delete ringBuffer; +#ifdef USE_LIVEBUFFER + free(fileName); +#endif /* LIVEBUFFER */ } void cRecorder::Activate(bool On) { if (On) { +#ifdef USE_LIVEBUFFER + if (writer) +#endif /* LIVEBUFFER */ writer->Start(); Start(); } @@ -174,6 +246,29 @@ void cRecorder::Action(void) uchar *b = ringBuffer->Get(r); if (b) { int Count = remux->Put(b, r); +#ifdef USE_LIVEBUFFER + if (!writer && liveBuffer) { + int c; + uchar pictureType; + uchar *p = remux->Get(c, &pictureType); + if (pictureType == I_FRAME && p && p[0]==0x00 && p[1]==0x00 && p[2]==0x01 && (p[7] & 0x80) && p[3]>=0xC0 && p[3]<=0xEF) { + int64_t pts = (int64_t) (p[ 9] & 0x0E) << 29 ; + pts |= (int64_t) p[ 10] << 22 ; + pts |= (int64_t) (p[ 11] & 0xFE) << 14 ; + pts |= (int64_t) p[ 12] << 7 ; + pts |= (int64_t) (p[ 13] & 0xFE) >> 1 ; + liveBuffer->CreateIndexFile(fileName, pts); +#ifdef USE_TTXTSUBS + writer = new cFileWriter(fileName, remux, ttxtSubsRecorder); +#else + writer = new cFileWriter(fileName, remux); +#endif /* TTXTSUBS */ + writer->Start(); + } + else + remux->Del(c); + } +#endif /* LIVEBUFFER */ if (Count) ringBuffer->Del(Count); else diff -ruNp vdr-1.6.0-2/recorder.h vdr-1.6.0-2-extensions/recorder.h --- vdr-1.6.0-2/recorder.h 2007-01-05 11:44:05.000000000 +0100 +++ vdr-1.6.0-2-extensions/recorder.h 2009-04-09 20:48:27.000000000 +0200 @@ -10,11 +10,17 @@ #ifndef __RECORDER_H #define __RECORDER_H +#ifdef USE_LIVEBUFFER +#include "livebuffer.h" +#endif /* LIVEBUFFER */ #include "receiver.h" #include "recording.h" #include "remux.h" #include "ringbuffer.h" #include "thread.h" +#ifdef USE_TTXTSUBS +#include "vdrttxtsubshooks.h" +#endif /* TTXTSUBS */ class cFileWriter; @@ -23,12 +29,30 @@ private: cRingBufferLinear *ringBuffer; cRemux *remux; cFileWriter *writer; +#ifdef USE_LIVEBUFFER + char *fileName; + cLiveBuffer *liveBuffer; +#ifdef USE_TTXTSUBS + cTtxtSubsRecorderBase *ttxtSubsRecorder; +#endif /* TTXTSUBS */ +#endif /* LIVEBUFFER */ protected: virtual void Activate(bool On); virtual void Receive(uchar *Data, int Length); virtual void Action(void); public: +#if defined (USE_LIVEBUFFER) || defined (USE_TTXTSUBS) + cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids +#ifdef USE_TTXTSUBS + ,cTtxtSubsRecorderBase *tsr +#endif /* TTXTSUBS */ +#ifdef USE_LIVEBUFFER + ,cLiveBuffer *LiveBuffer = NULL +#endif /* LIVEBUFFER */ + ); +#else cRecorder(const char *FileName, tChannelID ChannelID, int Priority, int VPid, const int *APids, const int *DPids, const int *SPids); +#endif /* LIVEBUFFER || TTXTSUBS */ // Creates a new recorder for the channel with the given ChannelID and // the given Priority that will record the given PIDs into the file FileName. virtual ~cRecorder(); diff -ruNp vdr-1.6.0-2/recording.c vdr-1.6.0-2-extensions/recording.c --- vdr-1.6.0-2/recording.c 2008-02-24 11:28:53.000000000 +0100 +++ vdr-1.6.0-2-extensions/recording.c 2009-04-09 20:48:27.000000000 +0200 @@ -8,6 +8,9 @@ */ #include "recording.h" +#ifdef USE_WAREAGLEICON +#include "iconpatch.h" +#endif /* WAREAGLEICON */ #include #include #include @@ -23,6 +26,17 @@ #include "skins.h" #include "tools.h" #include "videodir.h" +#ifdef USE_STREAMDEVEXT +#include "status.h" +#endif /* STREAMDEVEXT */ + +#if defined (USE_DVDCHAPJUMP) && defined (USE_DVDARCHIVE) +#include +/* libdvdread stuff */ +#include +#include +#include +#endif /* DVDCHAPJUMP & DVDARCHIVE */ #define SUMMARYFALLBACK @@ -46,6 +60,12 @@ #endif #define INFOFILESUFFIX "/info.vdr" #define MARKSFILESUFFIX "/marks.vdr" +#ifdef USE_LIEMIEXT +#define INDEXFILESUFFIX "/index.vdr" +#endif /* LIEMIEXT */ +#ifdef USE_DVDARCHIVE +#define DVDARCHIVEFILENAME "/dvd.vdr" +#endif /* DVDARCHIVE */ #define MINDISKSPACE 1024 // MB @@ -62,6 +82,13 @@ #define MAX_LINK_LEVEL 6 bool VfatFileSystem = false; +#ifdef USE_LIEMIEXT +bool DirOrderState = false; +#endif /* LIEMIEXT */ + +#ifdef USE_DVLFRIENDLYFNAMES +char *MakeFriendlyFilename(char **buf); +#endif /* DVLFRIENDLYFNAMES */ cRecordings DeletedRecordings(true); @@ -491,9 +518,24 @@ cRecording::cRecording(cTimer *Timer, co { resume = RESUME_NOT_INITIALIZED; titleBuffer = NULL; +#ifdef USE_SORTRECORDS + for (int i = 0; i < MAXSORTMODES; i++) { + sortBuffer[i] = NULL; + lastDirsFirst[i] = -1; + } +#else sortBuffer = NULL; +#endif /* SORTRECORDS */ fileName = NULL; name = NULL; +#ifdef USE_DVDARCHIVE + dvdname = NULL; + dvdtrack = NULL; + dvdchapters = NULL; + isArchived = false; + isOnlyOnDvd = false; + dvdtype = DVD_TYPE_UNKNOWN; +#endif /* DVDARCHIVE */ fileSizeMB = -1; // unknown deleted = 0; // set up the actual name: @@ -524,6 +566,11 @@ cRecording::cRecording(cTimer *Timer, co break; } if (Timer->IsSingleEvent()) { +#ifdef USE_DVLFRIENDLYFNAMES + if (Setup.UseFriendlyFNames == 1) + Timer -> SetFile(MakeFriendlyFilename(&name)); + else +#endif /* DVLFRIENDLYFNAMES */ Timer->SetFile(name); // this was an instant recording, so let's set the actual data Timers.SetModified(); } @@ -534,6 +581,10 @@ cRecording::cRecording(cTimer *Timer, co name = strdup(cString::sprintf("%s~%s", Timer->File(), Subtitle)); // substitute characters that would cause problems in file names: strreplace(name, '\n', ' '); +#ifdef USE_DVLFRIENDLYFNAMES + if (Setup.UseFriendlyFNames == 1) + MakeFriendlyFilename(&name); +#endif /* DVLFRIENDLYFNAMES */ start = Timer->StartTime(); priority = Timer->Priority(); lifetime = Timer->Lifetime(); @@ -548,12 +599,27 @@ cRecording::cRecording(const char *FileN fileSizeMB = -1; // unknown deleted = 0; titleBuffer = NULL; +#ifdef USE_SORTRECORDS + for (int i = 0; i < MAXSORTMODES; i++) { + sortBuffer[i] = NULL; + lastDirsFirst[i] = -1; + } +#else sortBuffer = NULL; +#endif /* SORTRECORDS */ fileName = strdup(FileName); FileName += strlen(VideoDirectory) + 1; char *p = strrchr(FileName, '/'); name = NULL; +#ifdef USE_DVDARCHIVE + dvdname = NULL; + dvdtrack = NULL; + dvdchapters = NULL; + isArchived = false; + isOnlyOnDvd = false; + dvdtype = DVD_TYPE_NOT_READ; +#endif /* DVDARCHIVE */ info = new cRecordingInfo; if (p) { time_t now = time(NULL); @@ -633,15 +699,34 @@ cRecording::cRecording(const char *FileN LOG_ERROR_STR(*SummaryFileName); } #endif +#ifdef USE_DVDARCHIVE + if (CheckFileExistence("dvd.vdr")) { + GetDvdName(fileName); + isArchived = true; + if (!CheckFileExistence("001.vdr")) + isOnlyOnDvd = true; + } +#endif /* DVDARCHIVE */ } } cRecording::~cRecording() { free(titleBuffer); +#ifdef USE_SORTRECORDS + for (int i = 0; i < MAXSORTMODES; i++) { + free(sortBuffer[i]); + } +#else free(sortBuffer); +#endif /* SORTRECORDS */ free(fileName); free(name); +#ifdef USE_DVDARCHIVE + free(dvdname); + free(dvdtrack); + free(dvdchapters); +#endif /* DVDARCHIVE */ delete info; } @@ -661,21 +746,46 @@ char *cRecording::StripEpisodeName(char t++; } if (s1 && s2) +#ifdef USE_SORTRECORDS + if (Setup.RecordingsSortDirsFirst) + *s1 = 'b'; + + if ((Setup.RecordingsSortMode <= 1 && s1 != s && !strchr(".-$ª·", *(s1 - 1))) || + (Setup.RecordingsSortMode == 1 && s1 == s) || + (Setup.RecordingsSortMode == 3)) +#endif /* SORTRECORDS */ memmove(s1 + 1, s2, t - s2 + 1); return s; } char *cRecording::SortName(void) const { +#ifdef USE_SORTRECORDS + if (!sortBuffer[Setup.RecordingsSortMode] || + lastDirsFirst[Setup.RecordingsSortMode] != Setup.RecordingsSortDirsFirst) { + free(sortBuffer[Setup.RecordingsSortMode]); + lastDirsFirst[Setup.RecordingsSortMode] = Setup.RecordingsSortDirsFirst; + char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory))); +#else if (!sortBuffer) { char *s = StripEpisodeName(strdup(FileName() + strlen(VideoDirectory) + 1)); +#endif /* SORTRECORDS */ strreplace(s, '/', 'a'); // some locales ignore '/' when sorting int l = strxfrm(NULL, s, 0) + 1; +#ifdef USE_SORTRECORDS + sortBuffer[Setup.RecordingsSortMode] = MALLOC(char, l); + strxfrm(sortBuffer[Setup.RecordingsSortMode], s, l); +#else sortBuffer = MALLOC(char, l); strxfrm(sortBuffer, s, l); +#endif /* SORTRECORDS */ free(s); } +#ifdef USE_SORTRECORDS + return sortBuffer[Setup.RecordingsSortMode]; +#else return sortBuffer; +#endif /* SORTRECORDS */ } int cRecording::GetResume(void) const @@ -690,7 +800,15 @@ int cRecording::GetResume(void) const int cRecording::Compare(const cListObject &ListObject) const { cRecording *r = (cRecording *)&ListObject; +#ifdef USE_SORTRECORDS + return Recordings.GetSortOrder() * strcasecmp(SortName(), r->SortName()); +#else +#ifdef USE_LIEMIEXT + if (DirOrderState) + return strcasecmp(FileName(), r->FileName()); +#endif /* LIEMIEXT */ return strcasecmp(SortName(), r->SortName()); +#endif /* USE_SORTRECORDS */ } const char *cRecording::FileName(void) const @@ -705,9 +823,359 @@ const char *cRecording::FileName(void) c return fileName; } +#ifdef USE_DVDARCHIVE +bool cRecording::CheckFileExistence(const char* FileNameToTest, const bool useVideoDir) const +{ + if (!useVideoDir || (useVideoDir && FileName())) { + cString filename = cString::sprintf("%s%s%s", useVideoDir ? FileName() : "", + useVideoDir ? "/" : "", + FileNameToTest); + struct stat statBuf; + if (lstat(filename, &statBuf) == -1) return false; + return S_ISREG(statBuf.st_mode) || S_ISLNK(statBuf.st_mode); + } + return false; +} + +bool cRecording::GetDvdName(const char* Directory) const +{ + char* filename = (char*)alloca(strlen(Directory) + strlen(DVDARCHIVEFILENAME) + 1); + if (filename) { + strcpy(filename, Directory); + char *end = filename + strlen(filename); + strcpy(end, DVDARCHIVEFILENAME); + FILE* file; + if ((file = fopen(filename, "r"))) { + cReadLine ReadLine; + char* buffer = (char*)alloca(BUFSIZ); + if (buffer) { + buffer = ReadLine.Read(file); + if (buffer) + ((cRecording*)this)->dvdname = strdup(buffer); + else + ((cRecording*)this)->dvdname = NULL; + + buffer = ReadLine.Read(file); + if (buffer) { + ((cRecording*)this)->dvdtrack = strdup(buffer); + if (atoi(buffer) == 0) + ((cRecording*)this)->dvdtype = DVD_VIDEO_TYPE; + else + ((cRecording*)this)->dvdtype = DVD_VIDEO_ARCHIVE_TYPE; + } + else { + ((cRecording*)this)->dvdtrack = NULL; + ((cRecording*)this)->dvdtype = DVD_ARCHIVE_TYPE; + } + + fclose(file); + return true; + } + } + } + return false; +} + +bool cRecording::GetDvdChaptersFromDvd(int title) const +{ +#ifdef USE_DVDCHAPJUMP + cString buf; + + dvd_reader_t *dvd; + ifo_handle_t *ifo_file; + tt_srpt_t *tt_srpt; + ifo_handle_t *vts_file; + pgc_t *cur_pgc; + + dvd = DVDOpen(DVD_DEVICE); + if (!dvd) { + esyslog("DVD-ARCHIVE: Couldn't open DVD device %s!", DVD_DEVICE); + return false; + } + + /* open title manager */ + ifo_file = ifoOpen(dvd,0); + if (!ifo_file) { + esyslog("DVD-ARCHIVE: Can't open VMG info."); + DVDClose(dvd); + return false; + } + + /* read total_title */ + tt_srpt = ifo_file->tt_srpt; + + /* get total chapters */ + int title_set_nr = tt_srpt->title[title-1].title_set_nr; + int total_chap = tt_srpt->title[title-1].nr_of_ptts; + int local_title_id = tt_srpt->title[title-1].vts_ttn - 1; + + /* access title set file */ + vts_file = ifoOpen(dvd, title_set_nr); + if (!vts_file) { + esyslog("DVD-ARCHIVE: Can't open info file for title set %d!",title_set_nr); + DVDClose(dvd); + return false; + } + + /* find program chain and check programs + all chapters should be in the same prog chain and + should be numbered from 1 to + */ + { + vts_ptt_srpt_t *vts_ptt_srpt = vts_file->vts_ptt_srpt; + int pgc_nr = vts_ptt_srpt->title[local_title_id].ptt[0].pgcn; + int pg = vts_ptt_srpt->title[local_title_id].ptt[0].pgn; + int p; + + assert(pg==1); + for (p=1; ptitle[local_title_id].ptt[p].pgcn; + assert(pgc_nr == this_pgc); + next_pg = vts_ptt_srpt->title[local_title_id].ptt[p].pgn; + assert(pg+1 == next_pg); + pg = next_pg; + } + + /* fetch program chain */ + cur_pgc = vts_file->vts_pgcit->pgci_srp[pgc_nr-1].pgc; + assert(cur_pgc->nr_of_programs == total_chap); + } + + /* --- main cell loop --- */ + { + pgc_program_map_t *chap_cell; + cell_playback_t *cell_pb; + int c; + int chap; + + /* total cells in chain */ + int total_cell = cur_pgc->nr_of_cells; + + /* get info */ + chap_cell = cur_pgc->program_map; + cell_pb = cur_pgc->cell_playback; + + /* loop through all cells */ + chap = -1; + int position = 0; + for (c=0; cplayback_time; + + int framerate = time->frame_u>>6; + assert(framerate == 1 || framerate == 3); + int frames_per_sec = (framerate == 1) ? 25 : 30; + + /* upper 4 bits are first digit, down 4 bits are second digit */ + int hour = (time->hour>>4) * 10 + (time->hour&15); + int minute = (time->minute>>4) * 10 + (time->minute&15); + int second = (time->second>>4) * 10 + (time->second&15); + /* upper 4 bits are first digit, down 4 bits are second digit */ + int frame = (time->frame_u>>4&3) * 10 + (time->frame_u&15); + + int frames = ((hour * 3600) + (minute * 60) + second) * frames_per_sec + frame; + + /* this cell is the begin of a new chapter! */ + if (chap_cell[chap+1] == c+1) { + cString oldbuf = cString::sprintf("%s", *buf); + buf = cString::sprintf("%s%d%s", *oldbuf, position, ((chap+2) < total_chap) ? "," : ""); + chap++; + } + + /* cell_mode: 0=normal, 1=first of angle, 2=in angle, 3=last of angle */ + cell_mode = cell_pb->block_mode; + if ((cell_mode==0) || (cell_mode==1)) { + /* only account for normal or begin of angle cells */ + position += frames; + mode = "counted"; + } + else + mode = "skipped"; + + cell_pb++; + } + } + + ifoClose(ifo_file); + ifoClose(vts_file); + DVDClose(dvd); + + ((cRecording*)this)->dvdchapters = strdup(buf); + + return true; +#else + return false; +#endif /* DVDCHAPJUMP */ +} + +const char *cRecording::GetDvdChapters(void) const +{ + // Read chapters from dvd + if (dvdtype == DVD_VIDEO_ARCHIVE_TYPE) { + if (dvdtrack) { + if (!GetDvdChaptersFromDvd(atoi(dvdtrack))) + ((cRecording*)this)->dvdchapters = NULL; + else + isyslog("DVD-ARCHIVE: Using following positions for chapter jumping: %s", dvdchapters); + return dvdchapters; + } + } + return NULL; +} + +int cRecording::MountDvd(void) const +{ + cString cmd; + if (Setup.DvdSpeedLimit > 0) { + cmd = cString::sprintf("speedcontrol -x %d %s", Setup.DvdSpeedLimit, DVD_DEVICE); + SystemExec(cmd); + } + + cString msg; + if (atoi(dvdname) == 0) + msg = cString::sprintf(tr("Please mount %s"), dvdname); + else { + if (Setup.DvdDisplayZeros) + msg = cString::sprintf(tr("Please mount DVD %04d"), atoi(dvdname)); + else + msg = cString::sprintf(tr("Please mount DVD %d"), atoi(dvdname)); + } + + bool rep = true; + while (rep) { + if (Setup.DvdTrayMode==1 || Setup.DvdTrayMode==3) + cmd = cString::sprintf("umount %s; eject %s", DVD_DEVICE, DVD_DEVICE); + else + cmd = cString::sprintf("umount %s", DVD_DEVICE); + SystemExec(cmd); + + if (Interface->Confirm(msg, 300)) { + Skins.Message(mtStatus, tr("Please wait. Checking DVD...")); + Skins.Flush(); + cmd = cString::sprintf("eject -t %s; mkdir -p %s; mount -o ro -t %s %s %s", + DVD_DEVICE, DVD_MOUNT_PATH, + (dvdtrack ? "udf" : "iso9660"), + DVD_DEVICE, DVD_MOUNT_PATH); + SystemExec(cmd); + + bool correctDvd = true; + + char *olddvdname, *olddvdtrack; + int olddvdtype; + olddvdname = dvdname; + olddvdtrack = dvdtrack; + olddvdtype = dvdtype; + if (GetDvdName(DVD_MOUNT_PATH)) { + if (atoi(dvdname) != atoi(olddvdname)) correctDvd = false; + } + ((cRecording*)this)->dvdname = olddvdname; + ((cRecording*)this)->dvdtrack = olddvdtrack; + ((cRecording*)this)->dvdtype = olddvdtype; + + if (correctDvd) { + if (dvdtrack == NULL) { + // Archived DVD in VDR format + char fn[BUFSIZ]; + strcpy(fn, FileName()); + char *p = strrchr(fn, '/'); + cmd = cString::sprintf("find '%s' -name '%s'", DVD_MOUNT_PATH, p+1); + } + else { + // Either archived DVD in DVD-Video format or DVD-Video which + // should be played with the DVD plugin + cmd = cString::sprintf("find '%s' -iname 'VIDEO_TS'", DVD_MOUNT_PATH); + } + + cReadLine pipe; + FILE* file; + char *dirname = NULL; + if ((file = popen(cmd, "r")) != (FILE *)NULL) { + if ((dirname = pipe.Read(file)) != NULL) { + pclose(file); + if (dvdtrack != NULL && atoi(dvdtrack) == 0) { + // It is a valid Video-DVD and DVD plugin can be started + return MOUNT_DVD_LAUNCH_DVD_PLUGIN; + } + else { + // It is a valid Archive-DVD or an archived Video-DVD + // and the links can now be established + cString srcFn; + int n = 1; + + do { + if (dvdtrack == NULL) + srcFn = cString::sprintf("%s/%03d.vdr", dirname, n); + else + srcFn = cString::sprintf("%s/VTS_%02d_%d.VOB", dirname, atoi(dvdtrack), n); + + if (!access(srcFn, R_OK)) { + cmd = cString::sprintf("ln -sf '%s' '%s/%03d.vdr'", *srcFn, FileName(), n); + SystemExec(cmd); + isyslog("DVD-ARCHIVE: Linking %s/%03d.vdr -> %s", FileName(), n, *srcFn); + } + else + break; + } while ( ++n < 999); + + if (!CheckFileExistence("index.vdr")) { + if (dvdtrack == NULL) + srcFn = cString::sprintf("%s/index.vdr", dirname); + else + srcFn = cString::sprintf("%s/index_%02d.vdr", dirname, atoi(dvdtrack)); + + if (!CheckFileExistence(srcFn, false)) { + msg = cString::sprintf(tr("No index-file found. Creating may take minutes. Create one?")); + if (Interface->Confirm(msg, 300)) { + Skins.Message(mtStatus, tr("Please wait. Creating index-file...")); + cmd = cString::sprintf("speedcontrol -x 999 %s; cd %s && genindex &", DVD_DEVICE, FileName()); + SystemExec(cmd); + return MOUNT_DVD_ABORT; + } + } + else { + cmd = cString::sprintf("ln -sf '%s' '%s/index.vdr'", *srcFn, FileName()); + SystemExec(cmd); + isyslog("DVD-ARCHIVE: Linking %s/index.vdr -> %s", FileName(), *srcFn); + } + } + return MOUNT_DVD_REPLAY; + } + } + else { + Skins.Message(mtError, tr("Wrong DVD!"), 3); + Skins.Flush(); + } + } + pclose(file); + } + else { + Skins.Message(mtError, tr("Wrong DVD!"), 3); + Skins.Flush(); + } + } + else { + rep = false; + } + } + return MOUNT_DVD_ABORT; +} + +#endif /* DVDARCHIVE */ +#ifdef USE_LIEMIEXT +const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level, bool Original) const +#else const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level) const +#endif /* LIEMIEXT */ { +#ifdef USE_WAREAGLEICON + const char *New = NewIndicator && IsNew() ? Setup.WarEagleIcons ? IsLangUtf8() ? ICON_NEW_UTF8 : ICON_NEW : "*" : " "; +#else char New = NewIndicator && IsNew() ? '*' : ' '; +#endif /* WAREAGLEICON */ free(titleBuffer); titleBuffer = NULL; if (Level < 0 || Level == HierarchyLevels()) { @@ -718,7 +1186,14 @@ const char *cRecording::Title(char Delim s++; else s = name; +#ifdef USE_LIEMIEXT + if (Original) { +#endif /* LIEMIEXT */ +#ifdef USE_WAREAGLEICON + titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%s%c%s", +#else titleBuffer = strdup(cString::sprintf("%02d.%02d.%02d%c%02d:%02d%c%c%s", +#endif /* WAREAGLEICON */ t->tm_mday, t->tm_mon + 1, t->tm_year % 100, @@ -728,6 +1203,92 @@ const char *cRecording::Title(char Delim New, Delimiter, s)); +#ifdef USE_LIEMIEXT + } + else { + cString RecLength("---"); + if (Setup.ShowRecLength && FileName()) { + cString filename = cString::sprintf("%s%s", FileName(), INDEXFILESUFFIX); + if (*filename) { + if (access(filename, R_OK) == 0) { + struct stat buf; + if (stat(filename, &buf) == 0) { + struct tIndex { int offset; uchar type; uchar number; short reserved; }; + int delta = buf.st_size % sizeof(tIndex); + if (delta) { + delta = sizeof(tIndex) - delta; + esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, *filename); + } + RecLength = cString::sprintf("%ld'", (buf.st_size + delta) / sizeof(tIndex) / SecondsToFrames(60)); + } + } + } + } +#endif /* LIEMIEXT */ +#ifdef USE_DVDARCHIVE +#ifdef USE_WAREAGLEICON + if (isArchived && !isOnlyOnDvd) New = Setup.WarEagleIcons ? IsLangUtf8() ? ICON_DVD_UTF8 : ICON_DVD : "~"; +#else + if (isArchived && !isOnlyOnDvd) New = '~'; +#endif /* WAREAGLEICON */ + + if (isOnlyOnDvd && Setup.DvdDisplayMode >= 1) { + char oldLength[21]; + + if (strrchr(RecLength, '\'')) + sprintf(oldLength,"%s", *RecLength); + else + oldLength[0] = 0; + + if (dvdname) { + if (atoi(dvdname) != 0) { + cString tmp; + if (Setup.DvdDisplayZeros) + tmp = cString::sprintf("%04d", atoi(dvdname)); + else { + int num = atoi(dvdname); + bool displaySpace = !(Setup.DvdDisplayMode == 1 && oldLength[0] != 0); + // ugly hack to have 2 spaces instead of one 0 for each place + tmp = cString::sprintf("%s%s%s%d", displaySpace && (num < 1000) ? " " : "", + displaySpace && (num < 100) ? " " : "", + displaySpace && (num < 10) ? " " : "", + num); + } + ((cRecording*)this)->dvdname = strdup(tmp); + } + } + + RecLength = strdup(cString::sprintf("%s%s%s%s", (Setup.ShowRecLength && (Setup.DvdDisplayMode == 1) && (oldLength[0] != 0)) ? oldLength : "", + (dvdname && isArchived && isOnlyOnDvd && Setup.ShowRecLength && (Setup.DvdDisplayMode == 1) && (oldLength[0] != 0)) ? " / " : "", + (dvdname && isArchived && isOnlyOnDvd) ? dvdname : "", + (dvdname && isArchived && isOnlyOnDvd) ? " " : "" + )); + } +#endif /* DVDARCHIVE */ +#ifdef USE_LIEMIEXT + cString RecDate = cString::sprintf("%02d.%02d.%02d", t->tm_mday, t->tm_mon + 1, t->tm_year % 100); + cString RecTime = cString::sprintf("%02d:%02d", t->tm_hour, t->tm_min); + cString RecDelimiter = cString::sprintf("%c", Delimiter); +#ifdef USE_WAREAGLEICON + titleBuffer = strdup(cString::sprintf("%s%s%s%s%s%s%s%s", +#else + titleBuffer = strdup(cString::sprintf("%s%s%s%c%s%s%s%s", +#endif /* WAREAGLEICON */ + (Setup.ShowRecDate ? *RecDate : ""), + (Setup.ShowRecDate && Setup.ShowRecTime ? *RecDelimiter : ""), + (Setup.ShowRecTime ? *RecTime : ""), + New, + (Setup.ShowRecTime || Setup.ShowRecDate ? *RecDelimiter : ""), +#ifdef USE_DVDARCHIVE + (((Setup.ShowRecLength + Setup.DvdDisplayMode) > 0) ? *RecLength : ""), + (((Setup.ShowRecLength + Setup.DvdDisplayMode) > 0) ? *RecDelimiter : ""), +#else + (Setup.ShowRecLength ? *RecLength : ""), + (Setup.ShowRecLength ? *RecDelimiter : ""), +#endif /* DVDARCHIVE */ + s)); + } +#endif /* LIEMIEXT */ // let's not display a trailing '~': if (!NewIndicator) stripspace(titleBuffer); @@ -756,6 +1317,17 @@ const char *cRecording::Title(char Delim return titleBuffer; } +#ifdef USE_CUTTIME +void cRecording::SetStartTime(time_t Start) +{ + start = Start; + if (fileName) { + free(fileName); + fileName = NULL; + } +} +#endif /* CUTTIME */ + const char *cRecording::PrefixFileName(char Prefix) { cString p = PrefixVideoFileName(FileName(), Prefix); @@ -809,10 +1381,20 @@ bool cRecording::Delete(void) // the new name already exists, so let's remove that one first: isyslog("removing recording '%s'", NewName); RemoveVideoFile(NewName); +#ifdef USE_STREAMDEVEXT + cStatus::MsgRecordingChange(this, scDel); +#endif /* STREAMDEVEXT */ } isyslog("deleting recording '%s'", FileName()); +#ifdef USE_STREAMDEVEXT + if (access(FileName(), F_OK) == 0) { + result = RenameVideoFile(FileName(), NewName); + cStatus::MsgRecordingChange(this, scDel); + } +#else if (access(FileName(), F_OK) == 0) result = RenameVideoFile(FileName(), NewName); +#endif /* STREAMDEVEXT */ else { isyslog("recording '%s' vanished", FileName()); result = true; // well, we were going to delete it, anyway @@ -830,7 +1412,13 @@ bool cRecording::Remove(void) return false; } isyslog("removing recording %s", FileName()); +#ifdef USE_STREAMDEVEXT + bool ret = RemoveVideoFile(FileName()); + cStatus::MsgRecordingChange(this, scDel); + return ret; +#else return RemoveVideoFile(FileName()); +#endif /* STREAMDEVEXT */ } bool cRecording::Undelete(void) @@ -847,8 +1435,15 @@ bool cRecording::Undelete(void) } else { isyslog("undeleting recording '%s'", FileName()); +#ifdef USE_STREAMDEVEXT + if (access(FileName(), F_OK) == 0) { + result = RenameVideoFile(FileName(), NewName); + cStatus::MsgRecordingChange(this, scAdd); + } +#else if (access(FileName(), F_OK) == 0) result = RenameVideoFile(FileName(), NewName); +#endif /* STREAMDEVEXT */ else { isyslog("deleted recording '%s' vanished", FileName()); result = false; @@ -864,6 +1459,53 @@ void cRecording::ResetResume(void) const resume = RESUME_NOT_INITIALIZED; } +#ifdef USE_LIEMIEXT +bool cRecording::Rename(const char *newName, int *newPriority, int *newLifetime) +{ + bool result = false; + struct tm tm_r; + struct tm *t = localtime_r(&start, &tm_r); + char *localNewName = ExchangeChars(strdup(newName), true); + char *newFileName = strdup(cString::sprintf(NAMEFORMAT, VideoDirectory, localNewName, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, *newPriority, *newLifetime)); + free(localNewName); + if (strcmp(FileName(), newFileName)) { + if (access(newFileName, F_OK) == 0) { + isyslog("recording %s already exists", newFileName); + } + else { + isyslog("renaming recording %s to %s", FileName(), newFileName); + result = MakeDirs(newFileName, true); + if (result) + result = RenameVideoFile(FileName(), newFileName); + if (result) { + priority = *newPriority; + lifetime = *newLifetime; + free(fileName); + fileName = strdup(newFileName); + free(name); + name = strdup(newName); +#ifdef USE_SORTRECORDS + for (int i = 0; i < MAXSORTMODES; i++) { + free(sortBuffer[i]); + sortBuffer[i] = NULL; + } +#else + free(sortBuffer); + sortBuffer = NULL; +#endif /* SORTRECORDS */ + free(titleBuffer); + titleBuffer = NULL; + } +#ifdef USE_STREAMDEVEXT + cStatus::MsgRecordingChange(this, scMod); +#endif /* STREAMDEVEXT */ + } + } + free(newFileName); + return result; +} +#endif /* LIEMIEXT */ + // --- cRecordings ----------------------------------------------------------- cRecordings Recordings; @@ -876,6 +1518,9 @@ cRecordings::cRecordings(bool Deleted) deleted = Deleted; lastUpdate = 0; state = 0; +#ifdef USE_SORTRECORDS + SortOrder = 1; +#endif /* SORTRECORDS */ } cRecordings::~cRecordings() @@ -1154,14 +1799,70 @@ cMark *cMarks::GetNext(int Position) return NULL; } +#ifdef USE_JUMPPLAY +// --- cMarksReload ---------------------------------------------------------- + +#define MARKS_RELOAD_MS 10000 + +time_t cMarksReload::lastsavetime = 0; + +cMarksReload::cMarksReload(const char *RecordingFileName) +:recDir(RecordingFileName) +{ + struct stat sbuf; + if (Load(recDir) && stat(FileName(), &sbuf) == 0) + lastmodtime = sbuf.st_mtime; + else + lastmodtime = 0; + nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); +} + +bool cMarksReload::Reload(void) +{ + // Check the timestamp of marks.vdr in 10 seconds intervals + // Independent but synchronized reloading of marks in two threads + if ((Setup.ReloadMarks && nextreload.TimedOut()) || lastsavetime > lastmodtime) { + nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); + struct stat sbuf; + if (stat(FileName(), &sbuf) == 0 && sbuf.st_mtime != lastmodtime) { + lastmodtime = sbuf.st_mtime; + if (Load(recDir)) + return true; + } + } + return false; +} + +bool cMarksReload::Save(void) +{ + bool ok = cMarks::Save(); + struct stat sbuf; + if (ok && stat(FileName(), &sbuf) == 0) + lastsavetime = lastmodtime = sbuf.st_mtime; + return ok; +} +#endif /* JUMPPLAY */ + // --- cRecordingUserCommand ------------------------------------------------- const char *cRecordingUserCommand::command = NULL; +#ifdef USE_DVLRECSCRIPTADDON +void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName, char *chanName) +#else void cRecordingUserCommand::InvokeCommand(const char *State, const char *RecordingFileName) +#endif /* DVLRECSCRIPTADDON */ { if (command) { +#ifdef USE_DVLRECSCRIPTADDON + cString cmd; + if (chanName != NULL) + cmd = cString::sprintf("%s %s \"%s\" \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$"), chanName); + else + cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); +#else cString cmd = cString::sprintf("%s %s \"%s\"", command, State, *strescape(RecordingFileName, "\\\"$")); +#endif /* DVLRECSCRIPTADDON */ isyslog("executing '%s'", *cmd); SystemExec(cmd); } @@ -1172,7 +1873,9 @@ void cRecordingUserCommand::InvokeComman //XXX+ somewhere else??? // --- cIndexFile ------------------------------------------------------------ +#ifndef USE_LIEMIEXT #define INDEXFILESUFFIX "/index.vdr" +#endif /* LIEMIEXT */ // The number of frames to stay off the end in case of time shift: #define INDEXSAFETYLIMIT 150 // frames @@ -1431,6 +2134,48 @@ cFileName::cFileName(const char *FileNam cFileName::~cFileName() { Close(); +#ifdef USE_DVDARCHIVE + + char fn[BUFSIZ]; + strcpy(fn, fileName); + + char *p; + if((p = strrchr(fn, '/'))) { + p[0] = 0; + } + + cString cmd = cString::sprintf("find \"%s\" -type l -lname \"%s/*\"", fn, DVD_MOUNT_PATH); + + bool isOnDvd = false; + + cReadLine pipe; + FILE* file; + char* filename; + if ((file = popen(cmd, "r")) != (FILE *)NULL) { + while ((filename = pipe.Read(file)) != NULL) { + isOnDvd = true; + unlink(filename); + isyslog("DVD-ARCHIVE: Deleting %s", filename); + } + pclose(file); + } + + if (isOnDvd) { + if (Setup.DvdTrayMode==2 || Setup.DvdTrayMode==3) + cmd = cString::sprintf("umount %s; eject %s", DVD_DEVICE, DVD_DEVICE); + else + cmd = cString::sprintf("umount %s", DVD_DEVICE); + + SystemExec(cmd); + + if (Setup.DvdSpeedLimit > 0) { + cmd = cString::sprintf("speedcontrol -x 999 %s", DVD_DEVICE); + SystemExec(cmd); + } + } + +#endif /* DVDARCHIVE */ + free(fileName); } @@ -1508,6 +2253,18 @@ cUnbufferedFile *cFileName::SetOffset(in return NULL; } +#ifdef USE_HARDLINKCUTTER +int cFileName::MaxFileSize() { + const int smallFiles = (255 * MAXVIDEOFILESIZE - 1024 * Setup.MaxRecordingSize) + / max(MAXVIDEOFILESIZE - Setup.MaxVideoFileSize, 1); + + if (fileNumber <= smallFiles) + return MEGABYTE(Setup.MaxVideoFileSize); + + return MEGABYTE(MAXVIDEOFILESIZE); +} +#endif /* HARDLINKCUTTER */ + cUnbufferedFile *cFileName::NextFile(void) { return SetOffset(fileNumber + 1); @@ -1555,3 +2312,113 @@ int ReadFrame(cUnbufferedFile *f, uchar LOG_ERROR; return r; } + +#ifdef USE_DVLFRIENDLYFNAMES +char *MakeFriendlyFilename(char **buf) +{ + char *b, *x, *y; + + if (buf == NULL || *buf == NULL) + return(NULL); + + b = (char *)malloc(strlen(*buf) * 2); + x = *buf; + y = b; + + while (*x != 0) { + switch (*x) { + case 'Ä': + *y = 'A'; + y++; + *y = 'e'; + y++; x++; + break; + + case 'ä': + *y = 'a'; + y++; + *y = 'e'; + y++; x++; + break; + + case 'Ö': + *y = 'O'; + y++; + *y = 'e'; + y++; x++; + break; + + case 'ö': + *y = 'o'; + y++; + *y = 'e'; + y++; x++; + break; + + case 'Ü': + *y = 'U'; + y++; + *y = 'e'; + y++; x++; + break; + + case 'ü': + *y = 'u'; + y++; + *y = 'e'; + y++; x++; + break; + + case 'ß': + *y = 's'; + y++; + *y = 's'; + y++; x++; + break; + + // chars to replace + case ':': + case ';': + case '?': + case ' ': + case '\t': + *y = '_'; + y++; x++; + break; + + // chars to simply strip + case '\"': + case '*': + case '{': + case '}': + case '[': + case ']': + case '=': + case '<': + case '>': + case '#': + case '`': + case '|': + case '\\': + case '\n': + case '\r': + x++; + break; + + default: + *y = *x; + y++; x++; + break; + } + } + *y = 0; + + x = strdup(b); + free(b); + + free(*buf); + *buf = x; + + return(*buf); +} +#endif /* DVLFRIENDLYFNAMES */ diff -ruNp vdr-1.6.0-2/recording.h vdr-1.6.0-2-extensions/recording.h --- vdr-1.6.0-2/recording.h 2007-10-14 12:11:34.000000000 +0200 +++ vdr-1.6.0-2-extensions/recording.h 2009-04-09 20:48:27.000000000 +0200 @@ -19,6 +19,9 @@ #include "tools.h" extern bool VfatFileSystem; +#ifdef USE_LIEMIEXT +extern bool DirOrderState; +#endif /* LIEMIEXT */ void RemoveDeletedRecordings(void); void AssertFreeDiskSpace(int Priority = 0, bool Force = false); @@ -52,9 +55,15 @@ private: public: ~cRecordingInfo(); tChannelID ChannelID(void) const { return channelID; } +#ifdef USE_STREAMDEVEXT + const cEvent *GetEvent(void) const { return event; } +#endif /* STREAMDEVEXT */ const char *ChannelName(void) const { return channelName; } const char *Title(void) const { return event->Title(); } const char *ShortText(void) const { return event->ShortText(); } +#ifdef USE_GRAPHTFT + tEventID EventID(void) const { return event->EventID(); } +#endif /* GRAPHTFT */ const char *Description(void) const { return event->Description(); } const cComponents *Components(void) const { return event->Components(); } const char *Aux(void) const { return aux; } @@ -62,16 +71,50 @@ public: bool Write(FILE *f, const char *Prefix = "") const; }; +#ifdef USE_SORTRECORDS +#define SORTRECORDINGSVERSNUM 3 +#define MAXSORTMODES 4 +#endif /* SORTRECORDS */ + +#ifdef USE_DVDARCHIVE +#define MOUNT_DVD_ABORT 0 +#define MOUNT_DVD_REPLAY 1 +#define MOUNT_DVD_LAUNCH_DVD_PLUGIN 2 +#define DVD_DEVICE "/dev/cdrom" +#define DVD_MOUNT_PATH "/tmp/vdr.dvd" + +#define DVD_TYPE_UNKNOWN -1 +#define DVD_TYPE_NOT_READ 0 +#define DVD_VIDEO_TYPE 1 +#define DVD_ARCHIVE_TYPE 2 +#define DVD_VIDEO_ARCHIVE_TYPE 3 +#endif /* DVDARCHIVE */ + class cRecording : public cListObject { friend class cRecordings; private: mutable int resume; mutable char *titleBuffer; + +#ifdef USE_SORTRECORDS + mutable char *sortBuffer[MAXSORTMODES]; + mutable char lastDirsFirst[MAXSORTMODES]; +#else mutable char *sortBuffer; +#endif /* SORTRECORDS */ mutable char *fileName; mutable char *name; mutable int fileSizeMB; cRecordingInfo *info; +#ifdef USE_DVDARCHIVE + char *dvdname; + char *dvdtrack; + char *dvdchapters; + bool isArchived; + bool isOnlyOnDvd; + int dvdtype; + bool GetDvdChaptersFromDvd(int title) const; +#endif /* DVDARCHIVE */ cRecording(const cRecording&); // can't copy cRecording cRecording &operator=(const cRecording &); // can't assign cRecording static char *StripEpisodeName(char *s); @@ -88,8 +131,23 @@ public: virtual int Compare(const cListObject &ListObject) const; const char *Name(void) const { return name; } const char *FileName(void) const; +#ifdef USE_DVDARCHIVE + bool CheckFileExistence(const char* FileNameToTest, const bool useVideoDir = true) const; + bool GetDvdName(const char* Directory) const; + bool IsOnlyOnDvd(void) const { return isOnlyOnDvd; } + int MountDvd(void) const; + int GetDvdType(void) const { return dvdtype; } + const char *GetDvdChapters(void) const ; +#endif /* DVDARCHIVE */ +#ifdef USE_LIEMIEXT + const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1, bool Original = true) const; +#else const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const; +#endif /* LIEMIEXT */ const cRecordingInfo *Info(void) const { return info; } +#ifdef USE_CUTTIME + void SetStartTime(time_t Start); +#endif /* CUTTIME */ const char *PrefixFileName(char Prefix); int HierarchyLevels(void) const; void ResetResume(void) const; @@ -106,6 +164,11 @@ public: // Changes the file name so that it will be visible in the "Recordings" menu again and // not processed by cRemoveDeletedRecordingsThread. // Returns false in case of error +#ifdef USE_LIEMIEXT + bool Rename(const char *newName, int *newPriority, int *newLifetime); + // Changes the file name + // Returns false in case of error +#endif /* LIEMIEXT */ }; class cRecordings : public cList, public cThread { @@ -114,6 +177,9 @@ private: bool deleted; time_t lastUpdate; int state; +#ifdef USE_SORTRECORDS + int SortOrder; +#endif /* SORTRECORDS */ const char *UpdateFileName(void); void Refresh(bool Foreground = false); void ScanVideoDir(const char *DirName, bool Foreground = false, int LinkLevel = 0); @@ -144,6 +210,10 @@ public: void AddByName(const char *FileName, bool TriggerUpdate = true); void DelByName(const char *FileName); int TotalFileSizeMB(void); ///< Only for deleted recordings! +#ifdef USE_SORTRECORDS + void ToggleSortOrder(void) { SortOrder *= -1; } + const int GetSortOrder(void) { return SortOrder; } +#endif /* SORTRECORDS */ }; extern cRecordings Recordings; @@ -170,6 +240,20 @@ public: cMark *GetNext(int Position); }; +#ifdef USE_JUMPPLAY +class cMarksReload : public cMarks { +private: + cString recDir; + cTimeMs nextreload; + time_t lastmodtime; + static time_t lastsavetime; +public: + cMarksReload(const char *RecordingFileName); + bool Reload(void); + bool Save(void); + }; +#endif /* JUMPPLAY */ + #define RUC_BEFORERECORDING "before" #define RUC_AFTERRECORDING "after" #define RUC_EDITEDRECORDING "edited" @@ -178,8 +262,15 @@ class cRecordingUserCommand { private: static const char *command; public: +#ifdef USE_DELTIMESHIFTREC + static const char *GetCommand(void) { return command; } +#endif /* DELTIMESHIFTREC */ static void SetCommand(const char *Command) { command = Command; } +#ifdef USE_DVLRECSCRIPTADDON + static void InvokeCommand(const char *State, const char *RecordingFileName, char *chanName = NULL); +#else static void InvokeCommand(const char *State, const char *RecordingFileName); +#endif /* DVLRECSCRIPTADDON */ }; //XXX+ @@ -195,7 +286,19 @@ public: // may be slightly higher because we stop recording only before the next // 'I' frame, to have a complete Group Of Pictures): #define MAXVIDEOFILESIZE 2000 // MB +#ifndef USE_HARDLINKCUTTER #define MINVIDEOFILESIZE 100 // MB +#else +#define MINVIDEOFILESIZE 1 // MB + +#define MINRECORDINGSIZE 25 // GB +#define MAXRECORDINGSIZE 500 // GB +#define DEFAULTRECORDINGSIZE 100 // GB +// Dynamic recording size: +// Keep recording file size at Setup.MaxVideoFileSize for as long as possible, +// but switch to MAXVIDEOFILESIZE early enough, so that Setup.MaxRecordingSize +// will be reached, before recording to file 255.vdr +#endif /* HARDLINKCUTTER */ class cIndexFile { private: @@ -207,6 +310,9 @@ private: cResumeFile resumeFile; cMutex mutex; bool CatchUp(int Index = -1); +#ifdef USE_DVDARCHIVE + bool isOnDVD; +#endif /* DVDARCHIVE */ public: cIndexFile(const char *FileName, bool Record); ~cIndexFile(); @@ -236,6 +342,10 @@ public: cUnbufferedFile *Open(void); void Close(void); cUnbufferedFile *SetOffset(int Number, int Offset = 0); +#ifdef USE_HARDLINKCUTTER + int MaxFileSize(); + // Dynamic file size for this file +#endif /* HARDLINKCUTTER */ cUnbufferedFile *NextFile(void); }; diff -ruNp vdr-1.6.0-2/remux.c vdr-1.6.0-2-extensions/remux.c --- vdr-1.6.0-2/remux.c 2007-11-25 14:56:03.000000000 +0100 +++ vdr-1.6.0-2-extensions/remux.c 2009-04-09 20:48:27.000000000 +0200 @@ -1829,8 +1829,15 @@ void cTS2PES::ts_to_pes(const uint8_t *B if (Buf[1] & TS_ERROR) tsErrors++; +#ifdef USE_DVBSETUP + if (!(Buf[3] & (ADAPT_FIELD | PAY_LOAD))) { + dsyslog("TS packet discarded due to invalid adaption_field_control"); + return; + } +#else if (!(Buf[3] & (ADAPT_FIELD | PAY_LOAD))) return; // discard TS packet with adaption_field_control set to '00'. +#endif /* DVBSETUP */ if ((Buf[3] & PAY_LOAD) && ((Buf[3] ^ ccCounter) & CONT_CNT_MASK)) { // This should check duplicates and packets which do not increase the counter. @@ -1842,6 +1849,9 @@ void cTS2PES::ts_to_pes(const uint8_t *B // These are the errors I used to get with Nova-T when antenna // was not positioned correcly (not transport errors). //tvr //dsyslog("TS continuity error (%d)", ccCounter); +#ifdef USE_DVBSETUP + dsyslog("TS continuity error (%d)", ccCounter); +#endif /* DVBSETUP */ } ccCounter = Buf[3] & CONT_CNT_MASK; } @@ -1867,6 +1877,10 @@ void cTS2PES::ts_to_pes(const uint8_t *B if (Buf[3] & PAY_LOAD) instant_repack(Buf + 4 + off, TS_SIZE - 4 - off); +#ifdef USE_DVBSETUP + else if (off + 4 < 188) + dsyslog("adaption_field zu short or PAY_LOAD not set"); +#endif /* DVBSETUP */ } // --- cRingBufferLinearPes -------------------------------------------------- @@ -1896,12 +1910,19 @@ int cRingBufferLinearPes::DataReady(cons #define RESULTBUFFERSIZE KILOBYTE(256) +#ifdef USE_SYNCEARLY +cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure, bool SyncEarly) +#else cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure) +#endif /* SYNCEARLY */ { exitOnFailure = ExitOnFailure; noVideo = VPid == 0 || VPid == 1 || VPid == 0x1FFF; numUPTerrors = 0; synced = false; +#ifdef USE_SYNCEARLY + syncEarly = SyncEarly; +#endif /* SYNCEARLY */ skipped = 0; numTracks = 0; resultSkipped = 0; @@ -2105,12 +2126,26 @@ uchar *cRemux::Get(int &Count, uchar *Pi } } else if (!synced) { +#ifdef USE_SYNCEARLY + if (pt == I_FRAME || syncEarly) { +#else if (pt == I_FRAME) { +#endif /* SYNCEARLY */ if (PictureType) *PictureType = pt; resultSkipped = i; // will drop everything before this position +#ifdef USE_SYNCEARLY + if (!syncEarly) +#endif /* SYNCEARLY */ SetBrokenLink(data + i, l); synced = true; +#ifdef USE_SYNCEARLY + if (syncEarly) { + if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink() + SetBrokenLink(data + i, l); + else fprintf(stderr, "video: synced early\n"); + } +#endif /* SYNCEARLY */ } } else if (Count) @@ -2123,12 +2158,21 @@ uchar *cRemux::Get(int &Count, uchar *Pi l = GetPacketLength(data, resultCount, i); if (l < 0) return resultData; +#ifdef USE_SYNCEARLY + if (noVideo || !synced && syncEarly) { + if (!synced) { + if (PictureType && noVideo) +#else if (noVideo) { if (!synced) { if (PictureType) +#endif /* SYNCEARLY */ *PictureType = I_FRAME; resultSkipped = i; // will drop everything before this position synced = true; +#ifdef USE_SYNCEARLY + if (!noVideo && syncEarly) fprintf(stderr, "audio: synced early\n"); +#endif /* SYNCEARLY */ } else if (Count) return resultData; diff -ruNp vdr-1.6.0-2/remux.h vdr-1.6.0-2-extensions/remux.h --- vdr-1.6.0-2/remux.h 2008-09-11 13:29:43.000000000 +0200 +++ vdr-1.6.0-2-extensions/remux.h 2009-04-09 20:48:27.000000000 +0200 @@ -38,6 +38,9 @@ private: bool noVideo; int numUPTerrors; bool synced; +#ifdef USE_SYNCEARLY + bool syncEarly; +#endif /* SYNCEARLY */ int skipped; cTS2PES *ts2pes[MAXTRACKS]; int numTracks; @@ -45,12 +48,18 @@ private: int resultSkipped; int GetPid(const uchar *Data); public: +#ifdef USE_SYNCEARLY + cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false, bool SyncEarly = false); +#else cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false); +#endif /* SYNCEARLY */ ///< Creates a new remuxer for the given PIDs. VPid is the video PID, while ///< APids, DPids and SPids are pointers to zero terminated lists of audio, ///< dolby and subtitle PIDs (the pointers may be NULL if there is no such ///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency ///< exit" in case of problems with the data stream. + ///< If USE_SYNCEARLY is activated: SyncEarly causes cRemux to sync as soon + ///< as a video or audio frame is seen. ~cRemux(); void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); } ///< By default cRemux assumes that Put() and Get() are called from different diff -ruNp vdr-1.6.0-2/skinclassic.c vdr-1.6.0-2-extensions/skinclassic.c --- vdr-1.6.0-2/skinclassic.c 2008-02-23 11:31:58.000000000 +0100 +++ vdr-1.6.0-2-extensions/skinclassic.c 2009-04-09 20:48:27.000000000 +0200 @@ -314,8 +314,52 @@ void cSkinClassicDisplayMenu::SetItem(co for (int i = 0; i < MaxTabs; i++) { const char *s = GetTabbedText(Text, i); if (s) { +#ifdef USE_LIEMIEXT + bool isprogressbar = false; + int now = 0, total = 0; + // check if progress bar: "[||||||| ]" + if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) { + const char *p = s + 1; + // update status + isprogressbar = true; + for (; *p != ']'; ++p) { + // check if progressbar characters + if (*p == ' ' || *p == '|') { + // update counters + ++total; + if (*p == '|') + ++now; + } + else { + // wrong character detected; not a progressbar + isprogressbar = false; + break; + } + } + } + int xt = x0 + Tab(i); + if (Setup.ShowProgressBar && isprogressbar) { + // define x coordinates of progressbar + int px0 = xt; + int px1 = (Tab(i + 1)?Tab(i+1):x1) - 5; + int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1); + // define y coordinates of progressbar + int py0 = y + 4; + int py1 = y + lineHeight - 4; + // draw background + osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i+1):x1) - 1, y + lineHeight - 1, ColorBg); + // draw progressbar + osd->DrawRectangle(px0, py0, px, py1, ColorFg); + osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg); + osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg); + osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg); + } + else + osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt); +#else int xt = x0 + Tab(i); osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt); +#endif /* LIEMIEXT */ } if (!Tab(i + 1)) break; diff -ruNp vdr-1.6.0-2/skinsttng.c vdr-1.6.0-2-extensions/skinsttng.c --- vdr-1.6.0-2/skinsttng.c 2008-02-23 11:23:44.000000000 +0100 +++ vdr-1.6.0-2-extensions/skinsttng.c 2009-04-09 20:48:27.000000000 +0200 @@ -558,8 +558,52 @@ void cSkinSTTNGDisplayMenu::SetItem(cons for (int i = 0; i < MaxTabs; i++) { const char *s = GetTabbedText(Text, i); if (s) { +#ifdef USE_LIEMIEXT + bool isprogressbar = false; + int now = 0, total = 0; + // check if progress bar: "[||||||| ]" + if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) { + const char *p = s + 1; + // update status + isprogressbar = true; + for (; *p != ']'; ++p) { + // check if progressbar characters + if (*p == ' ' || *p == '|') { + // update counters + ++total; + if (*p == '|') + ++now; + } + else { + // wrong character detected; not a progressbar + isprogressbar = false; + break; + } + } + } + int xt = x3 + 5 + Tab(i); + if (Setup.ShowProgressBar && isprogressbar) { + // define x coordinates of progressbar + int px0 = xt; + int px1 = x3 + (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1; + int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1); + // define y coordinates of progressbar + int py0 = y + 4; + int py1 = y + lineHeight - 4; + // draw background + osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1, y + lineHeight - 1, ColorBg); + // draw progressbar + osd->DrawRectangle(px0, py0, px, py1, ColorFg); + osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg); + osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg); + osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg); + } + else + osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt); +#else int xt = x3 + 5 + Tab(i); osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt); +#endif /* LIEMIEXT */ } if (!Tab(i + 1)) break; @@ -602,6 +646,21 @@ void cSkinSTTNGDisplayMenu::SetEvent(con y += ts.Height(); } y += font->Height(); +#ifdef USE_PARENTALRATING + if (!isempty(Event->GetParentalRatingString())) { + const cFont *font = cFont::GetFont(fontSml); + ts.Set(osd, xl, y, x4 - xl, y4 - y, Event->GetParentalRatingString(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); + y += ts.Height(); + } + int i = 0; + while (Event->Contents(i++)) { + if (!isempty(Event->GetContentsString())) { + const cFont *font = cFont::GetFont(fontSml); + ts.Set(osd, xl, y, x4 - xl, y4 - y, Event->GetContentsString(), font, Theme.Color(clrMenuEventShortText), Theme.Color(clrBackground)); + y += ts.Height(); + } + } +#endif /* PARENTALRATING */ if (!isempty(Event->Description())) { int yt = y; int yb = y4 - Roundness; diff -ruNp vdr-1.6.0-2/sources.c vdr-1.6.0-2-extensions/sources.c --- vdr-1.6.0-2/sources.c 2008-02-10 15:07:26.000000000 +0100 +++ vdr-1.6.0-2-extensions/sources.c 2009-04-09 20:48:27.000000000 +0200 @@ -37,6 +37,9 @@ cString cSource::ToString(int Code) char buffer[16]; char *q = buffer; switch (Code & st_Mask) { +#ifdef USE_PLUGINPARAM + case stPlug: *q++ = 'P'; break; +#endif /* PLUGINPARAM */ case stCable: *q++ = 'C'; break; case stSat: *q++ = 'S'; { @@ -56,6 +59,9 @@ int cSource::FromString(const char *s) { int type = stNone; switch (toupper(*s)) { +#ifdef USE_PLUGINPARAM + case 'P': type = stPlug; break; +#endif /* PLUGINPARAM */ case 'C': type = stCable; break; case 'S': type = stSat; break; case 'T': type = stTerr; break; @@ -68,7 +74,11 @@ int cSource::FromString(const char *s) int pos = 0; bool dot = false; bool neg = false; +#ifdef USE_SOURCECAPS + while (*++s && !isblank(*s)) { +#else while (*++s) { +#endif /* SOURCECAPS */ switch (toupper(*s)) { case '0' ... '9': pos *= 10; pos += *s - '0'; diff -ruNp vdr-1.6.0-2/sources.conf vdr-1.6.0-2-extensions/sources.conf --- vdr-1.6.0-2/sources.conf 2008-09-11 13:29:43.000000000 +0200 +++ vdr-1.6.0-2-extensions/sources.conf 2009-04-09 20:48:27.000000000 +0200 @@ -194,3 +194,7 @@ C Cable # Terrestrial T Terrestrial + +# Plugin PLUGINPARAM + +#P Plugin diff -ruNp vdr-1.6.0-2/sources.h vdr-1.6.0-2-extensions/sources.h --- vdr-1.6.0-2/sources.h 2005-05-14 11:30:41.000000000 +0200 +++ vdr-1.6.0-2-extensions/sources.h 2009-04-09 20:48:27.000000000 +0200 @@ -16,10 +16,17 @@ class cSource : public cListObject { public: enum eSourceType { stNone = 0x0000, +#ifdef USE_PLUGINPARAM + stPlug = 0x2000, +#endif /* PLUGINPARAM */ stCable = 0x4000, stSat = 0x8000, stTerr = 0xC000, +#ifdef USE_PLUGINPARAM + st_Mask = 0xE000, +#else st_Mask = 0xC000, +#endif /* PLUGINPARAM */ st_Neg = 0x0800, st_Pos = 0x07FF, }; @@ -35,6 +42,9 @@ public: static cString ToString(int Code); static int FromString(const char *s); static int FromData(eSourceType SourceType, int Position = 0, bool East = false); +#ifdef USE_PLUGINPARAM + static bool IsPlug(int Code) { return (Code & st_Mask) == stPlug; } +#endif /* PLUGINPARAM */ static bool IsCable(int Code) { return (Code & st_Mask) == stCable; } static bool IsSat(int Code) { return (Code & st_Mask) == stSat; } static bool IsTerr(int Code) { return (Code & st_Mask) == stTerr; } diff -ruNp vdr-1.6.0-2/status.c vdr-1.6.0-2-extensions/status.c --- vdr-1.6.0-2/status.c 2008-02-16 15:46:31.000000000 +0100 +++ vdr-1.6.0-2-extensions/status.c 2009-04-09 20:48:27.000000000 +0200 @@ -29,6 +29,20 @@ void cStatus::MsgTimerChange(const cTime sm->TimerChange(Timer, Change); } +#ifdef USE_STREAMDEVEXT +void cStatus::MsgRecordingChange(const cRecording *Recording, eStatusChange Change) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->RecordingChange(Recording, Change); +} + +void cStatus::MsgChannelChange(const cChannel *Channel, eStatusChange Change) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->ChannelChange(Channel, Change); +} +#endif /* STREAMDEVEXT */ + void cStatus::MsgChannelSwitch(const cDevice *Device, int ChannelNumber) { for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) @@ -124,3 +138,87 @@ void cStatus::MsgOsdProgramme(time_t Pre for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, FollowingTime, FollowingTitle, FollowingSubtitle); } + +#ifdef USE_PINPLUGIN +bool cStatus::MsgChannelProtected(const cDevice* Device, const cChannel* Channel) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + if (sm->ChannelProtected(Device, Channel) == true) + return true; + return false; +} + +bool cStatus::MsgReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + if (sm->ReplayProtected(Recording, Name, Base, isDirectory, menuView) == true) + return true; + return false; +} + +void cStatus::MsgRecordingFile(const char* FileName) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->RecordingFile(FileName); +} + +void cStatus::MsgTimerCreation(cTimer* Timer, const cEvent *Event) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->TimerCreation(Timer, Event); +} + +bool cStatus::MsgPluginProtected(cPlugin* Plugin, int menuView) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + if (sm->PluginProtected(Plugin, menuView) == true) + return true; + return false; +} + +void cStatus::MsgUserAction(const eKeys key, const cOsdObject* Interact) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->UserAction(key, Interact); +} + +bool cStatus::MsgMenuItemProtected(const char* Name, int menuView) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + if (sm->MenuItemProtected(Name, menuView) == true) + return true; + return false; +} +#endif /* PINPLUGIN */ + +#ifdef USE_GRAPHTFT +void cStatus::MsgOsdSetEvent(const cEvent* event) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->OsdSetEvent(event); +} + +void cStatus::MsgOsdSetRecording(const cRecording* recording) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->OsdSetRecording(recording); +} + +void cStatus::MsgOsdMenuDisplay(const char* kind) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->OsdMenuDisplay(kind); +} + +void cStatus::MsgOsdMenuDestroy() +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->OsdMenuDestroy(); +} + +void cStatus::MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) +{ + for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) + sm->OsdEventItem(Event, Text, Index, Count); +} +#endif /* GRAPHTFT */ diff -ruNp vdr-1.6.0-2/status.h vdr-1.6.0-2-extensions/status.h --- vdr-1.6.0-2/status.h 2008-02-16 16:00:33.000000000 +0100 +++ vdr-1.6.0-2-extensions/status.h 2009-04-09 20:48:27.000000000 +0200 @@ -14,8 +14,14 @@ #include "device.h" #include "player.h" #include "tools.h" +#ifdef USE_PINPLUGIN +#include "plugin.h" +#endif /* PINPLUGIN */ enum eTimerChange { tcMod, tcAdd, tcDel }; +#ifdef USE_STREAMDEVEXT +enum eStatusChange { scMod, scAdd, scDel }; +#endif /* STREAMDEVEXT */ class cTimer; @@ -30,6 +36,16 @@ protected: // been added or will be deleted, respectively. In case of tcMod, // Timer is NULL; this indicates that some timer has been changed. // Note that tcAdd and tcDel are always also followed by a tcMod. +#ifdef USE_STREAMDEVEXT + virtual void RecordingChange(const cRecording *Recording, eStatusChange Change) {} + // Indicates a change in the recordings settings. + // If Change is scAdd or scDel, Recording points to the recording that has + // been added or will be deleted, respectively. In case of scMod, + // Timer is NULL; this indicates that some timer has been changed. + // Note that scAdd and scDel are always also followed by a scMod. + virtual void ChannelChange(const cChannel *Channel, eStatusChange Change) {} + // Indicates a change in the channel list. +#endif /* STREAMDEVEXT */ virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber) {} // Indicates a channel switch on the given DVB device. // If ChannelNumber is 0, this is before the channel is being switched, @@ -80,11 +96,45 @@ protected: // The OSD displays the single line Text with the current channel information. virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) {} // The OSD displays the given programme information. +#ifdef USE_PINPLUGIN + virtual bool ChannelProtected(const cDevice *Device, const cChannel* Channel) { return false; } + // Checks if a channel is protected. + virtual bool ReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView = false) { return false; } + // Checks if a recording is protected. + virtual void RecordingFile(const char* FileName) {} + // The given DVB device has started recording to FileName. FileName is the name of the + // recording directory + virtual void TimerCreation(cTimer* Timer, const cEvent *Event) {} + // The given timer is created + virtual bool PluginProtected(cPlugin* Plugin, int menuView = false) { return false; } + // Checks if a plugin is protected. + virtual void UserAction(const eKeys key, const cOsdObject* Interact) {} + // report user action + virtual bool MenuItemProtected(const char* Name, int menuView = false) { return false; } + // Checks if a menu entry is protected. +#endif /* PINPLUGIN */ +#ifdef USE_GRAPHTFT + virtual void OsdSetRecording(const cRecording* recording) {} + // The OSD displays the recording information. + virtual void OsdSetEvent(const cEvent* event) {} + // The OSD displays the event information. + virtual void OsdMenuDisplay(const char* kind) {} + // report menu creation + virtual void OsdMenuDestroy() {} + // report menu destruvtion + virtual void OsdEventItem(const cEvent* Event, const char *Text, int Index, int Count) {} + // The OSD displays the given single line Event as menu item at Index. +#endif /* GRAPHTFT */ + public: cStatus(void); virtual ~cStatus(); // These functions are called whenever the related status information changes: static void MsgTimerChange(const cTimer *Timer, eTimerChange Change); +#ifdef USE_STREAMDEVEXT + static void MsgRecordingChange(const cRecording *Recording, eStatusChange Change); + static void MsgChannelChange(const cChannel *Channel, eStatusChange Change); +#endif /* STREAMDEVEXT */ static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber); static void MsgRecording(const cDevice *Device, const char *Name, const char *FileName, bool On); static void MsgReplaying(const cControl *Control, const char *Name, const char *FileName, bool On); @@ -101,6 +151,22 @@ public: static void MsgOsdTextItem(const char *Text, bool Scroll = false); static void MsgOsdChannel(const char *Text); static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle); +#ifdef USE_PINPLUGIN + static bool MsgChannelProtected(const cDevice* Device, const cChannel* Channel); + static bool MsgReplayProtected(const cRecording* Recording, const char* Name, const char* Base, bool isDirectory, int menuView = false); + static void MsgRecordingFile(const char* FileName); + static void MsgTimerCreation(cTimer* Timer, const cEvent *Event); + static bool MsgPluginProtected(cPlugin* Plugin, int menuView = false); + static void MsgUserAction(const eKeys key, const cOsdObject* Interact); + static bool MsgMenuItemProtected(const char* Name, int menuView = false); +#endif /* PINPLUGIN */ +#ifdef USE_GRAPHTFT + static void MsgOsdSetEvent(const cEvent* event); + static void MsgOsdSetRecording(const cRecording* recording); + static void MsgOsdMenuDisplay(const char* kind); + static void MsgOsdMenuDestroy(); + static void MsgOsdEventItem(const cEvent* Event, const char *Text, int Index, int Count); +#endif /* GRAPHTFT */ }; #endif //__STATUS_H diff -ruNp vdr-1.6.0-2/submenu.c vdr-1.6.0-2-extensions/submenu.c --- vdr-1.6.0-2/submenu.c 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/submenu.c 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,952 @@ +#ifdef USE_SETUP +/**************************************************************************** + * DESCRIPTION: + * Submenu + * + * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ + * + * Contact: ranga@teddycats.de + * + * Copyright (C) 2004, 2005 by Ralf Dotzert + * + * modified for the VDR Extensions Patch by zulu @vdr-portal + ****************************************************************************/ + +#ifndef SUBMENU_H +#include "submenu.h" +#include "plugin.h" + +static const char* TAG_SYSTEM = "system"; +static const char* TAG_PLUGIN = "plugin"; +static const char* TAG_COMMAND = "command"; +static const char* TAG_THREAD = "thread"; +static const char* TAG_MENU = "menu"; +static const char* TAG_UNDEFINED = "undefined"; +static const char* TRUE_STR = "yes"; + + +//################################################################################ +//# SubMenuNode +//################################################################################ + +cSubMenuNode::cSubMenuNode(TiXmlElement * xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) +{ + init(); + _parentMenu = parentMenu; + _currentMenu = currentMenu; + _level = level; + + if (xml != NULL && xml->Type() == TiXmlNode::ELEMENT) { + const char *tag = xml->Value(); + + if (cSubMenuNode::IsType(tag) != cSubMenuNode::UNDEFINED) { + SetType(tag); + SetName(xml->Attribute("name")); + if ((_type == COMMAND) || (_type == THREAD)) { + SetCommand(xml->Attribute("execute")); + const char * confirmStr = xml->Attribute("confirm"); + if (confirmStr != NULL && strcmp(confirmStr, TRUE_STR) == 0) + _commandConfirm = true; + } + else if (_type == PLUGIN) { // Add Plugin Index + SetCustomTitle(xml->Attribute("title")); + SetPlugin(); + } + else if (_type == MENU && xml->NoChildren() == false) { + xml = xml->FirstChildElement(); + do { + cSubMenuNode *node = new cSubMenuNode(xml, level+1, &_subMenus, currentMenu); + _subMenus.Add(node); + } while ((xml=xml->NextSiblingElement()) != NULL); + } + } + } + else + throw "Invalid XML Node"; +} + +/** + * Construct new Node empty Node + * + * + */ +cSubMenuNode::cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu) +{ + init(); + _parentMenu = parentMenu; + _currentMenu = currentMenu; + +} + + +/** + * + */ +void cSubMenuNode::init() +{ + _name = NULL; + _command = NULL; + _title = NULL; + _pluginMainMenuEntry = NULL; + _type = UNDEFINED; + _level = 0; + _parentMenu = NULL; + _currentMenu = NULL; + _pluginIndex = 0; + _commandConfirm = false; +} + + +cSubMenuNode::~ cSubMenuNode() +{ + if (_name != NULL) + free((void*)_name); + if (_command != NULL) + free((void*)_command); + if (_title != NULL) + free((void*)_title); + if (_pluginMainMenuEntry != NULL) + free((void*)_pluginMainMenuEntry); +} + +/** + * + */ +void cSubMenuNode::SetPlugin() +{ + bool found = false; + for (int i = 0; ; i++) { + cPlugin *p = cPluginManager::GetPlugin(i); + if (p) { + if (strcmp(_name, p->Name()) == 0 && p->MainMenuEntry() != NULL) { + SetPluginMainMenuEntry(p->MainMenuEntry()); + _pluginIndex = i; + found = true; + break; + } + } + else + break; + } + + if (!found) + _type = UNDEFINED; +} + + +bool cSubMenuNode::SaveXml(TiXmlElement * root) +{ + bool ok = true; + + if (root!=NULL) { + TiXmlElement *e = NULL; + switch(_type) { + case SYSTEM: + e = new TiXmlElement(TAG_SYSTEM); + e->SetAttribute("name", GetName()); + break; + case COMMAND: + e = new TiXmlElement(TAG_COMMAND); + e->SetAttribute("name", GetName()); + e->SetAttribute("execute", GetCommand()); + if (_commandConfirm) + e->SetAttribute("confirm", TRUE_STR); + break; + case THREAD: + e = new TiXmlElement(TAG_THREAD); + e->SetAttribute("name", GetName()); + e->SetAttribute("execute", GetCommand()); + if (_commandConfirm) + e->SetAttribute("confirm", TRUE_STR); + break; + case PLUGIN: + e = new TiXmlElement(TAG_PLUGIN); + e->SetAttribute("name", GetName()); + if (GetCustomTitle() != NULL && strcmp(GetCustomTitle(), "") != 0) + e->SetAttribute("title", GetCustomTitle()); + break; + case MENU: + e = new TiXmlElement(TAG_MENU); + e->SetAttribute("name", GetName()); + break; + case UNDEFINED: + default: + ok = false; + break; + } + if (ok) { + root->LinkEndChild(e); + if (HasSubMenus()) + for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) + node->SaveXml(e); + } + } + + return(ok); +} + + +cSubMenuNode::Type cSubMenuNode::IsType(const char *name) +{ + Type type = UNDEFINED; + + if (strcmp(name ,TAG_SYSTEM) == 0) + type = cSubMenuNode::SYSTEM; + else if (strcmp(name ,TAG_PLUGIN) == 0) + type = cSubMenuNode::PLUGIN; + else if (strcmp(name ,TAG_COMMAND) == 0) + type = cSubMenuNode::COMMAND; + else if (strcmp(name ,TAG_THREAD) == 0) + type = cSubMenuNode::THREAD; + else if (strcmp(name ,TAG_MENU) == 0) + type = cSubMenuNode::MENU; + + return(type); +} + +void cSubMenuNode::SetType(const char * name) +{ + _type = IsType(name); +} + +void cSubMenuNode::SetType(enum Type type) +{ + _type = type; +} + + +cSubMenuNode::Type cSubMenuNode::GetType() +{ + return(_type); +} + +const char * cSubMenuNode::GetTypeAsString() +{ + const char *str=NULL; + switch(_type) { + case SYSTEM: + str = TAG_SYSTEM; + break; + case COMMAND: + str = TAG_COMMAND; + break; + case THREAD: + str = TAG_THREAD; + break; + case PLUGIN: + str = TAG_PLUGIN; + break; + case MENU: + str = TAG_MENU; + break; + case UNDEFINED: + str = TAG_UNDEFINED; + default: + break; + } + + return(str); +} + +void cSubMenuNode::SetCommand(const char * command) +{ + if (_command != NULL) + free((void*)_command); + + if (command != NULL) + _command = strdup(command); + else + _command = NULL; +} + +const char * cSubMenuNode::GetCommand() +{ + return(_command); +} + +bool cSubMenuNode::CommandConfirm() +{ + return(_commandConfirm); +} + +void cSubMenuNode::SetCommandConfirm(int val) +{ + if (val == 1) + _commandConfirm = true; + else + _commandConfirm = false; +} + +void cSubMenuNode::SetCustomTitle(const char * title) +{ + if (_title != NULL) + free((void*)_title); + + if (title != NULL) + _title = strdup(title); + else + _title = NULL; +} + +const char * cSubMenuNode::GetCustomTitle() +{ + return(_title); +} + +void cSubMenuNode::SetName(const char * name) +{ + if (_name) + free ((void*)_name); + + if (name != NULL) + _name = strdup(name); + else + _name = NULL; +} + +const char * cSubMenuNode::GetName() +{ + return(_name); +} + +int cSubMenuNode::GetLevel() +{ + return(_level); +} + +void cSubMenuNode::SetLevel(int level) +{ + _level = level; + if (HasSubMenus()) { //Adjust Levels of Subnodes + for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) + node->SetLevel(level+1); + } +} + +int cSubMenuNode::GetPluginIndex() +{ + return(_pluginIndex); +} + +void cSubMenuNode::SetPluginIndex(int index) +{ + _pluginIndex = index; +} + +void cSubMenuNode::SetPluginMainMenuEntry(const char * mainMenuEntry) +{ + if (_pluginMainMenuEntry != NULL) + free((void*)_pluginMainMenuEntry); + + if (_title != NULL && strcmp(_title, "") != 0) + _pluginMainMenuEntry = strdup(_title); + else if (mainMenuEntry != NULL) + _pluginMainMenuEntry = strdup(mainMenuEntry); + else + _pluginMainMenuEntry = NULL; +} + +const char * cSubMenuNode::GetPluginMainMenuEntry() +{ + return(_pluginMainMenuEntry); +} + + + +cSubMenuNodes * cSubMenuNode::GetParentMenu() +{ + return(_parentMenu); +} + +void cSubMenuNode::SetParentMenu(cSubMenuNodes * parent) +{ + _parentMenu = parent; +} + +cSubMenuNodes * cSubMenuNode::GetCurrentMenu() +{ + return(_currentMenu); +} + +void cSubMenuNode::SetCurrentMenu(cSubMenuNodes * current) +{ + _currentMenu = current; +} + + +cSubMenuNodes * cSubMenuNode::GetSubMenus() +{ + return(&_subMenus); +} + +bool cSubMenuNode::HasSubMenus() +{ + if (_subMenus.Count() > 0) + return(true); + else + return(false); +} + + +void cSubMenuNode::Print(int index) +{ + for (int i = 0; i < index; i++) + printf(" "); + + printf("Name=%s Type=%s Level=%d", _name, GetTypeAsString(), _level); + if (_type == COMMAND || _type == THREAD) + printf(" Command=%s", _command); + else if (_type == PLUGIN && _title != NULL) + printf(" Title=%s", _title); + printf("\n"); + + for (cSubMenuNode *node = _subMenus.First(); node; node = _subMenus.Next(node)) + node->Print(index+4); +} + + +//################################################################################ +//# +//################################################################################ +cSubMenu::cSubMenu() +{ + _menuSuffix = NULL; + _fname = NULL; + _commandResult = NULL; + _currentMenuTree = &_menuTree; + _currentParentMenuTree = NULL; +#ifdef USE_PINPLUGIN + _currentParentIndex = -1; +#endif /* PINPLUGIN */ + _nodeArray = NULL; + _nrNodes = 0; +} + + +cSubMenu::~cSubMenu() +{ + if (_menuSuffix) + free(_menuSuffix); + if (_fname) + free(_fname); + if (_commandResult) + free(_commandResult); + if (_nodeArray) + free(_nodeArray); + _nrNodes = 0; +} + + +bool cSubMenu::LoadXml(char *fname) +{ + TiXmlDocument xmlDoc = TiXmlDocument(fname); + TiXmlElement *root = NULL; + cSubMenuNode *node = NULL; + + bool ok = true; + //Clear previously loaded Menu + if (_fname != NULL) + free(_fname); + _menuTree.Clear(); + _fname = strdup(fname); + + if ((ok = xmlDoc.LoadFile())) { + if ((root = xmlDoc.FirstChildElement("menus")) != NULL) { + char *tmp = NULL; + if ((tmp = (char*)root->Attribute("suffix")) == NULL) + asprintf(&_menuSuffix, " "); // set default menuSuffix // asprintf(&_menuSuffix, " ..."); + else + asprintf(&_menuSuffix, tmp); + + if ((root = root->FirstChildElement()) != NULL) { + do { + try { + node = new cSubMenuNode(root, 0, &_menuTree, NULL); + _menuTree.Add(node); + } + catch (char *message) { + esyslog("ERROR: while decoding XML Node"); + ok = false; + } + } while (ok == true && (root = root->NextSiblingElement()) != NULL); + addMissingPlugins(); + removeUndefinedNodes(); + } + } + else { + esyslog("ERROR: in %s, missing Tag \n", fname); + ok = false; + } + } + else { + esyslog("ERROR: in %s : %s Col=%d Row=%d\n", + fname, + xmlDoc.ErrorDesc(), + xmlDoc.ErrorCol(), + xmlDoc.ErrorRow()); + ok = false; + } + + return(ok); +} + + +bool cSubMenu::SaveXml() +{ + return(SaveXml(_fname)); +} + + +bool cSubMenu::SaveXml(char *fname) +{ + bool ok = true; + + if (_fname != NULL) { + TiXmlDocument xml = TiXmlDocument(fname); + TiXmlComment comment; + comment.SetValue("\n\ +- VDR Menu-Configuration File\n\ +-\n\ +-\n\ +- Example:\n\ +-\n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + \n\ + ...\n\ + \n\ + \n\ + \n\ + \n\ + ...\n\ + \n\ + \n\ +"); + + TiXmlElement root("menus"); + root.SetAttribute("suffix", _menuSuffix); + for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) + node->SaveXml(&root); + + if (xml.InsertEndChild(comment) != NULL && xml.InsertEndChild(root) != NULL) + ok = xml.SaveFile(fname); + } + else + ok = false; + + return(ok); +} + + + +cSubMenuNodes * cSubMenu::GetMenuTree() +{ + return(_currentMenuTree); +} + + +void cSubMenu::PrintMenuTree() +{ + for (cSubMenuNode *node = _menuTree.First(); node; node = _menuTree.Next(node)) + node->Print(); +} + + +int cSubMenu::GetNrOfNodes() +{ + if (_nrNodes == 0) { + if ((_nrNodes = countNodes(&_menuTree)) > 0) { + _nodeArray = (cSubMenuNode**) malloc(sizeof(cSubMenuNode*)*_nrNodes); + int index = 0; + tree2Array(&_menuTree, index); + } + } + + return(_nrNodes); +} + + +/** + * returns the specified node within the current menu + * @param index position in the current menu + * @return node or null if not found + */ +cSubMenuNode * cSubMenu::GetNode(int index) +{ + cSubMenuNode *node = NULL; + if (_currentMenuTree == NULL || (node=_currentMenuTree->Get(index)) == NULL) + esyslog("ERROR: illegal call of cSubMenu::GetNode(%d)", index); + + return(node); +} + + +/** + * Get the specified Node + * @param index specfies the absolut indes in the list of all nodes + * @return node or NULL if not found + */ +cSubMenuNode * cSubMenu::GetAbsNode(int index) +{ + cSubMenuNode *node = NULL; + GetNrOfNodes(); + if (_nrNodes > 0 && index >= 0 && index < _nrNodes) + node = _nodeArray[index]; + + return(node); +} + + +#ifdef USE_PINPLUGIN +bool cSubMenu::Down(cSubMenuNode *node, int currentIndex) +#else +bool cSubMenu::Down(int index) +#endif /* PINPLUGIN */ +{ + bool ok = true; +#ifdef USE_PINPLUGIN + if (_currentMenuTree != NULL && node && node->GetType() == cSubMenuNode::MENU) { +#else + cSubMenuNode *node = NULL; + + if (_currentMenuTree != NULL && (node=_currentMenuTree->Get(index)) != NULL && node->GetType() == cSubMenuNode::MENU) { +#endif /* PINPLUGIN */ + _currentParentMenuTree = _currentMenuTree; +#ifdef USE_PINPLUGIN + _currentParentIndex = currentIndex; +#endif /* PINPLUGIN */ + _currentMenuTree = node->GetSubMenus(); + } + else { + ok = false; +#ifdef USE_PINPLUGIN + esyslog("ERROR: illegal call of cSubMenu::Down"); +#else + esyslog("ERROR: illegal call of cSubMenu::Down(%d)", index); +#endif /* PINPLUGIN */ + } + + return(ok); +} + +bool cSubMenu::Up(int *parentIndex) +{ + bool ok = true; + + if (_currentMenuTree != NULL && parentIndex != NULL) { +#ifndef USE_PINPLUGIN + cSubMenuNode *node = NULL; +#endif /* PINPLUGIN */ + *parentIndex = 0; +#ifdef USE_PINPLUGIN + if (_currentParentIndex >= 0) + *parentIndex = _currentParentIndex; +#else + if (_currentParentMenuTree != NULL) + for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { + if (_currentMenuTree == node->GetSubMenus()) { + *parentIndex = i; + break; + } + } +#endif /* PINPLUGIN */ + + _currentMenuTree = _currentParentMenuTree; + if (_currentMenuTree != NULL) + _currentParentMenuTree = _currentMenuTree->Get(0)->GetParentMenu(); + else + ok = false; + } + else { + ok = false; + esyslog("ERROR: illegal call of cSubMenu::Up()"); + } + + return(ok); +} + +const char * cSubMenu::ExecuteCommand(const char * cmd) +{ + free(_commandResult); + _commandResult = NULL; + + dsyslog("executing command '%s'", cmd); + FILE *p = popen(cmd, "r"); + if (p) { + int l = 0; + int c; + while ((c = fgetc(p)) != EOF) { + if (l % 20 == 0) + _commandResult = (char *)realloc(_commandResult, l + 21); + _commandResult[l++] = c; + } + if (_commandResult) + _commandResult[l] = 0; + pclose(p); + } + else + esyslog("ERROR: can't open pipe for command '%s'", cmd); + + return _commandResult; +} + +/** + * Move Menu Entry to new Position + * @param index index of menu entry to move + * @param toIndex index of destination + * @param where After ore before the destination index + */ +void cSubMenu::MoveMenu(int index, int toIndex, enum Where where) +{ + if (index < 0 || index > _nrNodes || // invalid index is ignored + toIndex < 0 || toIndex > _nrNodes || index == toIndex) + return; + + cSubMenuNode *srcNode = GetAbsNode(index); + cSubMenuNode *destNode = GetAbsNode(toIndex); + + if (where == cSubMenu::INTO && destNode->GetType() != cSubMenuNode::MENU) + return; + + if (where == cSubMenu::INTO) { + if (destNode->GetType() == cSubMenuNode::MENU) { + srcNode->GetCurrentMenu()->Del(srcNode, false); + srcNode->SetLevel(destNode->GetLevel()+1); + srcNode->SetParentMenu(destNode->GetCurrentMenu()); + srcNode->SetCurrentMenu(destNode->GetSubMenus()); + + destNode->GetSubMenus()->Add(srcNode); + reloadNodeArray(); + } + } + else { + srcNode->GetCurrentMenu()->Del(srcNode, false); + srcNode->SetLevel(destNode->GetLevel()); + srcNode->SetParentMenu(destNode->GetParentMenu()); + srcNode->SetCurrentMenu(destNode->GetCurrentMenu()); + + if (where == cSubMenu::BEHIND) { + destNode->GetCurrentMenu()->Add(srcNode, GetAbsNode(toIndex)); + reloadNodeArray(); + } + else { + destNode->GetCurrentMenu()->Ins(srcNode, GetAbsNode(toIndex)); + reloadNodeArray(); + } + } +} + +/** + * Create a new Menu Entry + * @param index index of destination + * @param menuTitle Titel of new Menu entry + */ +void cSubMenu::CreateMenu(int index, const char * menuTitle) +{ + if (index >= 0 && index < _nrNodes) { + cSubMenuNode *srcNode = GetAbsNode(index); + if (srcNode != NULL) { + cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); + newNode->SetLevel(srcNode->GetLevel()); + newNode->SetName(menuTitle); + newNode->SetType(cSubMenuNode::MENU); + newNode->SetParentMenu(srcNode->GetParentMenu()); + newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); + + srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); + reloadNodeArray(); + } + } +} + +/** + * delete the specified entry, or subtree if the specified entry is a menu + * @param index destion index + */ +void cSubMenu::DeleteMenu(int index) +{ + if (index >= 0 && index < _nrNodes) { + cSubMenuNode *srcNode = GetAbsNode(index); + srcNode->GetCurrentMenu()->Del(srcNode, true); + reloadNodeArray(); + } +} + + +// Private Methods + +int cSubMenu::countNodes(cSubMenuNodes * tree) +{ + int count = 0; + if (tree != NULL) { + for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { + count++; + if (node->HasSubMenus()) + count += countNodes(node->GetSubMenus()); + } + } + return(count); +} + + +void cSubMenu::tree2Array(cSubMenuNodes * tree, int &index) +{ + if (tree != NULL) { + for (cSubMenuNode *node = tree->First(); node; node = tree->Next(node)) { + _nodeArray[index++]=node; + if (node->HasSubMenus()) + tree2Array(node->GetSubMenus(), index); + } + } + +} + +bool cSubMenu::IsPluginInMenu(const char * name) +{ + bool found = false; + for (int i = 0; i < _nrNodes && found == false; i++) { + cSubMenuNode *node = GetAbsNode(i); + if (node != NULL && node->GetType() == cSubMenuNode::PLUGIN && strcmp(name, node->GetName()) == 0) + found = true; + } + return(found); +} + +/** + * Adds the given plugin to the Menu-Tree if not allready in List + * @param name specifies the name of the plugin + */ +void cSubMenu::AddPlugin(const char * name) +{ + if (! IsPluginInMenu(name)) { + cSubMenuNode *node = new cSubMenuNode(&_menuTree, NULL); + node->SetName(name); + node->SetType("plugin"); + node->SetPlugin(); + _menuTree.Add(node); + } +} + +void cSubMenu::addMissingPlugins() +{ + _nrNodes = GetNrOfNodes(); + for (int i = 0; ; i++) { + cPlugin *p = cPluginManager::GetPlugin(i); + if (p) + AddPlugin(p->Name()); + else + break; + } + reloadNodeArray(); +} + +/** + * Adds the given command to the Menu-Tree + * @param name specifies the name of the command + */ +void cSubMenu::CreateCommand(int index, const char * name, const char * execute, int confirm) +{ + if (index >= 0 && index < _nrNodes) { + cSubMenuNode *srcNode = GetAbsNode(index); + if (srcNode != NULL) { + cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); + newNode->SetLevel(srcNode->GetLevel()); + newNode->SetName(name); + newNode->SetType("command"); + newNode->SetCommand(execute); + newNode->SetCommandConfirm(confirm); + newNode->SetParentMenu(srcNode->GetParentMenu()); + newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); + + srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); + reloadNodeArray(); + } + } +} + +void cSubMenu::CreateThread(int index, const char * name, const char * execute, int confirm) +{ + if (index >= 0 && index < _nrNodes) { + cSubMenuNode *srcNode = GetAbsNode(index); + if (srcNode != NULL) { + cSubMenuNode *newNode = new cSubMenuNode(srcNode->GetParentMenu(), srcNode->GetCurrentMenu()); + newNode->SetLevel(srcNode->GetLevel()); + newNode->SetName(name); + newNode->SetType("thread"); + newNode->SetCommand(execute); + newNode->SetCommandConfirm(confirm); + newNode->SetParentMenu(srcNode->GetParentMenu()); + newNode->SetCurrentMenu(srcNode->GetCurrentMenu()); + + srcNode->GetCurrentMenu()->Add(newNode, GetAbsNode(index)); + reloadNodeArray(); + } + } +} + +/** + * reloads the internal Array of Nodes + */ +void cSubMenu::reloadNodeArray() +{ + if (_nrNodes > 0) + free(_nodeArray); + _nodeArray = NULL; + _nrNodes = 0; + _nrNodes = GetNrOfNodes(); +} + +/** + * remove Undefined Nodes + */ +void cSubMenu::removeUndefinedNodes() +{ + bool remove = false; + + reloadNodeArray(); + for (int i = 0; i < _nrNodes; i++) { + cSubMenuNode *node = GetAbsNode(i); + if (node != NULL && node->GetType() == cSubMenuNode::UNDEFINED) { + cSubMenuNodes *pMenu = node->GetCurrentMenu(); + pMenu->Del(node, true); + remove = true; + } + } + if (remove) + reloadNodeArray(); +} + + +/** +* Retrieves the Menutitel of the parent Menu +*/ +const char *cSubMenu::GetParentMenuTitel() +{ + const char * result = ""; + + if (_currentMenuTree != NULL && _currentParentMenuTree != NULL) { + cSubMenuNode *node = NULL; + for (int i = 0; (node = _currentParentMenuTree->Get(i)) != NULL; i++) { + if (_currentMenuTree == node->GetSubMenus()) { + result = node->GetName(); + break; + } + } + } + + return(result); +} + +#endif +#endif /* SETUP */ diff -ruNp vdr-1.6.0-2/submenu.h vdr-1.6.0-2-extensions/submenu.h --- vdr-1.6.0-2/submenu.h 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/submenu.h 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,160 @@ +#ifdef USE_SETUP +/**************************************************************************** + * DESCRIPTION: + * Submenu + * + * $Id: vdr-1.3.44-Setup-0.3.0.diff,v 1.1 2006/03/04 09:58:47 ralf Exp $ + * + * Contact: ranga@teddycats.de + * + * Copyright (C) 2004, 2005 by Ralf Dotzert + * + * modified for the VDR Extensions Patch by zulu @vdr-portal + ****************************************************************************/ + +#ifndef SUBMENU_H +#define SUBMENU_H + +#include "thread.h" +#include "tools.h" +#include "tinystr.h" + +class cSubMenuNode; +class cSubMenuNodes; +class cSubMenu; + + +class cSubMenuNodes : public cList {}; + +// execute cmd thread +class cExecCmdThread : public cThread { +private: + char *ExecCmd; +protected: + virtual void Action(void) { + if (system(ExecCmd) == 0) + esyslog("%s - finished", ExecCmd); + delete(this); + }; +public: + cExecCmdThread(char *cmd) { + asprintf(&ExecCmd, "%s", cmd); + } + cExecCmdThread(const char *cmd) { + asprintf(&ExecCmd, "%s", cmd); + } + ~cExecCmdThread() { + free(ExecCmd); + }; + }; + +//################################################################################ +//# SubMenuNode +//################################################################################ +class cSubMenuNode : public cListObject { +public: + enum Type { UNDEFINED, SYSTEM, COMMAND, THREAD, PLUGIN, MENU }; + cSubMenuNode(TiXmlElement * xml, int level, cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); + cSubMenuNode(cSubMenuNodes *currentMenu, cSubMenuNodes *parentMenu); + ~cSubMenuNode(); + bool SaveXml(TiXmlElement * root); + static cSubMenuNode::Type IsType(const char *name); + void SetType(const char *name); + void SetType(enum Type type); + void SetPlugin(); + cSubMenuNode::Type GetType(); + const char *GetTypeAsString(); + void SetCommand(const char *command); + bool CommandConfirm(); + void SetCommandConfirm(int val); + const char *GetCommand(); + void SetCustomTitle(const char *title); + const char *GetCustomTitle(); + void SetName(const char *name); + const char*GetName(); + int GetLevel(); + void SetLevel(int level); + int GetPluginIndex(); + void SetPluginIndex(int index); + void SetPluginMainMenuEntry(const char *mainMenuEntry); + const char *GetPluginMainMenuEntry(); + cSubMenuNodes *GetParentMenu(); + void SetParentMenu(cSubMenuNodes *parent); + cSubMenuNodes *GetCurrentMenu(); + void SetCurrentMenu(cSubMenuNodes *current); + cSubMenuNodes *GetSubMenus(); + bool HasSubMenus(); + void Print(int index = 0); +private: + Type _type; + int _level; + // Plugin Variables + int _pluginIndex; + const char *_pluginMainMenuEntry; + // common + const char *_name; + const char *_command; + bool _commandConfirm; + const char *_title; + cSubMenuNodes _subMenus; + cSubMenuNodes *_parentMenu; + cSubMenuNodes *_currentMenu; + void init(); + }; + + +//################################################################################ +//# SubMenu Class +//################################################################################ +class cSubMenu { +public: + cSubMenu(); + ~cSubMenu(); + enum Where { BEFORE, BEHIND, INTO}; + bool LoadXml(char *fname); + bool SaveXml(char *fname); + bool SaveXml(); + cSubMenuNodes *GetMenuTree(); + bool Up(int *ParentIndex); +#ifdef USE_PINPLUGIN + bool Down(cSubMenuNode* node, int currentIndex); +#else + bool Down(int index); +#endif /* PINPLUGIN */ + int GetNrOfNodes(); + cSubMenuNode* GetAbsNode(int index); + cSubMenuNode* GetNode(int index); + void PrintMenuTree(); + bool IsPluginInMenu(const char *name); + void AddPlugin(const char *name); + void CreateCommand(int index, const char *name, const char *execute, int confirm); + void CreateThread(int index, const char *name, const char *execute, int confirm); + const char *ExecuteCommand(const char *command); + void MoveMenu(int index, int toindex, enum Where); + void CreateMenu(int index, const char *menuTitle); + void DeleteMenu(int index); + char *GetMenuSuffix() { return _menuSuffix; } + void SetMenuSuffix(char *suffix) { if (_menuSuffix) free(_menuSuffix); asprintf(&_menuSuffix, suffix); } + bool isTopMenu() { return (_currentParentMenuTree == NULL); } + const char *GetParentMenuTitel(); +private: + cSubMenuNodes _menuTree; + cSubMenuNodes *_currentMenuTree; + cSubMenuNodes *_currentParentMenuTree; +#ifdef USE_PINPLUGIN + int _currentParentIndex; +#endif /* PINPLUGIN */ + char *_fname; + char *_commandResult; + int _nrNodes; + cSubMenuNode **_nodeArray; + char *_menuSuffix; + int countNodes(cSubMenuNodes *tree); + void tree2Array(cSubMenuNodes *tree, int &index); + void addMissingPlugins(); + void reloadNodeArray(); + void removeUndefinedNodes(); + }; + +#endif //__SUBMENU_H +#endif /* SETUP */ diff -ruNp vdr-1.6.0-2/svdrp.c vdr-1.6.0-2-extensions/svdrp.c --- vdr-1.6.0-2/svdrp.c 2008-09-11 13:29:43.000000000 +0200 +++ vdr-1.6.0-2-extensions/svdrp.c 2009-04-09 20:48:27.000000000 +0200 @@ -39,6 +39,9 @@ #include "timers.h" #include "tools.h" #include "videodir.h" +#ifdef USE_STREAMDEVEXT +#include "status.h" +#endif /* STREAMDEVEXT */ // --- cSocket --------------------------------------------------------------- @@ -296,6 +299,10 @@ const char *HelpPages[] = { "REMO [ on | off ]\n" " Turns the remote control on or off. Without a parameter, the current\n" " status of the remote control is reported.", +#ifdef USE_LIEMIEXT + "RENR \n" + " Rename recording. Number must be the Number as returned by LSTR command.", +#endif /* LIEMIEXT */ "SCAN\n" " Forces an EPG scan. If this is a single DVB device system, the scan\n" " will be done on the primary device unless it is currently recording.", @@ -616,6 +623,9 @@ void cSVDRP::CmdDELC(const char *Option) Channels.ReNumber(); Channels.SetModified(true); isyslog("channel %s deleted", Option); +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(NULL, scDel); +#endif /* STREAMDEVEXT */ if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) Channels.SwitchTo(CurrentChannel->Number()); @@ -1135,6 +1145,9 @@ void cSVDRP::CmdMODC(const char *Option) Channels.ReNumber(); Channels.SetModified(true); isyslog("modifed channel %d %s", channel->Number(), *channel->ToText()); +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(channel, scMod); +#endif /* STREAMDEVEXT */ Reply(250, "%d %s", channel->Number(), *channel->ToText()); } else @@ -1221,6 +1234,9 @@ void cSVDRP::CmdMOVC(const char *Option) else cDevice::SetCurrentChannel(CurrentChannel); } +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(ToChannel, scMod); +#endif /* STREAMDEVEXT */ isyslog("channel %d moved to %d", FromNumber, ToNumber); Reply(250,"Channel \"%d\" moved to \"%d\"", From, To); } @@ -1264,6 +1280,9 @@ void cSVDRP::CmdNEWC(const char *Option) Channels.ReNumber(); Channels.SetModified(true); isyslog("new channel %d %s", channel->Number(), *channel->ToText()); +#ifdef USE_STREAMDEVEXT + cStatus::MsgChannelChange(channel, scAdd); +#endif /* STREAMDEVEXT */ Reply(250, "%d %s", channel->Number(), *channel->ToText()); } else @@ -1472,6 +1491,40 @@ void cSVDRP::CmdSCAN(const char *Option) Reply(250, "EPG scan triggered"); } +#ifdef USE_LIEMIEXT +void cSVDRP::CmdRENR(const char *Option) +{ + bool recordings = Recordings.Update(true); + if (recordings) { + if (*Option) { + char *tail; + int n = strtol(Option, &tail, 10); + cRecording *recording = Recordings.Get(n - 1); + if (recording && tail && tail != Option) { + int priority = recording->priority; + int lifetime = recording->lifetime; + char *oldName = strdup(recording->Name()); + tail = skipspace(tail); + if (recording->Rename(tail, &priority, &lifetime)) { + Reply(250, "Renamed \"%s\" to \"%s\"", oldName, recording->Name()); + Recordings.ChangeState(); + Recordings.TouchUpdate(); + } + else + Reply(501, "Renaming \"%s\" to \"%s\" failed", oldName, tail); + free(oldName); + } + else + Reply(501, "Recording not found or wrong syntax"); + } + else + Reply(501, "Missing Input settings"); + } + else + Reply(550, "No recordings available"); +} +#endif /* LIEMIEXT */ + void cSVDRP::CmdSTAT(const char *Option) { if (*Option) { @@ -1587,6 +1640,9 @@ void cSVDRP::Execute(char *Cmd) else if (CMD("PLUG")) CmdPLUG(s); else if (CMD("PUTE")) CmdPUTE(s); else if (CMD("REMO")) CmdREMO(s); +#ifdef USE_LIEMIEXT + else if (CMD("RENR")) CmdRENR(s); +#endif /* LIEMIEXT */ else if (CMD("SCAN")) CmdSCAN(s); else if (CMD("STAT")) CmdSTAT(s); else if (CMD("UPDT")) CmdUPDT(s); diff -ruNp vdr-1.6.0-2/svdrp.h vdr-1.6.0-2-extensions/svdrp.h --- vdr-1.6.0-2/svdrp.h 2007-04-30 14:28:28.000000000 +0200 +++ vdr-1.6.0-2-extensions/svdrp.h 2009-04-09 20:48:27.000000000 +0200 @@ -79,6 +79,9 @@ private: void CmdPLUG(const char *Option); void CmdPUTE(const char *Option); void CmdREMO(const char *Option); +#ifdef USE_LIEMIEXT + void CmdRENR(const char *Option); +#endif /* LIEMIEXT */ void CmdSCAN(const char *Option); void CmdSTAT(const char *Option); void CmdUPDT(const char *Option); diff -ruNp vdr-1.6.0-2/timers.c vdr-1.6.0-2-extensions/timers.c --- vdr-1.6.0-2/timers.c 2008-09-11 13:29:39.000000000 +0200 +++ vdr-1.6.0-2-extensions/timers.c 2009-04-09 20:48:27.000000000 +0200 @@ -13,6 +13,9 @@ #include "device.h" #include "i18n.h" #include "libsi/si.h" +#ifdef USE_LIVEBUFFER +#include "livebuffer.h" +#endif /* LIVEBUFFER */ #include "recording.h" #include "remote.h" #include "status.h" @@ -46,6 +49,9 @@ cTimer::cTimer(bool Instant, bool Pause, stop -= 2400; priority = Pause ? Setup.PausePriority : Setup.DefaultPriority; lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime; +#ifdef USE_PINPLUGIN + fskProtection = 0; +#endif /* PINPLUGIN */ *file = 0; aux = NULL; event = NULL; @@ -79,12 +85,18 @@ cTimer::cTimer(const cEvent *Event) stop -= 2400; priority = Setup.DefaultPriority; lifetime = Setup.DefaultLifetime; +#ifdef USE_PINPLUGIN + fskProtection = 0; +#endif /* PINPLUGIN */ *file = 0; const char *Title = Event->Title(); if (!isempty(Title)) Utf8Strn0Cpy(file, Event->Title(), sizeof(file)); aux = NULL; event = NULL; // let SetEvent() be called to get a log message +#ifdef USE_PINPLUGIN + cStatus::MsgTimerCreation(this, Event); +#endif /* PINPLUGIN */ } cTimer::cTimer(const cTimer &Timer) @@ -119,6 +131,9 @@ cTimer& cTimer::operator= (const cTimer stop = Timer.stop; priority = Timer.priority; lifetime = Timer.lifetime; +#ifdef USE_PINPLUGIN + fskProtection = Timer.fskProtection; +#endif /* PINPLUGIN */ strncpy(file, Timer.file, sizeof(file)); free(aux); aux = Timer.aux ? strdup(Timer.aux) : NULL; @@ -313,6 +328,9 @@ bool cTimer::Parse(const char *s) result = false; } } +#ifdef USE_PINPLUGIN + fskProtection = aux && strstr(aux, "yes"); +#endif /* PINPLUGIN */ free(channelbuffer); free(daybuffer); free(filebuffer); @@ -559,6 +577,9 @@ void cTimer::SetRecording(bool Recording SetFlags(tfRecording); else ClrFlags(tfRecording); +#ifdef USE_STREAMDEVEXT + cStatus::MsgRecordingChange(NULL, scAdd); +#endif /* STREAMDEVEXT */ isyslog("timer %s %s", *ToDescr(), recording ? "start" : "stop"); } @@ -622,6 +643,35 @@ void cTimer::OnOff(void) Matches(); // refresh start and end time } +#ifdef USE_PINPLUGIN +void cTimer::SetFskProtection(int aFlag) +{ + char* p; + char* tmp = 0; + + fskProtection = aFlag; + + if (fskProtection && (!aux || !strstr(aux, "yes"))) + { + // add protection info to aux + + if (aux) { tmp = strdup(aux); free(aux); } + asprintf(&aux,"%syes", tmp ? tmp : ""); + } + else if (!fskProtection && aux && (p = strstr(aux, "yes"))) + { + // remove protection info to aux + + asprintf(&tmp, "%.*s%s", p-aux, aux, p+strlen("yes")); + free(aux); + aux = strdup(tmp); + } + + if (tmp) + free(tmp); +} +#endif /* PINPLUGIN */ + // --- cTimers --------------------------------------------------------------- cTimers Timers; @@ -651,7 +701,11 @@ cTimer *cTimers::GetMatch(time_t t) static int LastPending = -1; cTimer *t0 = NULL; for (cTimer *ti = First(); ti; ti = Next(ti)) { +#ifdef USE_LIVEBUFFER + if (!ti->Recording() && (ti->Matches(t) || cLiveBufferManager::InLiveBuffer(ti))) { +#else if (!ti->Recording() && ti->Matches(t)) { +#endif /* LIVEBUFFER */ if (ti->Pending()) { if (ti->Index() > LastPending) LastPending = ti->Index(); @@ -752,7 +806,11 @@ void cTimers::DeleteExpired(void) cTimer *ti = First(); while (ti) { cTimer *next = Next(ti); +#ifdef USE_LIVEBUFFER + if (ti->Expired() && (!cLiveBufferManager::InLiveBuffer(ti) || !ti->HasFlags(tfActive))) { +#else if (ti->Expired()) { +#endif /* LIVEBUFFER */ isyslog("deleting timer %s", *ti->ToDescr()); Del(ti); SetModified(); diff -ruNp vdr-1.6.0-2/timers.h vdr-1.6.0-2-extensions/timers.h --- vdr-1.6.0-2/timers.h 2008-02-16 15:33:23.000000000 +0100 +++ vdr-1.6.0-2-extensions/timers.h 2009-04-09 20:48:27.000000000 +0200 @@ -20,12 +20,18 @@ enum eTimerFlags { tfNone = 0x0000, tfInstant = 0x0002, tfVps = 0x0004, tfRecording = 0x0008, +#ifdef USE_LIVEBUFFER + tfhasLiveBuf= 0x0010, +#endif /* LIVEBUFFER */ tfAll = 0xFFFF, }; enum eTimerMatch { tmNone, tmPartial, tmFull }; class cTimer : public cListObject { friend class cMenuEditTimer; +#ifdef USE_LIVEBUFFER + friend class cLiveBufferControl; +#endif /* LIVEBUFFER */ private: mutable time_t startTime, stopTime; time_t lastSetEvent; @@ -37,6 +43,9 @@ private: int start; int stop; int priority; +#ifdef USE_PINPLUGIN + int fskProtection; +#endif /* PINPLUGIN */ int lifetime; mutable char file[MaxFileName]; char *aux; @@ -58,6 +67,9 @@ public: int Start(void) const { return start; } int Stop(void) const { return stop; } int Priority(void) const { return priority; } +#ifdef USE_PINPLUGIN + int FskProtection(void) const { return fskProtection; } +#endif /* PINPLUGIN */ int Lifetime(void) const { return lifetime; } const char *File(void) const { return file; } time_t FirstDay(void) const { return weekdays ? day : 0; } @@ -86,6 +98,9 @@ public: void SetInVpsMargin(bool InVpsMargin); void SetPriority(int Priority); void SetFlags(uint Flags); +#ifdef USE_PINPLUGIN + void SetFskProtection(int aFlag); +#endif /* PINPLUGIN */ void ClrFlags(uint Flags); void InvFlags(uint Flags); bool HasFlags(uint Flags) const; diff -ruNp vdr-1.6.0-2/tinystr.c vdr-1.6.0-2-extensions/tinystr.c --- vdr-1.6.0-2/tinystr.c 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/tinystr.c 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,301 @@ +#ifdef USE_SETUP +/* +www.sourceforge.net/projects/tinyxml +Original file by Yves Berquin. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml.h" + +#ifndef TIXML_USE_STL + + +#include +#include +#include + +#include "tinystr.h" + +// TiXmlString constructor, based on a C string +TiXmlString::TiXmlString (const char* instring) +{ + unsigned newlen; + char * newstring; + + if (!instring) + { + allocated = 0; + cstring = NULL; + current_length = 0; + return; + } + newlen = strlen (instring) + 1; + newstring = new char [newlen]; + memcpy (newstring, instring, newlen); + // strcpy (newstring, instring); + allocated = newlen; + cstring = newstring; + current_length = newlen - 1; +} + +// TiXmlString copy constructor +TiXmlString::TiXmlString (const TiXmlString& copy) +{ + unsigned newlen; + char * newstring; + + // Prevent copy to self! + if ( © == this ) + return; + + if (! copy . allocated) + { + allocated = 0; + cstring = NULL; + current_length = 0; + return; + } + newlen = copy . length () + 1; + newstring = new char [newlen]; + // strcpy (newstring, copy . cstring); + memcpy (newstring, copy . cstring, newlen); + allocated = newlen; + cstring = newstring; + current_length = newlen - 1; +} + +// TiXmlString = operator. Safe when assign own content +void TiXmlString ::operator = (const char * content) +{ + unsigned newlen; + char * newstring; + + if (! content) + { + empty_it (); + return; + } + newlen = strlen (content) + 1; + newstring = new char [newlen]; + // strcpy (newstring, content); + memcpy (newstring, content, newlen); + empty_it (); + allocated = newlen; + cstring = newstring; + current_length = newlen - 1; +} + +// = operator. Safe when assign own content +void TiXmlString ::operator = (const TiXmlString & copy) +{ + unsigned newlen; + char * newstring; + + if (! copy . length ()) + { + empty_it (); + return; + } + newlen = copy . length () + 1; + newstring = new char [newlen]; + // strcpy (newstring, copy . c_str ()); + memcpy (newstring, copy . c_str (), newlen); + empty_it (); + allocated = newlen; + cstring = newstring; + current_length = newlen - 1; +} + + +// append a const char * to an existing TiXmlString +void TiXmlString::append( const char* str, int len ) +{ + char * new_string; + unsigned new_alloc, new_size, size_suffix; + + // don't use strlen - it can overrun the len passed in! + const char* p = str; + size_suffix = 0; + + while ( *p && size_suffix < (unsigned)len ) + { + ++p; + ++size_suffix; + } + if ( !size_suffix) + return; + + new_size = length () + size_suffix + 1; + // check if we need to expand + if (new_size > allocated) + { + // compute new size + new_alloc = assign_new_size (new_size); + + // allocate new buffer + new_string = new char [new_alloc]; + new_string [0] = 0; + + // copy the previous allocated buffer into this one + if (allocated && cstring) + // strcpy (new_string, cstring); + memcpy (new_string, cstring, length ()); + + // append the suffix. It does exist, otherwize we wouldn't be expanding + // strncat (new_string, str, len); + memcpy (new_string + length (), + str, + size_suffix); + + // return previsously allocated buffer if any + if (allocated && cstring) + delete [] cstring; + + // update member variables + cstring = new_string; + allocated = new_alloc; + } + else + { + // we know we can safely append the new string + // strncat (cstring, str, len); + memcpy (cstring + length (), + str, + size_suffix); + } + current_length = new_size - 1; + cstring [current_length] = 0; +} + + +// append a const char * to an existing TiXmlString +void TiXmlString::append( const char * suffix ) +{ + char * new_string; + unsigned new_alloc, new_size; + + new_size = length () + strlen (suffix) + 1; + // check if we need to expand + if (new_size > allocated) + { + // compute new size + new_alloc = assign_new_size (new_size); + + // allocate new buffer + new_string = new char [new_alloc]; + new_string [0] = 0; + + // copy the previous allocated buffer into this one + if (allocated && cstring) + memcpy (new_string, cstring, 1 + length ()); + // strcpy (new_string, cstring); + + // append the suffix. It does exist, otherwize we wouldn't be expanding + // strcat (new_string, suffix); + memcpy (new_string + length (), + suffix, + strlen (suffix) + 1); + + // return previsously allocated buffer if any + if (allocated && cstring) + delete [] cstring; + + // update member variables + cstring = new_string; + allocated = new_alloc; + } + else + { + // we know we can safely append the new string + // strcat (cstring, suffix); + memcpy (cstring + length (), + suffix, + strlen (suffix) + 1); + } + current_length = new_size - 1; +} + +// Check for TiXmlString equuivalence +//bool TiXmlString::operator == (const TiXmlString & compare) const +//{ +// return (! strcmp (c_str (), compare . c_str ())); +//} + +//unsigned TiXmlString::length () const +//{ +// if (allocated) +// // return strlen (cstring); +// return current_length; +// return 0; +//} + + +unsigned TiXmlString::find (char tofind, unsigned offset) const +{ + char * lookup; + + if (offset >= length ()) + return (unsigned) notfound; + for (lookup = cstring + offset; * lookup; lookup++) + if (* lookup == tofind) + return lookup - cstring; + return (unsigned) notfound; +} + + +bool TiXmlString::operator == (const TiXmlString & compare) const +{ + if ( allocated && compare.allocated ) + { + assert( cstring ); + assert( compare.cstring ); + return ( strcmp( cstring, compare.cstring ) == 0 ); + } + return false; +} + + +bool TiXmlString::operator < (const TiXmlString & compare) const +{ + if ( allocated && compare.allocated ) + { + assert( cstring ); + assert( compare.cstring ); + return ( strcmp( cstring, compare.cstring ) > 0 ); + } + return false; +} + + +bool TiXmlString::operator > (const TiXmlString & compare) const +{ + if ( allocated && compare.allocated ) + { + assert( cstring ); + assert( compare.cstring ); + return ( strcmp( cstring, compare.cstring ) < 0 ); + } + return false; +} + + +#endif // TIXML_USE_STL +#endif /* SETUP */ diff -ruNp vdr-1.6.0-2/tinystr.h vdr-1.6.0-2-extensions/tinystr.h --- vdr-1.6.0-2/tinystr.h 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/tinystr.h 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,244 @@ +#ifdef USE_SETUP +/* +www.sourceforge.net/projects/tinyxml +Original file by Yves Berquin. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml.h" + + +#ifndef TIXML_USE_STL + +#ifndef TIXML_STRING_INCLUDED +#define TIXML_STRING_INCLUDED + +#ifdef _MSC_VER +#pragma warning( disable : 4786 ) // Debugger truncating names. +#endif + +#include + +/* + TiXmlString is an emulation of the std::string template. + Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. + Only the member functions relevant to the TinyXML project have been implemented. + The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase + a string and there's no more room, we allocate a buffer twice as big as we need. +*/ +class TiXmlString +{ + public : + // TiXmlString constructor, based on a string + TiXmlString (const char * instring); + + // TiXmlString empty constructor + TiXmlString () + { + allocated = 0; + cstring = NULL; + current_length = 0; + } + + // TiXmlString copy constructor + TiXmlString (const TiXmlString& copy); + + // TiXmlString destructor + ~ TiXmlString () + { + empty_it (); + } + + // Convert a TiXmlString into a classical char * + const char * c_str () const + { + if (allocated) + return cstring; + return ""; + } + + // Return the length of a TiXmlString + unsigned length () const + { + return ( allocated ) ? current_length : 0; + } + + // TiXmlString = operator + void operator = (const char * content); + + // = operator + void operator = (const TiXmlString & copy); + + // += operator. Maps to append + TiXmlString& operator += (const char * suffix) + { + append (suffix); + return *this; + } + + // += operator. Maps to append + TiXmlString& operator += (char single) + { + append (single); + return *this; + } + + // += operator. Maps to append + TiXmlString& operator += (TiXmlString & suffix) + { + append (suffix); + return *this; + } + bool operator == (const TiXmlString & compare) const; + bool operator < (const TiXmlString & compare) const; + bool operator > (const TiXmlString & compare) const; + + // Checks if a TiXmlString is empty + bool empty () const + { + return length () ? false : true; + } + + // single char extraction + const char& at (unsigned index) const + { + assert( index < length ()); + return cstring [index]; + } + + // find a char in a string. Return TiXmlString::notfound if not found + unsigned find (char lookup) const + { + return find (lookup, 0); + } + + // find a char in a string from an offset. Return TiXmlString::notfound if not found + unsigned find (char tofind, unsigned offset) const; + + /* Function to reserve a big amount of data when we know we'll need it. Be aware that this + function clears the content of the TiXmlString if any exists. + */ + void reserve (unsigned size) + { + empty_it (); + if (size) + { + allocated = size; + cstring = new char [size]; + cstring [0] = 0; + current_length = 0; + } + } + + // [] operator + char& operator [] (unsigned index) const + { + assert( index < length ()); + return cstring [index]; + } + + // Error value for find primitive + enum { notfound = 0xffffffff, + npos = notfound }; + + void append (const char *str, int len ); + + protected : + + // The base string + char * cstring; + // Number of chars allocated + unsigned allocated; + // Current string size + unsigned current_length; + + // New size computation. It is simplistic right now : it returns twice the amount + // we need + unsigned assign_new_size (unsigned minimum_to_allocate) + { + return minimum_to_allocate * 2; + } + + // Internal function that clears the content of a TiXmlString + void empty_it () + { + if (cstring) + delete [] cstring; + cstring = NULL; + allocated = 0; + current_length = 0; + } + + void append (const char *suffix ); + + // append function for another TiXmlString + void append (const TiXmlString & suffix) + { + append (suffix . c_str ()); + } + + // append for a single char. + void append (char single) + { + if ( cstring && current_length < (allocated-1) ) + { + cstring[ current_length ] = single; + ++current_length; + cstring[ current_length ] = 0; + } + else + { + char smallstr [2]; + smallstr [0] = single; + smallstr [1] = 0; + append (smallstr); + } + } + +} ; + +/* + TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. + Only the operators that we need for TinyXML have been developped. +*/ +class TiXmlOutStream : public TiXmlString +{ +public : + TiXmlOutStream () : TiXmlString () {} + + // TiXmlOutStream << operator. Maps to TiXmlString::append + TiXmlOutStream & operator << (const char * in) + { + append (in); + return (* this); + } + + // TiXmlOutStream << operator. Maps to TiXmlString::append + TiXmlOutStream & operator << (const TiXmlString & in) + { + append (in . c_str ()); + return (* this); + } +} ; + +#endif // TIXML_STRING_INCLUDED +#endif // TIXML_USE_STL +#endif /* SETUP */ diff -ruNp vdr-1.6.0-2/tinyxml.c vdr-1.6.0-2-extensions/tinyxml.c --- vdr-1.6.0-2/tinyxml.c 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/tinyxml.c 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,1429 @@ +#ifdef USE_SETUP +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include +#include "tinyxml.h" + +#ifdef TIXML_USE_STL +#include +#endif + + +bool TiXmlBase::condenseWhiteSpace = true; + +void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_OSTREAM* stream ) +{ + TIXML_STRING buffer; + PutString( str, &buffer ); + (*stream) << buffer; +} + +void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString ) +{ + int i=0; + + while( i<(int)str.length() ) + { + unsigned char c = (unsigned char) str[i]; + + if ( c == '&' + && i < ( (int)str.length() - 2 ) + && str[i+1] == '#' + && str[i+2] == 'x' ) + { + // Hexadecimal character reference. + // Pass through unchanged. + // © -- copyright symbol, for example. + // + // The -1 is a bug fix from Rob Laveaux. It keeps + // an overflow from happening if there is no ';'. + // There are actually 2 ways to exit this loop - + // while fails (error case) and break (semicolon found). + // However, there is no mechanism (currently) for + // this function to return an error. + while ( i<(int)str.length()-1 ) + { + outString->append( str.c_str() + i, 1 ); + ++i; + if ( str[i] == ';' ) + break; + } + } + else if ( c == '&' ) + { + outString->append( entity[0].str, entity[0].strLength ); + ++i; + } + else if ( c == '<' ) + { + outString->append( entity[1].str, entity[1].strLength ); + ++i; + } + else if ( c == '>' ) + { + outString->append( entity[2].str, entity[2].strLength ); + ++i; + } + else if ( c == '\"' ) + { + outString->append( entity[3].str, entity[3].strLength ); + ++i; + } + else if ( c == '\'' ) + { + outString->append( entity[4].str, entity[4].strLength ); + ++i; + } + else if ( c < 32 ) + { + // Easy pass at non-alpha/numeric/symbol + // Below 32 is symbolic. + char buf[ 32 ]; + sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); + outString->append( buf, strlen( buf ) ); + ++i; + } + else + { + //char realc = (char) c; + //outString->append( &realc, 1 ); + *outString += (char) c; // somewhat more efficient function call. + ++i; + } + } +} + + +// <-- Strange class for a bug fix. Search for STL_STRING_BUG +TiXmlBase::StringToBuffer::StringToBuffer( const TIXML_STRING& str ) +{ + buffer = new char[ str.length()+1 ]; + if ( buffer ) + { + strcpy( buffer, str.c_str() ); + } +} + + +TiXmlBase::StringToBuffer::~StringToBuffer() +{ + delete [] buffer; +} +// End strange bug fix. --> + + +TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() +{ + parent = 0; + type = _type; + firstChild = 0; + lastChild = 0; + prev = 0; + next = 0; +} + + +TiXmlNode::~TiXmlNode() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } +} + + +void TiXmlNode::CopyTo( TiXmlNode* target ) const +{ + target->SetValue (value.c_str() ); + target->userData = userData; +} + + +void TiXmlNode::Clear() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } + + firstChild = 0; + lastChild = 0; +} + + +TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) +{ + node->parent = this; + + node->prev = lastChild; + node->next = 0; + + if ( lastChild ) + lastChild->next = node; + else + firstChild = node; // it was an empty list. + + lastChild = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) +{ + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + + return LinkEndChild( node ); +} + + +TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) +{ + if ( !beforeThis || beforeThis->parent != this ) + return 0; + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->next = beforeThis; + node->prev = beforeThis->prev; + if ( beforeThis->prev ) + { + beforeThis->prev->next = node; + } + else + { + assert( firstChild == beforeThis ); + firstChild = node; + } + beforeThis->prev = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) +{ + if ( !afterThis || afterThis->parent != this ) + return 0; + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->prev = afterThis; + node->next = afterThis->next; + if ( afterThis->next ) + { + afterThis->next->prev = node; + } + else + { + assert( lastChild == afterThis ); + lastChild = node; + } + afterThis->next = node; + return node; +} + + +TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) +{ + if ( replaceThis->parent != this ) + return 0; + + TiXmlNode* node = withThis.Clone(); + if ( !node ) + return 0; + + node->next = replaceThis->next; + node->prev = replaceThis->prev; + + if ( replaceThis->next ) + replaceThis->next->prev = node; + else + lastChild = node; + + if ( replaceThis->prev ) + replaceThis->prev->next = node; + else + firstChild = node; + + delete replaceThis; + node->parent = this; + return node; +} + + +bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) +{ + if ( removeThis->parent != this ) + { + assert( 0 ); + return false; + } + + if ( removeThis->next ) + removeThis->next->prev = removeThis->prev; + else + lastChild = removeThis->prev; + + if ( removeThis->prev ) + removeThis->prev->next = removeThis->next; + else + firstChild = removeThis->next; + + delete removeThis; + return true; +} + +TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const +{ + TiXmlNode* node; + for ( node = firstChild; node; node = node->next ) + { + if ( node->SValue() == TIXML_STRING( _value )) + return node; + } + return 0; +} + +TiXmlNode* TiXmlNode::LastChild( const char * _value ) const +{ + TiXmlNode* node; + for ( node = lastChild; node; node = node->prev ) + { + if ( node->SValue() == TIXML_STRING (_value)) + return node; + } + return 0; +} + +TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild(); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling(); + } +} + +TiXmlNode* TiXmlNode::IterateChildren( const char * val, TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild( val ); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling( val ); + } +} + +TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const +{ + TiXmlNode* node; + for ( node = next; node; node = node->next ) + { + if ( node->SValue() == TIXML_STRING (_value)) + return node; + } + return 0; +} + + +TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const +{ + TiXmlNode* node; + for ( node = prev; node; node = node->prev ) + { + if ( node->SValue() == TIXML_STRING (_value)) + return node; + } + return 0; +} + +void TiXmlElement::RemoveAttribute( const char * name ) +{ + TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + { + attributeSet.Remove( node ); + delete node; + } +} + +TiXmlElement* TiXmlNode::FirstChildElement() const +{ + TiXmlNode* node; + + for ( node = FirstChild(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + +TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const +{ + TiXmlNode* node; + + for ( node = FirstChild( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +TiXmlElement* TiXmlNode::NextSiblingElement() const +{ + TiXmlNode* node; + + for ( node = NextSibling(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + +TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const +{ + TiXmlNode* node; + + for ( node = NextSibling( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + + +TiXmlDocument* TiXmlNode::GetDocument() const +{ + const TiXmlNode* node; + + for( node = this; node; node = node->parent ) + { + if ( node->ToDocument() ) + return node->ToDocument(); + } + return 0; +} + + +TiXmlElement::TiXmlElement (const char * _value) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} + + +#ifdef TIXML_USE_STL +TiXmlElement::TiXmlElement( const std::string& _value ) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} +#endif + + +TiXmlElement::TiXmlElement( const TiXmlElement& copy) + : TiXmlNode( TiXmlNode::ELEMENT ) +{ + firstChild = lastChild = 0; + copy.CopyTo( this ); +} + + +void TiXmlElement::operator=( const TiXmlElement& base ) +{ + ClearThis(); + base.CopyTo( this ); +} + + +TiXmlElement::~TiXmlElement() +{ + ClearThis(); +} + + +void TiXmlElement::ClearThis() +{ + Clear(); + while( attributeSet.First() ) + { + TiXmlAttribute* node = attributeSet.First(); + attributeSet.Remove( node ); + delete node; + } +} + + +const char * TiXmlElement::Attribute( const char * name ) const +{ + TiXmlAttribute* node = attributeSet.Find( name ); + + if ( node ) + return node->Value(); + + return 0; +} + + +const char * TiXmlElement::Attribute( const char * name, int* i ) const +{ + const char * s = Attribute( name ); + if ( i ) + { + if ( s ) + *i = atoi( s ); + else + *i = 0; + } + return s; +} + + +const char * TiXmlElement::Attribute( const char * name, double* d ) const +{ + const char * s = Attribute( name ); + if ( d ) + { + if ( s ) + *d = atof( s ); + else + *d = 0; + } + return s; +} + + +int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const +{ + TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + return node->QueryIntValue( ival ); +} + + +int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const +{ + TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + return node->QueryDoubleValue( dval ); +} + + +void TiXmlElement::SetAttribute( const char * name, int val ) +{ + char buf[64]; + sprintf( buf, "%d", val ); + SetAttribute( name, buf ); +} + + +void TiXmlElement::SetDoubleAttribute( const char * name, double val ) +{ + char buf[128]; + sprintf( buf, "%f", val ); + SetAttribute( name, buf ); +} + + +void TiXmlElement::SetAttribute( const char * name, const char * _value ) +{ + TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + { + node->SetValue( _value ); + return; + } + + TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); + if ( attrib ) + { + attributeSet.Add( attrib ); + } + else + { + TiXmlDocument* document = GetDocument(); + if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); + } +} + +void TiXmlElement::Print( FILE* cfile, int depth ) const +{ + int i; + for ( i=0; iNext() ) + { + fprintf( cfile, " " ); + attrib->Print( cfile, depth ); + } + + // There are 3 different formatting approaches: + // 1) An element without children is printed as a node + // 2) An element with only a text child is printed as text + // 3) An element with children is printed on multiple lines. + TiXmlNode* node; + if ( !firstChild ) + { + fprintf( cfile, " />" ); + } + else if ( firstChild == lastChild && firstChild->ToText() ) + { + fprintf( cfile, ">" ); + firstChild->Print( cfile, depth + 1 ); + fprintf( cfile, "", value.c_str() ); + } + else + { + fprintf( cfile, ">" ); + + for ( node = firstChild; node; node=node->NextSibling() ) + { + if ( !node->ToText() ) + { + fprintf( cfile, "\n" ); + } + node->Print( cfile, depth+1 ); + } + fprintf( cfile, "\n" ); + for( i=0; i", value.c_str() ); + } +} + +void TiXmlElement::StreamOut( TIXML_OSTREAM * stream ) const +{ + (*stream) << "<" << value; + + TiXmlAttribute* attrib; + for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) + { + (*stream) << " "; + attrib->StreamOut( stream ); + } + + // If this node has children, give it a closing tag. Else + // make it an empty tag. + TiXmlNode* node; + if ( firstChild ) + { + (*stream) << ">"; + + for ( node = firstChild; node; node=node->NextSibling() ) + { + node->StreamOut( stream ); + } + (*stream) << ""; + } + else + { + (*stream) << " />"; + } +} + + +void TiXmlElement::CopyTo( TiXmlElement* target ) const +{ + // superclass: + TiXmlNode::CopyTo( target ); + + // Element class: + // Clone the attributes, then clone the children. + TiXmlAttribute* attribute = 0; + for( attribute = attributeSet.First(); + attribute; + attribute = attribute->Next() ) + { + target->SetAttribute( attribute->Name(), attribute->Value() ); + } + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + + +TiXmlNode* TiXmlElement::Clone() const +{ + TiXmlElement* clone = new TiXmlElement( Value() ); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + ClearError(); +} + +TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + value = documentName; + ClearError(); +} + + +#ifdef TIXML_USE_STL +TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + tabsize = 4; + value = documentName; + ClearError(); +} +#endif + + +TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDocument::operator=( const TiXmlDocument& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) +{ + // See STL_STRING_BUG below. + StringToBuffer buf( value ); + + if ( buf.buffer && LoadFile( buf.buffer, encoding ) ) + return true; + + return false; +} + + +bool TiXmlDocument::SaveFile() const +{ + // See STL_STRING_BUG below. + StringToBuffer buf( value ); + + if ( buf.buffer && SaveFile( buf.buffer ) ) + return true; + + return false; +} + +bool TiXmlDocument::LoadFile( const char* filename, TiXmlEncoding encoding ) +{ + // Delete the existing data: + Clear(); + location.Clear(); + + // There was a really terrifying little bug here. The code: + // value = filename + // in the STL case, cause the assignment method of the std::string to + // be called. What is strange, is that the std::string had the same + // address as it's c_str() method, and so bad things happen. Looks + // like a bug in the Microsoft STL implementation. + // See STL_STRING_BUG above. + // Fixed with the StringToBuffer class. + value = filename; + + FILE* file = fopen( value.c_str (), "r" ); + + if ( file ) + { + // Get the file size, so we can pre-allocate the string. HUGE speed impact. + long length = 0; + fseek( file, 0, SEEK_END ); + length = ftell( file ); + fseek( file, 0, SEEK_SET ); + + // Strange case, but good to handle up front. + if ( length == 0 ) + { + fclose( file ); + return false; + } + + // If we have a file, assume it is all one big XML file, and read it in. + // The document parser may decide the document ends sooner than the entire file, however. + TIXML_STRING data; + data.reserve( length ); + + const int BUF_SIZE = 2048; + char buf[BUF_SIZE]; + + while( fgets( buf, BUF_SIZE, file ) ) + { + data += buf; + } + fclose( file ); + + Parse( data.c_str(), 0, encoding ); + + if ( Error() ) + return false; + else + return true; + } + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; +} + +bool TiXmlDocument::SaveFile( const char * filename ) const +{ + // The old c stuff lives on... + FILE* fp = fopen( filename, "w" ); + if ( fp ) + { + Print( fp, 0 ); + fclose( fp ); + return true; + } + return false; +} + + +void TiXmlDocument::CopyTo( TiXmlDocument* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->error = error; + target->errorDesc = errorDesc.c_str (); + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + + +TiXmlNode* TiXmlDocument::Clone() const +{ + TiXmlDocument* clone = new TiXmlDocument(); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlDocument::Print( FILE* cfile, int depth ) const +{ + TiXmlNode* node; + for ( node=FirstChild(); node; node=node->NextSibling() ) + { + node->Print( cfile, depth ); + fprintf( cfile, "\n" ); + } +} + +void TiXmlDocument::StreamOut( TIXML_OSTREAM * out ) const +{ + TiXmlNode* node; + for ( node=FirstChild(); node; node=node->NextSibling() ) + { + node->StreamOut( out ); + + // Special rule for streams: stop after the root element. + // The stream in code will only read one element, so don't + // write more than one. + if ( node->ToElement() ) + break; + } +} + + +TiXmlAttribute* TiXmlAttribute::Next() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} + + +TiXmlAttribute* TiXmlAttribute::Previous() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} + + +void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const +{ + TIXML_STRING n, v; + + PutString( name, &n ); + PutString( value, &v ); + + if (value.find ('\"') == TIXML_STRING::npos) + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + else + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); +} + + +void TiXmlAttribute::StreamOut( TIXML_OSTREAM * stream ) const +{ + if (value.find( '\"' ) != TIXML_STRING::npos) + { + PutString( name, stream ); + (*stream) << "=" << "'"; + PutString( value, stream ); + (*stream) << "'"; + } + else + { + PutString( name, stream ); + (*stream) << "=" << "\""; + PutString( value, stream ); + (*stream) << "\""; + } +} + +int TiXmlAttribute::QueryIntValue( int* ival ) const +{ + if ( sscanf( value.c_str(), "%d", ival ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +int TiXmlAttribute::QueryDoubleValue( double* dval ) const +{ + if ( sscanf( value.c_str(), "%lf", dval ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +void TiXmlAttribute::SetIntValue( int _value ) +{ + char buf [64]; + sprintf (buf, "%d", _value); + SetValue (buf); +} + +void TiXmlAttribute::SetDoubleValue( double _value ) +{ + char buf [64]; + sprintf (buf, "%lf", _value); + SetValue (buf); +} + +const int TiXmlAttribute::IntValue() const +{ + return atoi (value.c_str ()); +} + +const double TiXmlAttribute::DoubleValue() const +{ + return atof (value.c_str ()); +} + + +TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) +{ + copy.CopyTo( this ); +} + + +void TiXmlComment::operator=( const TiXmlComment& base ) +{ + Clear(); + base.CopyTo( this ); +} + + +void TiXmlComment::Print( FILE* cfile, int depth ) const +{ + for ( int i=0; i", value.c_str() ); +} + +void TiXmlComment::StreamOut( TIXML_OSTREAM * stream ) const +{ + (*stream) << ""; +} + + +void TiXmlComment::CopyTo( TiXmlComment* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +TiXmlNode* TiXmlComment::Clone() const +{ + TiXmlComment* clone = new TiXmlComment(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlText::Print( FILE* cfile, int /*depth*/ ) const +{ + TIXML_STRING buffer; + PutString( value, &buffer ); + fprintf( cfile, "%s", buffer.c_str() ); +} + + +void TiXmlText::StreamOut( TIXML_OSTREAM * stream ) const +{ + PutString( value, stream ); +} + + +void TiXmlText::CopyTo( TiXmlText* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +TiXmlNode* TiXmlText::Clone() const +{ + TiXmlText* clone = 0; + clone = new TiXmlText( "" ); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlDeclaration::TiXmlDeclaration( const char * _version, + const char * _encoding, + const char * _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} + + +#ifdef TIXML_USE_STL +TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} +#endif + + +TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) + : TiXmlNode( TiXmlNode::DECLARATION ) +{ + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) +{ + Clear(); + copy.CopyTo( this ); +} + + +void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/ ) const +{ + fprintf (cfile, ""); +} + +void TiXmlDeclaration::StreamOut( TIXML_OSTREAM * stream ) const +{ + (*stream) << ""; +} + + +void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->version = version; + target->encoding = encoding; + target->standalone = standalone; +} + + +TiXmlNode* TiXmlDeclaration::Clone() const +{ + TiXmlDeclaration* clone = new TiXmlDeclaration(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlUnknown::Print( FILE* cfile, int depth ) const +{ + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlUnknown::StreamOut( TIXML_OSTREAM * stream ) const +{ + (*stream) << "<" << value << ">"; // Don't use entities here! It is unknown. +} + + +void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +TiXmlNode* TiXmlUnknown::Clone() const +{ + TiXmlUnknown* clone = new TiXmlUnknown(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlAttributeSet::TiXmlAttributeSet() +{ + sentinel.next = &sentinel; + sentinel.prev = &sentinel; +} + + +TiXmlAttributeSet::~TiXmlAttributeSet() +{ + assert( sentinel.next == &sentinel ); + assert( sentinel.prev == &sentinel ); +} + + +void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) +{ + assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. + + addMe->next = &sentinel; + addMe->prev = sentinel.prev; + + sentinel.prev->next = addMe; + sentinel.prev = addMe; +} + +void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) +{ + TiXmlAttribute* node; + + for( node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node == removeMe ) + { + node->prev->next = node->next; + node->next->prev = node->prev; + node->next = 0; + node->prev = 0; + return; + } + } + assert( 0 ); // we tried to remove a non-linked attribute. +} + +TiXmlAttribute* TiXmlAttributeSet::Find( const char * name ) const +{ + TiXmlAttribute* node; + + for( node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} + + +#ifdef TIXML_USE_STL +TIXML_ISTREAM & operator >> (TIXML_ISTREAM & in, TiXmlNode & base) +{ + TIXML_STRING tag; + tag.reserve( 8 * 1000 ); + base.StreamIn( &in, &tag ); + + base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); + return in; +} +#endif + + +TIXML_OSTREAM & operator<< (TIXML_OSTREAM & out, const TiXmlNode & base) +{ + base.StreamOut (& out); + return out; +} + + +#ifdef TIXML_USE_STL +std::string & operator<< (std::string& out, const TiXmlNode& base ) +{ + std::ostringstream os_stream( std::ostringstream::out ); + base.StreamOut( &os_stream ); + + out.append( os_stream.str() ); + return out; +} +#endif + + +TiXmlHandle TiXmlHandle::FirstChild() const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement() const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild(); + for ( i=0; + child && iNextSibling(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild( value ); + for ( i=0; + child && iNextSibling( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement(); + for ( i=0; + child && iNextSiblingElement(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement( value ); + for ( i=0; + child && iNextSiblingElement( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} +#endif /* SETUP */ diff -ruNp vdr-1.6.0-2/tinyxmlerror.c vdr-1.6.0-2-extensions/tinyxmlerror.c --- vdr-1.6.0-2/tinyxmlerror.c 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/tinyxmlerror.c 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,53 @@ +#ifdef USE_SETUP +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml.h" + +// The goal of the seperate error file is to make the first +// step towards localization. tinyxml (currently) only supports +// latin-1, but at least the error messages could now be translated. +// +// It also cleans up the code a bit. +// + +const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] = +{ + "No error", + "Error", + "Failed to open file", + "Memory allocation failed.", + "Error parsing Element.", + "Failed to read Element name", + "Error reading Element value.", + "Error reading Attributes.", + "Error: empty tag.", + "Error reading end tag.", + "Error parsing Unknown.", + "Error parsing Comment.", + "Error parsing Declaration.", + "Error document empty.", + "Error null (0) or unexpected EOF found in input stream.", +}; +#endif /* SETUP */ diff -ruNp vdr-1.6.0-2/tinyxml.h vdr-1.6.0-2-extensions/tinyxml.h --- vdr-1.6.0-2/tinyxml.h 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/tinyxml.h 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,1372 @@ +#ifdef USE_SETUP +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TINYXML_INCLUDED +#define TINYXML_INCLUDED + +#ifdef _MSC_VER +#pragma warning( disable : 4530 ) +#pragma warning( disable : 4786 ) +#endif + +#include +#include +#include +#include +#include + +// Help out windows: +#if defined( _DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +#if defined( DEBUG ) && defined( _MSC_VER ) +#include +#define TIXML_LOG OutputDebugString +#else +#define TIXML_LOG printf +#endif + +#ifdef TIXML_USE_STL + #include + #include + #define TIXML_STRING std::string + #define TIXML_ISTREAM std::istream + #define TIXML_OSTREAM std::ostream +#else + #include "tinystr.h" + #define TIXML_STRING TiXmlString + #define TIXML_OSTREAM TiXmlOutStream +#endif + +class TiXmlDocument; +class TiXmlElement; +class TiXmlComment; +class TiXmlUnknown; +class TiXmlAttribute; +class TiXmlText; +class TiXmlDeclaration; +class TiXmlParsingData; + +const int TIXML_MAJOR_VERSION = 2; +const int TIXML_MINOR_VERSION = 3; +const int TIXML_PATCH_VERSION = 2; + +/* Internal structure for tracking location of items + in the XML file. +*/ +struct TiXmlCursor +{ + TiXmlCursor() { Clear(); } + void Clear() { row = col = -1; } + + int row; // 0 based. + int col; // 0 based. +}; + + +// Only used by Attribute::Query functions +enum +{ + TIXML_SUCCESS, + TIXML_NO_ATTRIBUTE, + TIXML_WRONG_TYPE +}; + + +// Used by the parsing routines. +enum TiXmlEncoding +{ + TIXML_ENCODING_UNKNOWN, + TIXML_ENCODING_UTF8, + TIXML_ENCODING_LEGACY +}; + +const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; + +/** TiXmlBase is a base class for every class in TinyXml. + It does little except to establish that TinyXml classes + can be printed and provide some utility functions. + + In XML, the document and elements can contain + other elements and other types of nodes. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + A Decleration contains: Attributes (not on tree) + @endverbatim +*/ +class TiXmlBase +{ + friend class TiXmlNode; + friend class TiXmlElement; + friend class TiXmlDocument; + +public: + TiXmlBase() : userData(0) {} + virtual ~TiXmlBase() {} + + /** All TinyXml classes can print themselves to a filestream. + This is a formatted print, and will insert tabs and newlines. + + (For an unformatted stream, use the << operator.) + */ + virtual void Print( FILE* cfile, int depth ) const = 0; + + /** The world does not agree on whether white space should be kept or + not. In order to make everyone happy, these global, static functions + are provided to set whether or not TinyXml will condense all white space + into a single space or not. The default is to condense. Note changing this + values is not thread safe. + */ + static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } + + /// Return the current white space setting. + static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } + + /** Return the position, in the original source file, of this node or attribute. + The row and column are 1-based. (That is the first row and first column is + 1,1). If the returns values are 0 or less, then the parser does not have + a row and column value. + + Generally, the row and column value will be set when the TiXmlDocument::Load(), + TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set + when the DOM was created from operator>>. + + The values reflect the initial load. Once the DOM is modified programmatically + (by adding or changing nodes and attributes) the new values will NOT update to + reflect changes in the document. + + There is a minor performance cost to computing the row and column. Computation + can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. + + @sa TiXmlDocument::SetTabSize() + */ + int Row() const { return location.row + 1; } + int Column() const { return location.col + 1; } ///< See Row() + + void SetUserData( void* user ) { userData = user; } + void* GetUserData() { return userData; } + + // Table that returs, for a given lead byte, the total number of bytes + // in the UTF-8 sequence. + static const int utf8ByteTable[256]; + + virtual const char* Parse( const char* p, + TiXmlParsingData* data, + TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; + +protected: + + // See STL_STRING_BUG + // Utility class to overcome a bug. + class StringToBuffer + { + public: + StringToBuffer( const TIXML_STRING& str ); + ~StringToBuffer(); + char* buffer; + }; + + static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); + inline static bool IsWhiteSpace( char c ) + { + return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); + } + + virtual void StreamOut (TIXML_OSTREAM *) const = 0; + + #ifdef TIXML_USE_STL + static bool StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ); + static bool StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ); + #endif + + /* Reads an XML name into the string provided. Returns + a pointer just past the last character of the name, + or 0 if the function has an error. + */ + static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); + + /* Reads text. Returns a pointer past the given end tag. + Wickedly complex options, but it keeps the (sensitive) code in one place. + */ + static const char* ReadText( const char* in, // where to start + TIXML_STRING* text, // the string read + bool ignoreWhiteSpace, // whether to keep the white space + const char* endTag, // what ends this text + bool ignoreCase, // whether to ignore case in the end tag + TiXmlEncoding encoding ); // the current encoding + + // If an entity has been found, transform it into a character. + static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); + + // Get a character, while interpreting entities. + // The length can be from 0 to 4 bytes. + inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) + { + assert( p ); + if ( encoding == TIXML_ENCODING_UTF8 ) + { + *length = utf8ByteTable[ *((unsigned char*)p) ]; + assert( *length >= 0 && *length < 5 ); + } + else + { + *length = 1; + } + + if ( *length == 1 ) + { + if ( *p == '&' ) + return GetEntity( p, _value, length, encoding ); + *_value = *p; + return p+1; + } + else if ( *length ) + { + strncpy( _value, p, *length ); + return p + (*length); + } + else + { + // Not valid text. + return 0; + } + } + + // Puts a string to a stream, expanding entities as it goes. + // Note this should not contian the '<', '>', etc, or they will be transformed into entities! + static void PutString( const TIXML_STRING& str, TIXML_OSTREAM* out ); + + static void PutString( const TIXML_STRING& str, TIXML_STRING* out ); + + // Return true if the next characters in the stream are any of the endTag sequences. + // Ignore case only works for english, and should only be relied on when comparing + // to Engilish words: StringEqual( p, "version", true ) is fine. + static bool StringEqual( const char* p, + const char* endTag, + bool ignoreCase, + TiXmlEncoding encoding ); + + + enum + { + TIXML_NO_ERROR = 0, + TIXML_ERROR, + TIXML_ERROR_OPENING_FILE, + TIXML_ERROR_OUT_OF_MEMORY, + TIXML_ERROR_PARSING_ELEMENT, + TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, + TIXML_ERROR_READING_ELEMENT_VALUE, + TIXML_ERROR_READING_ATTRIBUTES, + TIXML_ERROR_PARSING_EMPTY, + TIXML_ERROR_READING_END_TAG, + TIXML_ERROR_PARSING_UNKNOWN, + TIXML_ERROR_PARSING_COMMENT, + TIXML_ERROR_PARSING_DECLARATION, + TIXML_ERROR_DOCUMENT_EMPTY, + TIXML_ERROR_EMBEDDED_NULL, + + TIXML_ERROR_STRING_COUNT + }; + static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; + + TiXmlCursor location; + + /// Field containing a generic user pointer + void* userData; + + // None of these methods are reliable for any language except English. + // Good for approximation, not great for accuracy. + static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); + static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); + inline static int ToLower( int v, TiXmlEncoding encoding ) + { + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( v < 128 ) return tolower( v ); + return v; + } + else + { + return tolower( v ); + } + } + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + +private: + TiXmlBase( const TiXmlBase& ); // not implemented. + void operator=( const TiXmlBase& base ); // not allowed. + + struct Entity + { + const char* str; + unsigned int strLength; + char chr; + }; + enum + { + NUM_ENTITY = 5, + MAX_ENTITY_LENGTH = 6 + + }; + static Entity entity[ NUM_ENTITY ]; + static bool condenseWhiteSpace; +}; + + +/** The parent class for everything in the Document Object Model. + (Except for attributes). + Nodes have siblings, a parent, and children. A node can be + in a document, or stand on its own. The type of a TiXmlNode + can be queried, and it can be cast to its more defined type. +*/ +class TiXmlNode : public TiXmlBase +{ + friend class TiXmlDocument; + friend class TiXmlElement; + +public: + #ifdef TIXML_USE_STL + + /** An input stream operator, for every class. Tolerant of newlines and + formatting, but doesn't expect them. + */ + friend std::istream& operator >> (std::istream& in, TiXmlNode& base); + + /** An output stream operator, for every class. Note that this outputs + without any newlines or formatting, as opposed to Print(), which + includes tabs and new lines. + + The operator<< and operator>> are not completely symmetric. Writing + a node to a stream is very well defined. You'll get a nice stream + of output, without any extra whitespace or newlines. + + But reading is not as well defined. (As it always is.) If you create + a TiXmlElement (for example) and read that from an input stream, + the text needs to define an element or junk will result. This is + true of all input streams, but it's worth keeping in mind. + + A TiXmlDocument will read nodes until it reads a root element, and + all the children of that root element. + */ + friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); + + /// Appends the XML node or attribute to a std::string. + friend std::string& operator<< (std::string& out, const TiXmlNode& base ); + + #else + // Used internally, not part of the public API. + friend TIXML_OSTREAM& operator<< (TIXML_OSTREAM& out, const TiXmlNode& base); + #endif + + /** The types of XML nodes supported by TinyXml. (All the + unsupported types are picked up by UNKNOWN.) + */ + enum NodeType + { + DOCUMENT, + ELEMENT, + COMMENT, + UNKNOWN, + TEXT, + DECLARATION, + TYPECOUNT + }; + + virtual ~TiXmlNode(); + + /** The meaning of 'value' changes for the specific type of + TiXmlNode. + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + + The subclasses will wrap this function. + */ + const char * Value() const { return value.c_str (); } + + /** Changes the value of the node. Defined as: + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + void SetValue(const char * _value) { value = _value;} + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetValue( const std::string& _value ) + { + StringToBuffer buf( _value ); + SetValue( buf.buffer ? buf.buffer : "" ); + } + #endif + + /// Delete all the children of this node. Does not affect 'this'. + void Clear(); + + /// One step up the DOM. + TiXmlNode* Parent() const { return parent; } + + TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. + TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. + + TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. + TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. + + #ifdef TIXML_USE_STL + TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. + #endif + + /** An alternate way to walk the children of a node. + One way to iterate over nodes is: + @verbatim + for( child = parent->FirstChild(); child; child = child->NextSibling() ) + @endverbatim + + IterateChildren does the same thing with the syntax: + @verbatim + child = 0; + while( child = parent->IterateChildren( child ) ) + @endverbatim + + IterateChildren takes the previous child as input and finds + the next one. If the previous child is null, it returns the + first. IterateChildren will return null when done. + */ + TiXmlNode* IterateChildren( TiXmlNode* previous ) const; + + /// This flavor of IterateChildren searches for children with a particular 'value' + TiXmlNode* IterateChildren( const char * value, TiXmlNode* previous ) const; + + #ifdef TIXML_USE_STL + TiXmlNode* IterateChildren( const std::string& _value, TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + #endif + + /** Add a new node related to this. Adds a child past the LastChild. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); + + + /** Add a new node related to this. Adds a child past the LastChild. + + NOTE: the node to be added is passed by pointer, and will be + henceforth owned (and deleted) by tinyXml. This method is efficient + and avoids an extra copy, but should be used with care as it + uses a different memory model than the other insert functions. + + @sa InsertEndChild + */ + TiXmlNode* LinkEndChild( TiXmlNode* addThis ); + + /** Add a new node related to this. Adds a child before the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); + + /** Add a new node related to this. Adds a child after the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); + + /** Replace a child of this node. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); + + /// Delete a child of this node. + bool RemoveChild( TiXmlNode* removeThis ); + + /// Navigate to a sibling node. + TiXmlNode* PreviousSibling() const { return prev; } + + /// Navigate to a sibling node. + TiXmlNode* PreviousSibling( const char * ) const; + + #ifdef TIXML_USE_STL + TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Navigate to a sibling node. + TiXmlNode* NextSibling() const { return next; } + + /// Navigate to a sibling node with the given 'value'. + TiXmlNode* NextSibling( const char * ) const; + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + TiXmlElement* NextSiblingElement() const; + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + TiXmlElement* NextSiblingElement( const char * ) const; + + #ifdef TIXML_USE_STL + TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Convenience function to get through elements. + TiXmlElement* FirstChildElement() const; + + /// Convenience function to get through elements. + TiXmlElement* FirstChildElement( const char * value ) const; + + #ifdef TIXML_USE_STL + TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /** Query the type (as an enumerated value, above) of this node. + The possible types are: DOCUMENT, ELEMENT, COMMENT, + UNKNOWN, TEXT, and DECLARATION. + */ + virtual int Type() const { return type; } + + /** Return a pointer to the Document this node lives in. + Returns null if not in a document. + */ + TiXmlDocument* GetDocument() const; + + /// Returns true if this node has no children. + bool NoChildren() const { return !firstChild; } + + TiXmlDocument* ToDocument() const { return ( this && type == DOCUMENT ) ? (TiXmlDocument*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. + TiXmlElement* ToElement() const { return ( this && type == ELEMENT ) ? (TiXmlElement*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. + TiXmlComment* ToComment() const { return ( this && type == COMMENT ) ? (TiXmlComment*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. + TiXmlUnknown* ToUnknown() const { return ( this && type == UNKNOWN ) ? (TiXmlUnknown*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. + TiXmlText* ToText() const { return ( this && type == TEXT ) ? (TiXmlText*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. + TiXmlDeclaration* ToDeclaration() const { return ( this && type == DECLARATION ) ? (TiXmlDeclaration*) this : 0; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Create an exact duplicate of this node and return it. The memory must be deleted + by the caller. + */ + virtual TiXmlNode* Clone() const = 0; + +protected: + TiXmlNode( NodeType _type ); + + // Copy to the allocated object. Shared functionality between Clone, Copy constructor, + // and the assignment operator. + void CopyTo( TiXmlNode* target ) const; + + #ifdef TIXML_USE_STL + // The real work of the input operator. + virtual void StreamIn( TIXML_ISTREAM* in, TIXML_STRING* tag ) = 0; + #endif + + // Figure out what is at *p, and parse it. Returns null if it is not an xml node. + TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); + + // Internal Value function returning a TIXML_STRING + const TIXML_STRING& SValue() const { return value ; } + + TiXmlNode* parent; + NodeType type; + + TiXmlNode* firstChild; + TiXmlNode* lastChild; + + TIXML_STRING value; + + TiXmlNode* prev; + TiXmlNode* next; + +private: + TiXmlNode( const TiXmlNode& ); // not implemented. + void operator=( const TiXmlNode& base ); // not allowed. +}; + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not TiXmlNodes, since they are not + part of the tinyXML document object model. There are other + suggested ways to look at this problem. +*/ +class TiXmlAttribute : public TiXmlBase +{ + friend class TiXmlAttributeSet; + +public: + /// Construct an empty attribute. + TiXmlAttribute() : TiXmlBase() + { + document = 0; + prev = next = 0; + } + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlAttribute( const std::string& _name, const std::string& _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + #endif + + /// Construct an attribute with a name and value. + TiXmlAttribute( const char * _name, const char * _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + + const char* Name() const { return name.c_str (); } ///< Return the name of this attribute. + const char* Value() const { return value.c_str (); } ///< Return the value of this attribute. + const int IntValue() const; ///< Return the value of this attribute, converted to an integer. + const double DoubleValue() const; ///< Return the value of this attribute, converted to a double. + + /** QueryIntValue examines the value string. It is an alternative to the + IntValue() method with richer error checking. + If the value is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. + + A specialized but useful call. Note that for success it returns 0, + which is the opposite of almost all other TinyXml calls. + */ + int QueryIntValue( int* value ) const; + /// QueryDoubleValue examines the value string. See QueryIntValue(). + int QueryDoubleValue( double* value ) const; + + void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. + void SetValue( const char* _value ) { value = _value; } ///< Set the value. + + void SetIntValue( int value ); ///< Set the value from an integer. + void SetDoubleValue( double value ); ///< Set the value from a double. + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetName( const std::string& _name ) + { + StringToBuffer buf( _name ); + SetName ( buf.buffer ? buf.buffer : "error" ); + } + /// STL std::string form. + void SetValue( const std::string& _value ) + { + StringToBuffer buf( _value ); + SetValue( buf.buffer ? buf.buffer : "error" ); + } + #endif + + /// Get the next sibling attribute in the DOM. Returns null at end. + TiXmlAttribute* Next() const; + /// Get the previous sibling attribute in the DOM. Returns null at beginning. + TiXmlAttribute* Previous() const; + + bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } + bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } + bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } + + /* Attribute parsing starts: first letter of the name + returns: the next char after the value end quote + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + // Prints this Attribute to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual void StreamOut( TIXML_OSTREAM * out ) const; + // [internal use] + // Set the document pointer so the attribute can report errors. + void SetDocument( TiXmlDocument* doc ) { document = doc; } + +private: + TiXmlAttribute( const TiXmlAttribute& ); // not implemented. + void operator=( const TiXmlAttribute& base ); // not allowed. + + TiXmlDocument* document; // A pointer back to a document, for error reporting. + TIXML_STRING name; + TIXML_STRING value; + TiXmlAttribute* prev; + TiXmlAttribute* next; +}; + + +/* A class used to manage a group of attributes. + It is only used internally, both by the ELEMENT and the DECLARATION. + + The set can be changed transparent to the Element and Declaration + classes that use it, but NOT transparent to the Attribute + which has to implement a next() and previous() method. Which makes + it a bit problematic and prevents the use of STL. + + This version is implemented with circular lists because: + - I like circular lists + - it demonstrates some independence from the (typical) doubly linked list. +*/ +class TiXmlAttributeSet +{ +public: + TiXmlAttributeSet(); + ~TiXmlAttributeSet(); + + void Add( TiXmlAttribute* attribute ); + void Remove( TiXmlAttribute* attribute ); + + TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + TiXmlAttribute* Find( const char * name ) const; + +private: + TiXmlAttribute sentinel; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TiXmlElement : public TiXmlNode +{ +public: + /// Construct an element. + TiXmlElement (const char * in_value); + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlElement( const std::string& _value ); + #endif + + TiXmlElement( const TiXmlElement& ); + + void operator=( const TiXmlElement& base ); + + virtual ~TiXmlElement(); + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + */ + const char* Attribute( const char* name ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an integer, + the integer value will be put in the return 'i', if 'i' + is non-null. + */ + const char* Attribute( const char* name, int* i ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an double, + the double value will be put in the return 'd', if 'd' + is non-null. + */ + const char* Attribute( const char* name, double* d ) const; + + /** QueryIntAttribute examines the attribute - it is an alternative to the + Attribute() method with richer error checking. + If the attribute is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. If the attribute + does not exist, then TIXML_NO_ATTRIBUTE is returned. + */ + int QueryIntAttribute( const char* name, int* value ) const; + /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). + int QueryDoubleAttribute( const char* name, double* value ) const; + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char* name, const char * value ); + + #ifdef TIXML_USE_STL + const char* Attribute( const std::string& name ) const { return Attribute( name.c_str() ); } + const char* Attribute( const std::string& name, int* i ) const { return Attribute( name.c_str(), i ); } + const char* Attribute( const std::string& name, double* d ) const { return Attribute( name.c_str(), d ); } + int QueryIntAttribute( const std::string& name, int* value ) const { return QueryIntAttribute( name.c_str(), value ); } + int QueryDoubleAttribute( const std::string& name, double* value ) const { return QueryDoubleAttribute( name.c_str(), value ); } + + /// STL std::string form. + void SetAttribute( const std::string& name, const std::string& _value ) + { + StringToBuffer n( name ); + StringToBuffer v( _value ); + if ( n.buffer && v.buffer ) + SetAttribute (n.buffer, v.buffer ); + } + ///< STL std::string form. + void SetAttribute( const std::string& name, int _value ) + { + StringToBuffer n( name ); + if ( n.buffer ) + SetAttribute (n.buffer, _value); + } + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char * name, int value ); + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetDoubleAttribute( const char * name, double value ); + + /** Deletes an attribute with the given name. + */ + void RemoveAttribute( const char * name ); + #ifdef TIXML_USE_STL + void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. + #endif + + TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. + TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. + + /// Creates a new Element and returns it - the returned element is a copy. + virtual TiXmlNode* Clone() const; + // Print the Element to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: next char past '<' + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + +protected: + + void CopyTo( TiXmlElement* target ) const; + void ClearThis(); // like clear, but initializes 'this' object as well + + // Used to be public [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); + #endif + virtual void StreamOut( TIXML_OSTREAM * out ) const; + + /* [internal use] + Reads the "value" of the element -- another element, or text. + This should terminate with the current end tag. + */ + const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + +private: + + TiXmlAttributeSet attributeSet; +}; + + +/** An XML comment. +*/ +class TiXmlComment : public TiXmlNode +{ +public: + /// Constructs an empty comment. + TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} + TiXmlComment( const TiXmlComment& ); + void operator=( const TiXmlComment& base ); + + virtual ~TiXmlComment() {} + + /// Returns a copy of this Comment. + virtual TiXmlNode* Clone() const; + /// Write this Comment to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: at the ! of the !-- + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + +protected: + void CopyTo( TiXmlComment* target ) const; + + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); + #endif + virtual void StreamOut( TIXML_OSTREAM * out ) const; + +private: + +}; + + +/** XML text. Contained in an element. +*/ +class TiXmlText : public TiXmlNode +{ + friend class TiXmlElement; +public: + /// Constructor. + TiXmlText (const char * initValue) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + } + virtual ~TiXmlText() {} + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) + { + SetValue( initValue ); + } + #endif + + TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } + void operator=( const TiXmlText& base ) { base.CopyTo( this ); } + + /// Write this text object to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + +protected : + /// [internal use] Creates a new Element and returns it. + virtual TiXmlNode* Clone() const; + void CopyTo( TiXmlText* target ) const; + + virtual void StreamOut ( TIXML_OSTREAM * out ) const; + bool Blank() const; // returns true if all white space and new lines + // [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); + #endif + +private: +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXml will happily read or write files without a declaration, + however. There are 3 possible attributes to the declaration: + version, encoding, and standalone. + + Note: In this version of the code, the attributes are + handled as special cases, not generic attributes, simply + because there can only be at most 3 and they are always the same. +*/ +class TiXmlDeclaration : public TiXmlNode +{ +public: + /// Construct an empty declaration. + TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ); +#endif + + /// Construct. + TiXmlDeclaration( const char* _version, + const char* _encoding, + const char* _standalone ); + + TiXmlDeclaration( const TiXmlDeclaration& copy ); + void operator=( const TiXmlDeclaration& copy ); + + virtual ~TiXmlDeclaration() {} + + /// Version. Will return an empty string if none was found. + const char *Version() const { return version.c_str (); } + /// Encoding. Will return an empty string if none was found. + const char *Encoding() const { return encoding.c_str (); } + /// Is this a standalone document? + const char *Standalone() const { return standalone.c_str (); } + + /// Creates a copy of this Declaration and returns it. + virtual TiXmlNode* Clone() const; + /// Print this declaration to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + +protected: + void CopyTo( TiXmlDeclaration* target ) const; + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); + #endif + virtual void StreamOut ( TIXML_OSTREAM * out) const; + +private: + + TIXML_STRING version; + TIXML_STRING encoding; + TIXML_STRING standalone; +}; + + +/** Any tag that tinyXml doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into TiXmlUnknowns. +*/ +class TiXmlUnknown : public TiXmlNode +{ +public: + TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} + virtual ~TiXmlUnknown() {} + + TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } + void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } + + /// Creates a copy of this Unknown and returns it. + virtual TiXmlNode* Clone() const; + /// Print this Unknown to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + +protected: + void CopyTo( TiXmlUnknown* target ) const; + + #ifdef TIXML_USE_STL + virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); + #endif + virtual void StreamOut ( TIXML_OSTREAM * out ) const; + +private: + +}; + + +/** Always the top level node. A document binds together all the + XML pieces. It can be saved, loaded, and printed to the screen. + The 'value' of a document node is the xml file name. +*/ +class TiXmlDocument : public TiXmlNode +{ +public: + /// Create an empty document, that has no name. + TiXmlDocument(); + /// Create a document with a name. The name of the document is also the filename of the xml. + TiXmlDocument( const char * documentName ); + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlDocument( const std::string& documentName ); + #endif + + TiXmlDocument( const TiXmlDocument& copy ); + void operator=( const TiXmlDocument& copy ); + + virtual ~TiXmlDocument() {} + + /** Load a file using the current document value. + Returns true if successful. Will delete any existing + document data before loading. + */ + bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the current document value. Returns true if successful. + bool SaveFile() const; + /// Load a file using the given filename. Returns true if successful. + bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given filename. Returns true if successful. + bool SaveFile( const char * filename ) const; + + #ifdef TIXML_USE_STL + bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. + { + StringToBuffer f( filename ); + return ( f.buffer && LoadFile( f.buffer, encoding )); + } + bool SaveFile( const std::string& filename ) const ///< STL std::string version. + { + StringToBuffer f( filename ); + return ( f.buffer && SaveFile( f.buffer )); + } + #endif + + /** Parse the given null terminated block of xml data. Passing in an encoding to this + method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml + to use that encoding, regardless of what TinyXml might otherwise try to detect. + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + + /** Get the root element -- the only top level element -- of the document. + In well formed XML, there should only be one. TinyXml is tolerant of + multiple elements at the document level. + */ + TiXmlElement* RootElement() const { return FirstChildElement(); } + + /** If an error occurs, Error will be set to true. Also, + - The ErrorId() will contain the integer identifier of the error (not generally useful) + - The ErrorDesc() method will return the name of the error. (very useful) + - The ErrorRow() and ErrorCol() will return the location of the error (if known) + */ + bool Error() const { return error; } + + /// Contains a textual (english) description of the error if one occurs. + const char * ErrorDesc() const { return errorDesc.c_str (); } + + /** Generally, you probably want the error string ( ErrorDesc() ). But if you + prefer the ErrorId, this function will fetch it. + */ + const int ErrorId() const { return errorId; } + + /** Returns the location (if known) of the error. The first column is column 1, + and the first row is row 1. A value of 0 means the row and column wasn't applicable + (memory errors, for example, have no row/column) or the parser lost the error. (An + error in the error reporting, in that case.) + + @sa SetTabSize, Row, Column + */ + int ErrorRow() { return errorLocation.row+1; } + int ErrorCol() { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() + + /** By calling this method, with a tab size + greater than 0, the row and column of each node and attribute is stored + when the file is loaded. Very useful for tracking the DOM back in to + the source file. + + The tab size is required for calculating the location of nodes. If not + set, the default of 4 is used. The tabsize is set per document. Setting + the tabsize to 0 disables row/column tracking. + + Note that row and column tracking is not supported when using operator>>. + + The tab size needs to be enabled before the parse or load. Correct usage: + @verbatim + TiXmlDocument doc; + doc.SetTabSize( 8 ); + doc.Load( "myfile.xml" ); + @endverbatim + + @sa Row, Column + */ + void SetTabSize( int _tabsize ) { tabsize = _tabsize; } + + int TabSize() const { return tabsize; } + + /** If you have handled the error, it can be reset with this call. The error + state is automatically cleared if you Parse a new XML block. + */ + void ClearError() { error = false; + errorId = 0; + errorDesc = ""; + errorLocation.row = errorLocation.col = 0; + //errorLocation.last = 0; + } + + /** Dump the document to standard out. */ + void Print() const { Print( stdout, 0 ); } + + /// Print this Document to a FILE stream. + virtual void Print( FILE* cfile, int depth = 0 ) const; + // [internal use] + void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + +protected : + virtual void StreamOut ( TIXML_OSTREAM * out) const; + // [internal use] + virtual TiXmlNode* Clone() const; + #ifdef TIXML_USE_STL + virtual void StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ); + #endif + +private: + void CopyTo( TiXmlDocument* target ) const; + + bool error; + int errorId; + TIXML_STRING errorDesc; + int tabsize; + TiXmlCursor errorLocation; +}; + + +/** + A TiXmlHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + TiXmlElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + TiXmlElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + TiXmlElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + TiXmlElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity + of such code. A TiXmlHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + TiXmlHandle docHandle( &document ); + TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).Element(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + TiXmlHandle handleCopy = handle; + @endverbatim + + What they should not be used for is iteration: + + @verbatim + int i=0; + while ( true ) + { + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).Element(); + if ( !child ) + break; + // do something + ++i; + } + @endverbatim + + It seems reasonable, but it is in fact two embedded while loops. The Child method is + a linear walk to find the element, so this code would iterate much more than it needs + to. Instead, prefer: + + @verbatim + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).Element(); + + for( child; child; child=child->NextSiblingElement() ) + { + // do something + } + @endverbatim +*/ +class TiXmlHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + TiXmlHandle( TiXmlNode* node ) { this->node = node; } + /// Copy constructor + TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } + TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } + + /// Return a handle to the first child node. + TiXmlHandle FirstChild() const; + /// Return a handle to the first child node with the given name. + TiXmlHandle FirstChild( const char * value ) const; + /// Return a handle to the first child element. + TiXmlHandle FirstChildElement() const; + /// Return a handle to the first child element with the given name. + TiXmlHandle FirstChildElement( const char * value ) const; + + /** Return a handle to the "index" child with the given name. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( const char* value, int index ) const; + /** Return a handle to the "index" child. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( int index ) const; + /** Return a handle to the "index" child element with the given name. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( const char* value, int index ) const; + /** Return a handle to the "index" child element. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( int index ) const; + + #ifdef TIXML_USE_STL + TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } + TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } + + TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } + TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } + #endif + + /// Return the handle as a TiXmlNode. This may return null. + TiXmlNode* Node() const { return node; } + /// Return the handle as a TiXmlElement. This may return null. + TiXmlElement* Element() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } + /// Return the handle as a TiXmlText. This may return null. + TiXmlText* Text() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } + /// Return the handle as a TiXmlUnknown. This may return null; + TiXmlUnknown* Unknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } + +private: + TiXmlNode* node; +}; + + +#endif +#endif /* SETUP */ diff -ruNp vdr-1.6.0-2/tinyxmlparser.c vdr-1.6.0-2-extensions/tinyxmlparser.c --- vdr-1.6.0-2/tinyxmlparser.c 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/tinyxmlparser.c 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,1494 @@ +#ifdef USE_SETUP +/* +www.sourceforge.net/projects/tinyxml +Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml.h" +#include + +//#define DEBUG_PARSER + +// Note tha "PutString" hardcodes the same list. This +// is less flexible than it appears. Changing the entries +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = +{ + { "&", 5, '&' }, + { "<", 4, '<' }, + { ">", 4, '>' }, + { """, 6, '\"' }, + { "'", 6, '\'' } +}; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// Including the basic of this table, which determines the #bytes in the +// sequence from the lead byte. 1 placed for invalid sequences -- +// although the result will be junk, pass it through as much as possible. +// Beware of the non-characters in UTF-8: +// ef bb bf (Microsoft "lead bytes") +// ef bf be +// ef bf bf + + + +const int TiXmlBase::utf8ByteTable[256] = +{ + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte + 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid +}; + + +void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) + *length = 1; + else if ( input < 0x800 ) + *length = 2; + else if ( input < 0x10000 ) + *length = 3; + else if ( input < 0x200000 ) + *length = 4; + else + { *length = 0; return; } // This code won't covert this correctly anyway. + + output += *length; + + // Scary scary fall throughs. + switch (*length) + { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + } +} + + +/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalpha( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalpha( anyByte ); +// } +} + + +/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalnum( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalnum( anyByte ); +// } +} + + +class TiXmlParsingData +{ + friend class TiXmlDocument; + public: + void Stamp( const char* now, TiXmlEncoding encoding ); + + const TiXmlCursor& Cursor() { return cursor; } + + private: + // Only used by the document! + TiXmlParsingData( const char* start, int _tabsize, int row, int col ) + { + assert( start ); + stamp = start; + tabsize = _tabsize; + cursor.row = row; + cursor.col = col; + } + + TiXmlCursor cursor; + const char* stamp; + int tabsize; +}; + + +void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) +{ + assert( now ); + + // Do nothing if the tabsize is 0. + if ( tabsize < 1 ) + { + return; + } + + // Get the current row, column. + int row = cursor.row; + int col = cursor.col; + const char* p = stamp; + assert( p ); + + while ( p < now ) + { + // Code contributed by Fletcher Dunn: (modified by lee) + switch (*p) { + case 0: + // We *should* never get here, but in case we do, don't + // advance past the terminating null character, ever + return; + + case '\r': + // bump down to the next line + ++row; + col = 0; + // Eat the character + ++p; + + // Check for \r\n sequence, and treat this as a single character + if (*p == '\n') { + ++p; + } + break; + + case '\n': + // bump down to the next line + ++row; + col = 0; + + // Eat the character + ++p; + + // Check for \n\r sequence, and treat this as a single + // character. (Yes, this bizarre thing does occur still + // on some arcane platforms...) + if (*p == '\r') { + ++p; + } + break; + + case '\t': + // Eat the character + ++p; + + // Skip to next tab stop + col = (col / tabsize + 1) * tabsize; + break; + + case (char)(0xef): + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( *(p+1) && *(p+2) ) + { + // In these cases, don't advance the column. These are + // 0-width spaces. + if ( *(p+1)==(char)(0xbb) && *(p+2)==(char)(0xbf) ) + p += 3; + else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbe) ) + p += 3; + else if ( *(p+1)==(char)(0xbf) && *(p+2)==(char)(0xbf) ) + p += 3; + else + { p +=3; ++col; } // A normal character. + } + } + else + { + ++p; + ++col; + } + break; + + default: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // Eat the 1 to 4 byte utf8 character. + int step = TiXmlBase::utf8ByteTable[*((unsigned char*)p)]; + if ( step == 0 ) + step = 1; // Error case from bad encoding, but handle gracefully. + p += step; + + // Just advance one column, of course. + ++col; + } + else + { + ++p; + ++col; + } + break; + } + } + cursor.row = row; + cursor.col = col; + assert( cursor.row >= -1 ); + assert( cursor.col >= -1 ); + stamp = p; + assert( stamp ); +} + + +const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) +{ + if ( !p || !*p ) + { + return 0; + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + while ( *p ) + { + // Skip the stupid Microsoft UTF-8 Byte order marks + if ( *(p+0)==(char) 0xef + && *(p+1)==(char) 0xbb + && *(p+2)==(char) 0xbf ) + { + p += 3; + continue; + } + else if(*(p+0)==(char) 0xef + && *(p+1)==(char) 0xbf + && *(p+2)==(char) 0xbe ) + { + p += 3; + continue; + } + else if(*(p+0)==(char) 0xef + && *(p+1)==(char) 0xbf + && *(p+2)==(char) 0xbf ) + { + p += 3; + continue; + } + + if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space. + ++p; + else + break; + } + } + else + { + while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) + ++p; + } + + return p; +} + +#ifdef TIXML_USE_STL +/*static*/ bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag ) +{ + for( ;; ) + { + if ( !in->good() ) return false; + + int c = in->peek(); + // At this scope, we can't get to a document. So fail silently. + if ( !IsWhiteSpace( c ) || c <= 0 ) + return true; + + *tag += (char) in->get(); + } +} + +/*static*/ bool TiXmlBase::StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag ) +{ + //assert( character > 0 && character < 128 ); // else it won't work in utf-8 + while ( in->good() ) + { + int c = in->peek(); + if ( c == character ) + return true; + if ( c <= 0 ) // Silent failure: can't get document at this scope + return false; + + in->get(); + *tag += (char) c; + } + return false; +} +#endif + +const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) +{ + *name = ""; + assert( p ); + + // Names start with letters or underscores. + // Of course, in unicode, tinyxml has no idea what a letter *is*. The + // algorithm is generous. + // + // After that, they can be letters, underscores, numbers, + // hyphens, or colons. (Colons are valid ony for namespaces, + // but tinyxml can't tell namespaces from names.) + if ( p && *p + && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) + { + while( p && *p + && ( IsAlphaNum( (unsigned char ) *p, encoding ) + || *p == '_' + || *p == '-' + || *p == '.' + || *p == ':' ) ) + { + (*name) += *p; + ++p; + } + return p; + } + return 0; +} + +const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) +{ + // Presume an entity, and pull it out. + TIXML_STRING ent; + int i; + *length = 0; + + if ( *(p+1) && *(p+1) == '#' && *(p+2) ) + { + unsigned long ucs = 0; + unsigned delta = 0; + unsigned mult = 1; + + if ( *(p+2) == 'x' ) + { + // Hexadecimal. + if ( !*(p+3) ) return 0; + + const char* q = p+3; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != 'x' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else if ( *q >= 'a' && *q <= 'f' ) + ucs += mult * (*q - 'a' + 10); + else if ( *q >= 'A' && *q <= 'F' ) + ucs += mult * (*q - 'A' + 10 ); + else + return 0; + mult *= 16; + --q; + } + } + else + { + // Decimal. + if ( !*(p+2) ) return 0; + + const char* q = p+2; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != '#' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else + return 0; + mult *= 10; + --q; + } + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + } + else + { + *value = (char)ucs; + *length = 1; + } + return p + delta + 1; + } + + // Now try to match it. + for( i=0; iappend( cArr, len ); + } + } + else + { + bool whitespace = false; + + // Remove leading white space: + p = SkipWhiteSpace( p, encoding ); + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) ) + { + if ( *p == '\r' || *p == '\n' ) + { + whitespace = true; + ++p; + } + else if ( IsWhiteSpace( *p ) ) + { + whitespace = true; + ++p; + } + else + { + // If we've found whitespace, add it before the + // new character. Any whitespace just becomes a space. + if ( whitespace ) + { + (*text) += ' '; + whitespace = false; + } + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + if ( len == 1 ) + (*text) += cArr[0]; // more efficient + else + text->append( cArr, len ); + } + } + } + return p + strlen( endTag ); +} + +#ifdef TIXML_USE_STL + +void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) +{ + // The basic issue with a document is that we don't know what we're + // streaming. Read something presumed to be a tag (and hope), then + // identify it, and call the appropriate stream method on the tag. + // + // This "pre-streaming" will never read the closing ">" so the + // sub-tag can orient itself. + + if ( !StreamTo( in, '<', tag ) ) + { + SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + while ( in->good() ) + { + int tagIndex = (int) tag->length(); + while ( in->good() && in->peek() != '>' ) + { + int c = in->get(); + if ( c <= 0 ) + { + SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + break; + } + (*tag) += (char) c; + } + + if ( in->good() ) + { + // We now have something we presume to be a node of + // some sort. Identify it, and call the node to + // continue streaming. + TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); + + if ( node ) + { + node->StreamIn( in, tag ); + bool isElement = node->ToElement() != 0; + delete node; + node = 0; + + // If this is the root element, we're done. Parsing will be + // done by the >> operator. + if ( isElement ) + { + return; + } + } + else + { + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + } + } + // We should have returned sooner. + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); +} + +#endif + +const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) +{ + ClearError(); + + // Parse away, at the document level. Since a document + // contains nothing but other tags, most of what happens + // here is skipping white space. + if ( !p || !*p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + // Note that, for a document, this needs to come + // before the while space skip, so that parsing + // starts from the pointer we are given. + location.Clear(); + if ( prevData ) + { + location.row = prevData->cursor.row; + location.col = prevData->cursor.col; + } + else + { + location.row = 0; + location.col = 0; + } + TiXmlParsingData data( p, TabSize(), location.row, location.col ); + location = data.Cursor(); + + if ( encoding == TIXML_ENCODING_UNKNOWN ) + { + // Check for the Microsoft UTF-8 lead bytes. + if ( *(p+0) && *(p+0) == (char)(0xef) + && *(p+1) && *(p+1) == (char)(0xbb) + && *(p+2) && *(p+2) == (char)(0xbf) ) + { + encoding = TIXML_ENCODING_UTF8; + } + } + + p = SkipWhiteSpace( p, encoding ); + if ( !p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + while ( p && *p ) + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, &data, encoding ); + LinkEndChild( node ); + } + else + { + break; + } + + // Did we get encoding info? + if ( encoding == TIXML_ENCODING_UNKNOWN + && node->ToDeclaration() ) + { + TiXmlDeclaration* dec = node->ToDeclaration(); + const char* enc = dec->Encoding(); + assert( enc ); + + if ( *enc == 0 ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice + else + encoding = TIXML_ENCODING_LEGACY; + } + + p = SkipWhiteSpace( p, encoding ); + } + + // All is well. + return p; +} + +void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + // The first error in a chain is more accurate - don't set again! + if ( error ) + return; + + assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); + error = true; + errorId = err; + errorDesc = errorString[ errorId ]; + + errorLocation.Clear(); + if ( pError && data ) + { + //TiXmlParsingData data( pError, prevData ); + data->Stamp( pError, encoding ); + errorLocation = data->Cursor(); + } +} + + +TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) +{ + TiXmlNode* returnNode = 0; + + p = SkipWhiteSpace( p, encoding ); + if( !p || !*p || *p != '<' ) + { + return 0; + } + + TiXmlDocument* doc = GetDocument(); + p = SkipWhiteSpace( p, encoding ); + + if ( !p || !*p ) + { + return 0; + } + + // What is this thing? + // - Elements start with a letter or underscore, but xml is reserved. + // - Comments: "; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + p = ReadText( p, &value, false, endTag, false, encoding ); + return p; +} + + +const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) return 0; + + int tabsize = 4; + if ( document ) + tabsize = document->TabSize(); + +// TiXmlParsingData data( p, prevData ); + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + // Read the name, the '=' and the value. + const char* pErr = p; + p = ReadName( p, &name, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p || *p != '=' ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + ++p; // skip '=' + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + const char* end; + + if ( *p == '\'' ) + { + ++p; + end = "\'"; + p = ReadText( p, &value, false, end, false, encoding ); + } + else if ( *p == '"' ) + { + ++p; + end = "\""; + p = ReadText( p, &value, false, end, false, encoding ); + } + else + { + // All attribute values should be in single or double quotes. + // But this is such a common error that the parser will try + // its best, even without them. + value = ""; + while ( p && *p // existence + && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace + && *p != '/' && *p != '>' ) // tag end + { + value += *p; + ++p; + } + } + return p; +} + +#ifdef TIXML_USE_STL +void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->peek(); + if ( c == '<' ) + return; + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + in->get(); + } +} +#endif + +const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + value = ""; +// TiXmlParsingData data( p, prevData ); + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + bool ignoreWhite = true; + + const char* end = "<"; + p = ReadText( p, &value, ignoreWhite, end, false, encoding ); + if ( p ) + return p-1; // don't truncate the '<' + return 0; +} + +#ifdef TIXML_USE_STL +void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } +} +#endif + +const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) +{ + p = SkipWhiteSpace( p, _encoding ); + // Find the beginning, find the end, and look for + // the stuff in-between. + TiXmlDocument* document = GetDocument(); + if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); + return 0; + } +// TiXmlParsingData data( p, prevData ); + if ( data ) + { + data->Stamp( p, _encoding ); + location = data->Cursor(); + } + p += 5; + + version = ""; + encoding = ""; + standalone = ""; + + while ( p && *p ) + { + if ( *p == '>' ) + { + ++p; + return p; + } + + p = SkipWhiteSpace( p, _encoding ); + if ( StringEqual( p, "version", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + version = attrib.Value(); + } + else if ( StringEqual( p, "encoding", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + encoding = attrib.Value(); + } + else if ( StringEqual( p, "standalone", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + standalone = attrib.Value(); + } + else + { + // Read over whatever it is. + while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) + ++p; + } + } + return 0; +} + +bool TiXmlText::Blank() const +{ + for ( unsigned i=0; i 0) @@ -553,6 +817,11 @@ int main(int argc, char *argv[]) if (!PluginManager.LoadPlugins(true)) EXIT(2); +#ifdef USE_LIVEBUFFER + if (!BufferDirectory) + BufferDirectory = VideoDirectory; +#endif /* LIVEBUFFER */ + // Configuration data: if (!ConfigDirectory) @@ -566,8 +835,20 @@ int main(int argc, char *argv[]) Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC) && Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true) && Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")) && +#ifdef USE_CMDRECCMDI18N + LoadCommandsI18n(Commands,AddDirectory(ConfigDirectory, "commands.conf"), true) && + LoadCommandsI18n(RecordingCommands, AddDirectory(ConfigDirectory, "reccmds.conf"), true) && +#else Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true) && RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true) && +#endif /* CMDRECCMDI18N */ +#ifdef USE_TIMERCMD +#ifdef USE_CMDRECCMDI18N + LoadCommandsI18n(TimerCommands, AddDirectory(ConfigDirectory, "timercmds.conf"), true) && +#else + TimerCommands.Load(AddDirectory(ConfigDirectory, "timercmds.conf"), true) && +#endif /* CMDRECCMDI18N */ +#endif /* TIMERCMD */ SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true) && Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")) && KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true) @@ -730,7 +1011,11 @@ int main(int argc, char *argv[]) // Make sure we have a visible programme in case device usage has changed: if (!EITScanner.Active() && cDevice::PrimaryDevice()->HasDecoder() && !cDevice::PrimaryDevice()->HasProgramme()) { static time_t lastTime = 0; +#ifdef USE_CHANNELSCAN + if (!scanning_on_receiving_device && (!Menu || CheckHasProgramme) && Now - lastTime > MINCHANNELWAIT) { +#else if ((!Menu || CheckHasProgramme) && Now - lastTime > MINCHANNELWAIT) { // !Menu to avoid interfering with the CAM if a CAM menu is open +#endif /* CHANNELSCAN */ cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel()); if (Channel && (Channel->Vpid() || Channel->Apid(0))) { if (!Channels.SwitchTo(cDevice::CurrentChannel()) // try to switch to the original channel... @@ -786,8 +1071,17 @@ int main(int argc, char *argv[]) } // Channel display: if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) { +#ifdef USE_LIVEBUFFER + if (!Menu) { + if (cControl::Control(true)) + cControl::Control(true)->Hide(); +#else if (!Menu) +#endif /* LIVEBUFFER */ Menu = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel >= 0); +#ifdef USE_LIVEBUFFER + } +#endif /* LIVEBUFFER */ LastChannel = cDevice::CurrentChannel(); LastChannelChanged = Now; } @@ -902,9 +1196,19 @@ int main(int argc, char *argv[]) if (!Skins.IsOpen()) Skins.ProcessQueuedMessages(); // User Input: +#ifdef USE_LIVEBUFFER + cOsdObject *Interact = Menu ? Menu : cControl::Control(true); +#else cOsdObject *Interact = Menu ? Menu : cControl::Control(); +#endif /* LIVEBUFFER */ eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse()); +#ifdef USE_LIVEBUFFER + Interact = Menu ? Menu : cControl::Control(); +#endif /* LIVEBUFFER */ if (ISREALKEY(key)) { +#ifdef USE_PINPLUGIN + cStatus::MsgUserAction(key, Interact); +#endif /* PINPLUGIN */ EITScanner.Activity(); // Cancel shutdown countdown: if (ShutdownHandler.countdown) @@ -921,9 +1225,17 @@ int main(int argc, char *argv[]) bool WasMenu = Interact && Interact->IsMenu(); if (Menu) DELETE_MENU; +#ifdef USE_LIVEBUFFER + else if (cControl::Control(true)) { +#else else if (cControl::Control()) { +#endif /* LIVEBUFFER */ if (cOsd::IsOpen()) +#ifdef USE_LIVEBUFFER + cControl::Control(true)->Hide(); +#else cControl::Control()->Hide(); +#endif /* LIVEBUFFER */ else WasOpen = false; } @@ -956,12 +1268,21 @@ int main(int argc, char *argv[]) } break; // Direct main menu functions: +#ifdef USE_LIVEBUFFER + #define DirectMainFunction(function)\ + DELETE_MENU;\ + if (cControl::Control(true))\ + cControl::Control(true)->Hide();\ + Menu = new cMenuMain(function);\ + key = kNone; // nobody else needs to see this key +#else #define DirectMainFunction(function)\ DELETE_MENU;\ if (cControl::Control())\ cControl::Control()->Hide();\ Menu = new cMenuMain(function);\ key = kNone; // nobody else needs to see this key +#endif /* LIVEBUFFER */ case kSchedule: DirectMainFunction(osSchedule); break; case kChannels: DirectMainFunction(osChannels); break; case kTimers: DirectMainFunction(osTimers); break; @@ -973,14 +1294,25 @@ int main(int argc, char *argv[]) const char *PluginName = cRemote::GetPlugin(); if (PluginName) { DELETE_MENU; +#ifdef USE_LIVEBUFFER + if (cControl::Control(true)) + cControl::Control(true)->Hide(); +#else if (cControl::Control()) cControl::Control()->Hide(); +#endif /* LIVEBUFFER */ cPlugin *plugin = cPluginManager::GetPlugin(PluginName); if (plugin) { +#ifdef USE_PINPLUGIN + if (!cStatus::MsgPluginProtected(plugin)) { +#endif /* PINPLUGIN */ Menu = plugin->MainMenuAction(); if (Menu) Menu->Show(); } +#ifdef USE_PINPLUGIN + } +#endif /* PINPLUGIN */ else esyslog("ERROR: unknown plugin '%s'", PluginName); } @@ -992,8 +1324,17 @@ int main(int argc, char *argv[]) case kChanUp: case kChanDn|k_Repeat: case kChanDn: +#ifdef USE_LIVEBUFFER + if (!Interact) { + if (cControl::Control(true)) + cControl::Control(true)->Hide(); +#else if (!Interact) +#endif /* LIVEBUFFER */ Menu = new cDisplayChannel(NORMALKEY(key)); +#ifdef USE_LIVEBUFFER + } +#endif /* LIVEBUFFER */ else if (cDisplayChannel::IsOpen() || cControl::Control()) { Interact->ProcessKey(key); continue; @@ -1023,8 +1364,13 @@ int main(int argc, char *argv[]) break; // Audio track control: case kAudio: +#ifdef USE_LIVEBUFFER + if (cControl::Control(true)) + cControl::Control(true)->Hide(); +#else if (cControl::Control()) cControl::Control()->Hide(); +#endif /* LIVEBUFFER */ if (!cDisplayTracks::IsOpen()) { DELETE_MENU; Menu = cDisplayTracks::Create(); @@ -1047,7 +1393,11 @@ int main(int argc, char *argv[]) break; // Pausing live video: case kPause: +#ifdef USE_LIVEBUFFER + if (!cControl::Control() && !cLiveBufferManager::GetLiveBufferControl()) { +#else if (!cControl::Control()) { +#endif /* LIVEBUFFER */ DELETE_MENU; if (!cRecordControls::PauseLiveVideo()) Skins.Message(mtError, tr("No free DVB device to record!")); @@ -1056,9 +1406,20 @@ int main(int argc, char *argv[]) break; // Instant recording: case kRecord: +#ifdef USE_LIVEBUFFER + if (!cControl::Control() && !cLiveBufferManager::GetLiveBufferControl()) { +#else if (!cControl::Control()) { +#endif /* LIVEBUFFER */ +#ifdef USE_STREAMDEVEXT + if (cRecordControls::Start()) { + Skins.Message(mtInfo, tr("Recording started")); + cStatus::MsgRecordingChange(NULL, scAdd); + } +#else if (cRecordControls::Start()) Skins.Message(mtInfo, tr("Recording started")); +#endif /* STREAMDEVEXT */ key = kNone; // nobody else needs to see this key } break; @@ -1108,14 +1469,42 @@ int main(int argc, char *argv[]) state = osEnd; } switch (state) { +#ifdef USE_LIVEBUFFER + case osPause: if (cLiveBufferManager::GetLiveBufferControl()) { + DELETE_MENU; + if (cControl::Control(true)) { + cControl::Control(true)->ProcessKey(kPlay); + cControl::Control(true)->ProcessKey(kPause); + } + break; + } + DELETE_MENU; +#else case osPause: DELETE_MENU; +#endif /* LIVEBUFFER */ cControl::Shutdown(); // just in case if (!cRecordControls::PauseLiveVideo()) Skins.Message(mtError, tr("No free DVB device to record!")); break; +#ifdef USE_LIVEBUFFER + case osRecord: if (cLiveBufferManager::GetLiveBufferControl()) { + if (cControl::Control(true)) + cControl::Control(true)->ProcessKey(kRecord); + break; + } + DELETE_MENU; +#else case osRecord: DELETE_MENU; +#endif /* LIVEBUFFER */ +#ifdef USE_STREAMDEVEXT + if (cRecordControls::Start()) { + Skins.Message(mtInfo, tr("Recording started")); + cStatus::MsgRecordingChange(NULL, scAdd); + } +#else if (cRecordControls::Start()) Skins.Message(mtInfo, tr("Recording started")); +#endif /* STREAMDEVEXT */ break; case osRecordings: DELETE_MENU; @@ -1152,6 +1541,12 @@ int main(int argc, char *argv[]) } } else { +#ifdef USE_LIVEBUFFER + eOSState state = osUnknown; + if (cLiveBufferManager::GetLiveBufferControl()) + state = cLiveBufferManager::GetLiveBufferControl()->ProcessKey(key); + if (state == osUnknown) { +#endif /* LIVEBUFFER */ // Key functions in "normal" viewing mode: if (key != kNone && KeyMacros.Get(key)) { cRemote::PutMacro(key); @@ -1166,13 +1561,26 @@ int main(int argc, char *argv[]) Channels.SwitchTo(PreviousChannel[PreviousChannelIndex ^= 1]); break; } +#ifdef USE_VOLCTRL + // Left/Right volume control +#else // Direct Channel Select: case k1 ... k9: // Left/Right rotates through channel groups: +#endif /* VOLCTRL */ case kLeft|k_Repeat: case kLeft: case kRight|k_Repeat: case kRight: +#ifdef USE_VOLCTRL + if (Setup.LRVolumeControl && Setup.LRChannelGroups < 2) { + cRemote::Put(NORMALKEY(key) == kLeft ? kVolDn : kVolUp, true); + break; + } + // else fall through + // Direct Channel Select: + case k1 ... k9: +#endif /* VOLCTRL */ // Previous/Next rotates through channel groups: case kPrev|k_Repeat: case kPrev: @@ -1183,6 +1591,10 @@ int main(int argc, char *argv[]) case kUp: case kDown|k_Repeat: case kDown: +#ifdef USE_LIVEBUFFER + if (cControl::Control(true)) + cControl::Control(true)->Hide(); +#endif /* LIVEBUFFER */ Menu = new cDisplayChannel(NORMALKEY(key)); break; // Viewing Control: @@ -1190,13 +1602,22 @@ int main(int argc, char *argv[]) // Instant resume of the last viewed recording: case kPlay: if (cReplayControl::LastReplayed()) { +#ifdef USE_PINPLUGIN + if (cStatus::MsgReplayProtected(0, cReplayControl::LastReplayed(), 0, false) == false) { +#endif /* PINPLUGIN */ cControl::Shutdown(); cControl::Launch(new cReplayControl); } +#ifdef USE_PINPLUGIN + } +#endif /* PINPLUGIN */ break; default: break; } } +#ifdef USE_LIVEBUFFER + } +#endif /* LIVEBUFFER */ if (!Menu) { if (!InhibitEpgScan) EITScanner.Process(); @@ -1266,6 +1687,9 @@ Exit: signal(SIGPIPE, SIG_DFL); signal(SIGALRM, SIG_DFL); +#ifdef USE_LIVEBUFFER + cLiveBufferManager::Shutdown(); +#endif /* LIVEBUFFER */ PluginManager.StopPlugins(); cRecordControls::Shutdown(); cCutter::Stop(); diff -ruNp vdr-1.6.0-2/vdrttxtsubshooks.c vdr-1.6.0-2-extensions/vdrttxtsubshooks.c --- vdr-1.6.0-2/vdrttxtsubshooks.c 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/vdrttxtsubshooks.c 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,46 @@ +#ifdef USE_TTXTSUBS + +#include +#include +#include + +#include "vdrttxtsubshooks.h" + +// XXX Really should be a list... +static cVDRTtxtsubsHookListener *gListener; + +// ------ class cVDRTtxtsubsHookProxy ------ + +class cVDRTtxtsubsHookProxy : public cVDRTtxtsubsHookListener +{ + public: + virtual void HideOSD(void) { if(gListener) gListener->HideOSD(); }; + virtual void ShowOSD(void) { if(gListener) gListener->ShowOSD(); }; + virtual void PlayerTeletextData(uint8_t *p, int length) + { if(gListener) gListener->PlayerTeletextData(p, length); }; + virtual cTtxtSubsRecorderBase *NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch) + { if(gListener) return gListener->NewTtxtSubsRecorder(dev, ch); else return NULL; }; +}; + + +// ------ class cVDRTtxtsubsHookListener ------ + +cVDRTtxtsubsHookListener::~cVDRTtxtsubsHookListener() +{ + gListener = 0; +} + +void cVDRTtxtsubsHookListener::HookAttach(void) +{ + gListener = this; + //printf("cVDRTtxtsubsHookListener::HookAttach\n"); +} + +static cVDRTtxtsubsHookProxy gProxy; + +cVDRTtxtsubsHookListener *cVDRTtxtsubsHookListener::Hook(void) +{ + return &gProxy; +} + +#endif /* TTXTSUBS */ diff -ruNp vdr-1.6.0-2/vdrttxtsubshooks.h vdr-1.6.0-2-extensions/vdrttxtsubshooks.h --- vdr-1.6.0-2/vdrttxtsubshooks.h 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.6.0-2-extensions/vdrttxtsubshooks.h 2009-04-09 20:48:27.000000000 +0200 @@ -0,0 +1,38 @@ +#ifdef USE_TTXTSUBS + +#ifndef __VDRTTXTSUBSHOOKS_H +#define __VDRTTXTSUBSHOOKS_H + +class cDevice; +class cChannel; + +#define VDRTTXTSUBSHOOKS + +class cTtxtSubsRecorderBase { + public: + virtual ~cTtxtSubsRecorderBase() {}; + + // returns a PES packet if there is data to add to the recording + virtual uint8_t *GetPacket(uint8_t **buf, size_t *len) { return NULL; }; + virtual void DeviceAttach(void) {}; +}; + +class cVDRTtxtsubsHookListener { + public: + cVDRTtxtsubsHookListener(void) {}; + virtual ~cVDRTtxtsubsHookListener(); + + void HookAttach(void); + + virtual void HideOSD(void) {}; + virtual void ShowOSD(void) {}; + virtual void PlayerTeletextData(uint8_t *p, int length) {}; + virtual cTtxtSubsRecorderBase *NewTtxtSubsRecorder(cDevice *dev, const cChannel *ch) + { return NULL; }; + + // used by VDR to call hook listeners + static cVDRTtxtsubsHookListener *Hook(void); +}; + +#endif /* __VDRTTXTSUBSHOOKS_H */ +#endif /* TTXTSUBS */ diff -ruNp vdr-1.6.0-2/videodir.c vdr-1.6.0-2-extensions/videodir.c --- vdr-1.6.0-2/videodir.c 2008-02-16 14:00:03.000000000 +0100 +++ vdr-1.6.0-2-extensions/videodir.c 2009-04-09 20:48:27.000000000 +0200 @@ -19,7 +19,17 @@ #include "recording.h" #include "tools.h" +#ifdef USE_HARDLINKCUTTER +//#define HARDLINK_TEST_ONLY +#ifdef USE_STREAMDEVEXT +#include "status.h" +#endif /* STREAMDEVEXT */ +#endif /* HARDLINKCUTTER */ + const char *VideoDirectory = VIDEODIR; +#ifdef USE_LIVEBUFFER +const char *BufferDirectory = NULL; +#endif /* LIVEBUFFER */ class cVideoDirectory { private: @@ -36,6 +46,11 @@ public: bool Next(void); void Store(void); const char *Adjust(const char *FileName); +#ifdef USE_DVLVIDPREFER + char *GetVidPath(int nVid); + bool GetPreferedVideoDir(void); + bool IsVidDirOK(int nVid, int *freeMB = NULL); +#endif /* DVLVIDPREFER */ }; cVideoDirectory::cVideoDirectory(void) @@ -117,6 +132,9 @@ cUnbufferedFile *OpenVideoFile(const cha if ((Flags & O_CREAT) != 0) { cVideoDirectory Dir; if (Dir.IsDistributed()) { +#ifdef USE_DVLVIDPREFER + if (Setup.UseVidPrefer == 0) { +#endif /* DVLVIDPREFER */ // Find the directory with the most free space: int MaxFree = Dir.FreeMB(); while (Dir.Next()) { @@ -126,14 +144,24 @@ cUnbufferedFile *OpenVideoFile(const cha MaxFree = Free; } } +#ifdef USE_DVLVIDPREFER + } + else Dir.GetPreferedVideoDir(); +#endif /* DVLVIDPREFER */ if (Dir.Stored()) { ActualFileName = Dir.Adjust(FileName); if (!MakeDirs(ActualFileName, false)) return NULL; // errno has been set by MakeDirs() +#ifdef USE_DVLVIDPREFER + if (strcmp(ActualFileName, FileName) != 0) { +#endif /* DVLVIDPREFER */ if (symlink(ActualFileName, FileName) < 0) { LOG_ERROR_STR(FileName); return NULL; } +#ifdef USE_DVLVIDPREFER + } +#endif /* DVLVIDPREFER */ ActualFileName = strdup(ActualFileName); // must survive Dir! } } @@ -168,6 +196,125 @@ bool RemoveVideoFile(const char *FileNam return RemoveFileOrDir(FileName, true); } +#ifdef USE_HARDLINKCUTTER +static bool StatNearestDir(const char *FileName, struct stat *Stat) +{ + cString Name(FileName); + char *p; + while ((p = strrchr((const char*)Name + 1, '/')) != NULL) { + *p = 0; // truncate at last '/' + if (stat(Name, Stat) == 0) { + isyslog("StatNearestDir: Stating %s", (const char*)Name); + return true; + } + } + return false; +} + +bool HardLinkVideoFile(const char *OldName, const char *NewName) +{ + // Incoming name must be in base video directory: + if (strstr(OldName, VideoDirectory) != OldName) { + esyslog("ERROR: %s not in %s", OldName, VideoDirectory); + return false; + } + if (strstr(NewName, VideoDirectory) != NewName) { + esyslog("ERROR: %s not in %s", NewName, VideoDirectory); + return false; + } + + const char *ActualNewName = NewName; + cString ActualOldName(ReadLink(OldName), true); + + // Some safety checks: + struct stat StatOldName; + if (lstat(ActualOldName, &StatOldName) == 0) { + if (S_ISLNK(StatOldName.st_mode)) { + esyslog("HardLinkVideoFile: Failed to resolve symbolic link %s", (const char*)ActualOldName); + return false; + } + } + else { + esyslog("HardLinkVideoFile: lstat failed on %s", (const char*)ActualOldName); + return false; + } + isyslog("HardLinkVideoFile: %s is on %i", (const char*)ActualOldName, (int)StatOldName.st_dev); + + // Find the video directory where ActualOldName is located + + cVideoDirectory Dir; + struct stat StatDir; + if (!StatNearestDir(NewName, &StatDir)) { + esyslog("HardLinkVideoFile: stat failed on %s", NewName); + return false; + } + + isyslog("HardLinkVideoFile: %s is on %i", NewName, (int)StatDir.st_dev); + if (StatDir.st_dev != StatOldName.st_dev) { + // Not yet found. + + if (!Dir.IsDistributed()) { + esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); + return false; + } + + // Search in video01 and upwards + bool found = false; + while (Dir.Next()) { + Dir.Store(); + const char *TmpNewName = Dir.Adjust(NewName); + if (StatNearestDir(TmpNewName, &StatDir) && StatDir.st_dev == StatOldName.st_dev) { + isyslog("HardLinkVideoFile: %s is on %i (match)", TmpNewName, (int)StatDir.st_dev); + ActualNewName = TmpNewName; + found = true; + break; + } + isyslog("HardLinkVideoFile: %s is on %i", TmpNewName, (int)StatDir.st_dev); + } + if (ActualNewName == NewName) { + esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName); + return false; + } + + // Looking good, we have a match. Create necessary folders. + if (!MakeDirs(ActualNewName, false)) + return false; + // There's no guarantee that the directory of ActualNewName + // is on the same device as the dir that StatNearestDir found. + // But worst case is that the link fails. + } + +#ifdef HARDLINK_TEST_ONLY + // Do the hard link to *.vdr_ for testing only + char *name = NULL; + asprintf(&name, "%s_", ActualNewName); + link(ActualOldName, name); + free(name); + return false; +#endif // HARDLINK_TEST_ONLY + + // Try creating the hard link + if (link(ActualOldName, ActualNewName) != 0) { + // Failed to hard link. Maybe not allowed on file system. + LOG_ERROR_STR(ActualNewName); + isyslog("HardLinkVideoFile: failed to hard link from %s to %s", (const char*)ActualOldName, ActualNewName); + return false; + } + + if (ActualNewName != NewName) { + // video01 and up. Do the remaining symlink + if (symlink(ActualNewName, NewName) < 0) { + LOG_ERROR_STR(NewName); + return false; + } + } +#ifdef USE_STREAMDEVEXT + cStatus::MsgRecordingChange(Recordings.GetByName(NewName), scMod); +#endif /* STREAMDEVEXT */ + return true; +} +#endif /* HARDLINKCUTTER */ + bool VideoFileSpaceAvailable(int SizeMB) { cVideoDirectory Dir; @@ -232,6 +379,129 @@ void RemoveEmptyVideoDirectories(void) } while (Dir.Next()); } +#ifdef USE_DVLVIDPREFER +// returns path to nVid'th video directory or NULL if not existing +char *cVideoDirectory::GetVidPath(int nVid) +{ + char *b = strdup(VideoDirectory); + int l = strlen(b), di, n; + + while (l-- > 0 && isdigit(b[ l ])); + + l++; + di = strlen(b) - l; + + // di == number of digits + n = atoi(&b[ l ]); + if (n != 0) + return NULL; + + // add requested number to dir name + sprintf(&b[ l ], "%0*d", di, nVid); + + if (DirectoryOk(b) == true) + return b; + + free(b); + return NULL; +} + +// checks if a video dir is 'valid' +bool cVideoDirectory::IsVidDirOK(int nVid, int *freeMB) +{ + char *dn; + int fMB; + + if (nVid >= Setup.nVidPrefer) + return false; + + if (Setup.VidPreferSize[ nVid ] == -1) + return false; + + dn = GetVidPath(nVid); + if (dn == NULL) + return false; + + fMB = FreeDiskSpaceMB(dn, NULL); + if (freeMB != NULL) + *freeMB = fMB; + + free(dn); + + if (Setup.VidPreferSize[ nVid ] >= fMB) + return false; + return true; +} + + +// calculates which video dir to use +bool cVideoDirectory::GetPreferedVideoDir(void) +{ + cVideoDirectory d; + int nDirs = 1, + vidUse = Setup.nVidPrefer; + int i, top, topFree, x; + + if (name == NULL) + return(false); + + // count available video dirs + while (d.Next() == true) + nDirs++; + + if (vidUse > nDirs) + vidUse = nDirs; + + // check for prefered video dir + for (i = 0, top = -1, topFree = 0; i < vidUse; i++) { + if (IsVidDirOK(i, &x) == true) { + if (top == -1) { + // nothing set yet, use first 'ok' dir + top = i; + topFree = x; + } + else { + // check if we got a higher priority + if (Setup.VidPreferPrio[ i ] >= Setup.VidPreferPrio[ top ]) { + top = i; + topFree = x; + } + // check if we got same priority but more space + else if (Setup.VidPreferPrio[ i ] == Setup.VidPreferPrio[ top ] && x >= topFree) { + top = i; + topFree = x; + } + } + } + } + + if (top == -1) { + isyslog("VidPrefer: no prefered video directory could be determined!"); + + // something went wrong here... + // let VDR determine the video directory + int MaxFree = FreeMB(); + + while (Next()) { + int Free = FreeDiskSpaceMB(Name()); + + if (Free > MaxFree) { + Store(); + MaxFree = Free; + } + } + } + else { + isyslog("VidPrefer: prefered video directory '%d' set.", top); + if (stored != NULL) + free(stored); + stored = GetVidPath(top); + } + + return true; +} +#endif /* DVLVIDPREFER */ + bool IsOnVideoDirectoryFileSystem(const char *FileName) { cVideoDirectory Dir; diff -ruNp vdr-1.6.0-2/videodir.h vdr-1.6.0-2-extensions/videodir.h --- vdr-1.6.0-2/videodir.h 2008-02-16 13:53:11.000000000 +0100 +++ vdr-1.6.0-2-extensions/videodir.h 2009-04-09 20:48:27.000000000 +0200 @@ -14,11 +14,17 @@ #include "tools.h" extern const char *VideoDirectory; +#ifdef USE_LIVEBUFFER +extern const char *BufferDirectory; +#endif /* LIVEBUFFER */ cUnbufferedFile *OpenVideoFile(const char *FileName, int Flags); int CloseVideoFile(cUnbufferedFile *File); bool RenameVideoFile(const char *OldName, const char *NewName); bool RemoveVideoFile(const char *FileName); +#ifdef USE_HARDLINKCUTTER +bool HardLinkVideoFile(const char *OldName, const char *NewName); +#endif /* HARDLINKCUTTER */ bool VideoFileSpaceAvailable(int SizeMB); int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent cString PrefixVideoFileName(const char *FileName, char Prefix);