diff options
Diffstat (limited to 'plugin')
-rw-r--r-- | plugin/HISTORY | 31 | ||||
-rw-r--r-- | plugin/Makefile | 111 | ||||
-rw-r--r-- | plugin/README | 99 | ||||
-rw-r--r-- | plugin/README - vps | 33 | ||||
-rw-r--r-- | plugin/TODO | 10 | ||||
-rw-r--r-- | plugin/vdrtva.c | 1042 | ||||
-rw-r--r-- | plugin/vdrtva.h | 128 | ||||
-rw-r--r-- | plugin/vdrvps-1.7.22.diff | 61 |
8 files changed, 0 insertions, 1515 deletions
diff --git a/plugin/HISTORY b/plugin/HISTORY deleted file mode 100644 index 93a7782..0000000 --- a/plugin/HISTORY +++ /dev/null @@ -1,31 +0,0 @@ -VDR Plugin 'vdrtva' Revision History -------------------------------------- - -2007-10-07: Version 0.0.1 - -- Initial experimental plugin. - -2011-06-18: Version 0.0.2 - -- First functional proof-of-concept. - -2011-07-17: Version 0.0.3 - -- Handling of Links file moved from Perl script into plugin. -- Implemented config settings. - -2011-08-18: Version 0.0.4 - -- Major functions of Perl script built into plugin. -- Auto-execution of series link updates. -- Simplified internal data structures. - -2011-09-02: Version 0.0.5 - -- Added check for series links whenever a new timer is added. -- Added setup menu (not fully tested). - -2012-01-05 Version 0.0.6 -- Configuration of update time changed. -- Fixed bug in processing of updates. -- Patch version is now deprecated. diff --git a/plugin/Makefile b/plugin/Makefile deleted file mode 100644 index 421a70e..0000000 --- a/plugin/Makefile +++ /dev/null @@ -1,111 +0,0 @@ -# -# Makefile for a Video Disk Recorder plugin -# -# $Id$ - -# The official name of this plugin. -# This name will be used in the '-P...' option of VDR to load the plugin. -# By default the main source file also carries this name. -# IMPORTANT: the presence of this macro is important for the Make.config -# file. So it must be defined, even if it is not used here! -# -PLUGIN = vdrtva - -### The version number of this plugin (taken from the main source file): - -VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') - -### The C++ compiler and options: - -CXX ?= g++ -CXXFLAGS ?= -g -O3 -Wall -Woverloaded-virtual -Wno-parentheses - -### The directory environment: - -VDRDIR = ../../.. -LIBDIR = ../../lib -TMPDIR = /tmp - -### Make sure that necessary options are included: - -include $(VDRDIR)/Make.global - -### Allow user defined options to overwrite defaults: - --include $(VDRDIR)/Make.config - -### The version number of VDR's plugin API (taken from VDR's "config.h"): - -APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) - -### The name of the distribution archive: - -ARCHIVE = $(PLUGIN)-$(VERSION) -PACKAGE = vdr-$(ARCHIVE) - -### Includes and Defines (add further entries here): - -INCLUDES += -I$(VDRDIR)/include - -DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' - -### The object files (add further files here): - -OBJS = $(PLUGIN).o - -### Implicit rules: - -%.o: %.c - $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< - -### Dependencies: - -MAKEDEP = $(CXX) -MM -MG -DEPFILE = .dependencies -$(DEPFILE): Makefile - @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ - --include $(DEPFILE) - -### Internationalization (I18N): - -PODIR = po -LOCALEDIR = $(VDRDIR)/locale -I18Npo = $(wildcard $(PODIR)/*.po) -I18Ndirs = $(notdir $(foreach file, $(I18Npo), $(basename $(file)))) -I18Npot = $(PODIR)/$(PLUGIN).pot - -%.mo: %.po - msgfmt -c -o $@ $< - -$(I18Npot): $(wildcard *.c) - xgettext -C -cTRANSLATORS --no-wrap -F -k -ktr -ktrNOOP --msgid-bugs-address='<see README>' -o $@ $(wildcard *.c) - -$(I18Npo): $(I18Npot) - msgmerge -U --no-wrap -F --backup=none -q $@ $< - -i18n: $(I18Nmo) - @mkdir -p $(LOCALEDIR) - for i in $(I18Ndirs); do\ - mkdir -p $(LOCALEDIR)/$$i/LC_MESSAGES;\ - cp $(PODIR)/$$i.mo $(LOCALEDIR)/$$i/LC_MESSAGES/$(PLUGIN).mo;\ - done - -### Targets: - -all: libvdr-$(PLUGIN).so i18n - -libvdr-$(PLUGIN).so: $(OBJS) - $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@ - @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION) - -dist: clean - @-rm -rf $(TMPDIR)/$(ARCHIVE) - @mkdir $(TMPDIR)/$(ARCHIVE) - @cp -a * $(TMPDIR)/$(ARCHIVE) - @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) - @-rm -rf $(TMPDIR)/$(ARCHIVE) - @echo Distribution package created as $(PACKAGE).tgz - -clean: - @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot diff --git a/plugin/README b/plugin/README deleted file mode 100644 index 7a9b012..0000000 --- a/plugin/README +++ /dev/null @@ -1,99 +0,0 @@ -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. See the file COPYING for more information. - -Description: - -TV-Anytime is the name given to a set of technologies which aim to simplify the -process of recording and replaying broadcast content. The standards are -published by ETSI and are available without cost from www.etsi.org. The main -standard is ETSI TS 102 323. - -In the UK a subset of the TV-Anytime specification is broadcast on the DTV -service under the trade name "FreeView Plus". This plugin is written for the UK -version but should work with the full specification (untested). - -TV-Anytime data is contained in Content Reference Identifiers (CRIDs). The -syntax of a CRID is described in RFC 4078; it is a URI-compliant string of the -form: - - crid://<DNS name>/<data> - -in which <DNS name> is a registered internet domain name (RFC 1034) and <data> -is a free-format string. The <DNS Name> section relates to the content provider -(TV channel or company), and the <data> section to the programme. - -CRIDs are transmitted in the EIT as Content Identifier Descriptors, with -descriptor ID 0x76. To save bandwith only the <data> section is sent, the <DNS -Name> part is taken from the Default Authority Descriptor in the SDT, and the -crid:// is assumed. - -A programme may have up to two CRIDs in its EPG entry. One identifies the -specific item of content which is being broadcast, while the other identifies a -series of programmes which this item belongs to. In FreeView Plus these CRIDs -have crid_type values 0x31 and 0x32 respectively (TV-Anytime uses values 0x01 -and 0x02). - -To give an example, the programme "Torchwood" broadcast on channel BBC2 at 21:00 -on 2008-01-16 had item CRID '54BXLC' and series CRID 'KCJ00C'. When the same -programme was repeated the following day on channel BBC3, the item CRID remained -the same but the series CRID was 'KCJ12C'. Meanwhile the episode broadcast on -BBC2 one week later on 2008-01-24 had CRID '54BXLD' but the same series as the -previous week. Hence it is possible for a PVR to record an entire series by -using the series CRID, or to find an alternative broadcast for an individual -item if there is a clash with another recording. - -Operation: - -The use of the 'Accurate Recording' feature is described in README-vps. - -The plugin runs every 24 hours at a time set by the '-u' parameter (default -03:00). It captures CRID data for a time (10 minutes) then: - -- Checks for new manually-created timers and adds series links for them. - -- Checks each series link to see if any new events have been added to the EPG in - the same series. If so then timers are added for them. - -- Checks for timer clashes and suggests possible alternative recording times. - -- Checks that the event being recorded by each timer is the same as when the - timer was set (ie that the EPG has not changed in the meantime) - -The plugin logs its activity through the VDR syslog. - -The plugin has an SVDRP interface which is mainly used for debugging, but could -be used to interface with other applications. The commands are: - -LSTL Print the series links list - -LSTY Print the CRIDs for each event - -LSTZ Print the Default Authority data for each channel - -STOP Start and stop CRID data capture -STRT - -UPDT Trigger an update of the series links. - -Points to remember: - -- Not all channels on UK Freeview have CRIDs in the EPG Some radio channels - have item CRIDs but none have series CRIDs. - -- Different programme providers have different ideas of what constitutes a - 'series'. - -- The timer creation process is very simplistic; it doesn't check for timer - clashes, and selects the first physical entry in the EPG (which may not be - the prime broadcast of the programme). - -- A series link is created for every timer whether you want one or not. - -- This script has not been tested with multiple tuner cards or with mixed DVB-T - and DVB-S setups. - - -Although I use this software on my VDR installation, this is Alpha-quality code -- USE AT YOUR OWN RISK!! diff --git a/plugin/README - vps b/plugin/README - vps deleted file mode 100644 index 8d172c2..0000000 --- a/plugin/README - vps +++ /dev/null @@ -1,33 +0,0 @@ -One of the important features of a video recorder is the ability to deal with -programme schedule changes and to ensure that the wanted programme is always -recorded. TVAnytime has its own set of data descriptors to handle late-running -or cancelled programmes but these are not used by Freeview Plus. Instead the -Running Status from the now/next section of the EIT is used to start and stop -the recording. - -VDR can control timers from the running status by using 'VPS' functions in -conjunction with this patch. Note however that the normal VPS operation will no -longer work. - -To use VPS for accurate recording, some conditions must be met: - -- VDR must be compiled with the 'VPS Fallback' patch (included with this - plugin). Note that some Linux distributions (esp. Mandriva) include this - patch in their binaries. -- Parameters 'UseVps' and 'VpsFallback' in setup.conf must both be set to 1 -- Timers must have the 'use VPS' flag set -- The start time of a timer must be set to exactly the scheduled start time of - the programme (ie no padding). - -With these conditions met, the sequence of events is: - -- Shortly before the scheduled time of the recording (set by 'VpsMargin' in - VDR's setup.conf) VDR switches to the multiplex containing the channel to be - recorded -- VDR monitors the running status of the programme to be recorded -- When the running status changes to 'running', VDR starts recording -- When the running status changes to 'not running', VDR stops recording and - deletes the timer. - -CAUTION - VPS recordings seem to have a lower priority than live viewing. VDR -will not interrupt live viewing to start looking for the start of a recording.
\ No newline at end of file diff --git a/plugin/TODO b/plugin/TODO deleted file mode 100644 index 9b9a913..0000000 --- a/plugin/TODO +++ /dev/null @@ -1,10 +0,0 @@ -Handle CRID 'suggestions' via new SVDRP command. - -Mail a log file after the update. - -Missing functions from Perl script: - Check split recordings - -Timer clash check code needs to cope with multiple tuner cards. - -Config file diff --git a/plugin/vdrtva.c b/plugin/vdrtva.c deleted file mode 100644 index bfc45cf..0000000 --- a/plugin/vdrtva.c +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * vdrtva.c: A plugin for the Video Disk Recorder - * - * See the README file for copyright information and how to reach the author. - * - * $Id$ - */ - -#include <vdr/plugin.h> -#include <libsi/section.h> -#include <libsi/descriptor.h> -#include <stdarg.h> -#include <getopt.h> - -#include "vdrtva.h" - -#define SVDRPOSD_BUFSIZE KILOBYTE(4) -#define SECONDSPERDAY (86400) - -cChanDAs *ChanDAs; -cEventCRIDs *EventCRIDs; -cLinks *Links; - -static const char *VERSION = "0.0.6"; -static const char *DESCRIPTION = "TV-Anytime plugin"; -static const char *MAINMENUENTRY = "vdrTva"; - -int collectionperiod; // Time to collect all CRID data (default 10 minutes) -int lifetime; // Lifetime of series link recordings (default 99) -int priority; // Priority of series link recordings (default 99) -int seriesLifetime; // Expiry time of a series link (default 30 days) -int updatetime; // Time to carry out the series link update HHMM (default 03:00) - - - -class cPluginvdrTva : public cPlugin { -private: - // Add any member variables or functions you may need here. - int length; - int size; - int flags; - int state; - time_t nextactiontime; - char *buffer; - char* configDir; - cTvaFilter *Filter; - cTvaStatusMonitor *statusMonitor; - bool Append(const char *Fmt, ...); - bool AppendItems(const char* Option); - const char* Reply(); - bool AddSeriesLink(const char *scrid, int modtime, const char *icrid); - void LoadLinksFile(void); - bool SaveLinksFile(void); - bool UpdateLinksFromTimers(void); - bool AddNewEventsToSeries(void); - void CheckChangedEvents(void); - void CheckTimerClashes(void); - void FindAlternatives(const cEvent *event); - void StartDataCapture(void); - void StopDataCapture(void); - void Update(void); - void Check(void); -// void Reset(); -public: - cPluginvdrTva(void); - virtual ~cPluginvdrTva(); - virtual const char *Version(void) { return VERSION; } - virtual const char *Description(void) { return tr(DESCRIPTION); } - virtual const char *CommandLineHelp(void); - virtual bool ProcessArgs(int argc, char *argv[]); - virtual bool Initialize(void); - virtual bool Start(void); - virtual void Stop(void); - virtual void Housekeeping(void); - virtual void MainThreadHook(void); - virtual cString Active(void); - virtual time_t WakeupTime(void); - virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; } - virtual cOsdObject *MainMenuAction(void); - virtual cMenuSetupPage *SetupMenu(void); - virtual bool SetupParse(const char *Name, const char *Value); - virtual bool Service(const char *Id, void *Data = NULL); - virtual const char **SVDRPHelpPages(void); - virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); - }; - -cPluginvdrTva::cPluginvdrTva(void) -{ - // Initialize any member variables here. - // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL - // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! - buffer = NULL; - configDir = NULL; - Filter = NULL; - ChanDAs = NULL; - EventCRIDs = NULL; - Links = NULL; - seriesLifetime = 30 * SECONDSPERDAY; - priority = 99; - lifetime = 99; - flags = 5; - state = 0; - collectionperiod = 10 * 60; - updatetime = 300; -} - -cPluginvdrTva::~cPluginvdrTva() -{ - // Clean up after yourself! - delete statusMonitor; -} - -const char *cPluginvdrTva::CommandLineHelp(void) -{ - // Return a string that describes all known command line options. - return " -l n --lifetime=n Lifetime of new timers (default 99)\n" - " -p n --priority=n Priority of new timers (default 99)\n" - " -s n --serieslifetime=n Days to remember a series after the last event (default 30)\n" - " -u HH:MM --updatetime=HH:MM Time to update series links (default 03:00)\n"; -} - -bool cPluginvdrTva::ProcessArgs(int argc, char *argv[]) -{ - // Implement command line argument processing here if applicable. - static struct option long_options[] = { - { "serieslifetime", required_argument, NULL, 's' }, - { "priority", required_argument, NULL, 'p' }, - { "lifetime", required_argument, NULL, 'l' }, - { "updatetime", required_argument, NULL, 'u' }, - { NULL } - }; - - int c, opt; - char *hours, *mins, *strtok_next; - char buf[32]; - while ((c = getopt_long(argc, argv, "l:p:s:u:", long_options, NULL)) != -1) { - switch (c) { - case 'l': - opt = atoi(optarg); - if (opt > 0) lifetime = opt; - break; - case 'p': - opt = atoi(optarg); - if (opt > 0) priority = opt; - break; - case 's': - opt = atoi(optarg); - if (opt > 0) seriesLifetime = opt * SECONDSPERDAY; - break; - case 'u': - strncpy(buf, optarg,sizeof(buf)); - hours = strtok_r(buf, ":", &strtok_next); - mins = strtok_r(NULL, "!", &strtok_next); - updatetime = atoi(hours)*100 + atoi(mins); - break; - default: - return false; - } - } - return true; -} - -bool cPluginvdrTva::Initialize(void) -{ - // Initialize any background activities the plugin shall perform. - return true; -} - -bool cPluginvdrTva::Start(void) -{ - // Start any background activities the plugin shall perform. - configDir = strcpyrealloc(configDir, cPlugin::ConfigDirectory("vdrtva")); - LoadLinksFile(); - statusMonitor = new cTvaStatusMonitor; - struct tm tm_r; - char buff[32]; - time_t now = time(NULL); - localtime_r(&now, &tm_r); - tm_r.tm_sec = 0; - tm_r.tm_hour = updatetime / 100; - tm_r.tm_min = updatetime % 100; - nextactiontime = mktime(&tm_r); - if (nextactiontime < now) nextactiontime += SECONDSPERDAY; - ctime_r(&nextactiontime, buff); - isyslog("vdrtva: next update due at %s", buff); - return true; -} - -void cPluginvdrTva::Stop(void) -{ - // Stop any background activities the plugin is performing. - if (Filter) { - delete Filter; - Filter = NULL; - } -} - -void cPluginvdrTva::Housekeeping(void) -{ - // Perform any cleanup or other regular tasks. - if (nextactiontime < time(NULL)) { - statusMonitor->ClearTimerAdded(); // Ignore any timer changes while update is in progress - switch (state) { - case 0: - StartDataCapture(); - nextactiontime += collectionperiod; - state++; - break; - case 1: - StopDataCapture(); - state++; - break; - case 2: - Update(); - state++; - break; - case 3: - Check(); - nextactiontime += (SECONDSPERDAY - collectionperiod); - state = 0; - break; - } - } - else if (EventCRIDs && statusMonitor->GetTimerAddedDelta() > 60) { - Update(); // Wait 1 minute for VDR to enter the event data into the new timer. - Check(); - statusMonitor->ClearTimerAdded(); - } -} - -void cPluginvdrTva::MainThreadHook(void) -{ - // Perform actions in the context of the main program thread. - // WARNING: Use with great care - see PLUGINS.html! -} - -cString cPluginvdrTva::Active(void) -{ - // Return a message string if shutdown should be postponed - return NULL; -} - -time_t cPluginvdrTva::WakeupTime(void) -{ - // Return custom wakeup time for shutdown script - return 0; -} - -cOsdObject *cPluginvdrTva::MainMenuAction(void) -{ - // Perform the action when selected from the main VDR menu. - return NULL; -} - -cMenuSetupPage *cPluginvdrTva::SetupMenu(void) -{ - // Return a setup menu in case the plugin supports one. - return new cTvaMenuSetup; -} - -bool cPluginvdrTva::SetupParse(const char *Name, const char *Value) -{ - // Parse your own setup parameters and store their values. - if (!strcasecmp(Name, "CollectionPeriod")) collectionperiod = atoi(Value); - else if (!strcasecmp(Name, "SeriesLifetime")) seriesLifetime = atoi(Value); - else if (!strcasecmp(Name, "TimerLifetime")) lifetime = atoi(Value); - else if (!strcasecmp(Name, "TimerPriority")) priority = atoi(Value); - else if (!strcasecmp(Name, "UpdateTime")) updatetime = atoi(Value); - else return false; - return true; -} - -bool cPluginvdrTva::Service(const char *Id, void *Data) -{ - // Handle custom service requests from other plugins - return false; -} - -const char **cPluginvdrTva::SVDRPHelpPages(void) -{ - // Return help text for SVDRP commands this plugin implements - static const char *HelpPages[] = { - "LSTL\n" - " Print the Links list.", - "LSTY\n" - " Print the Event list including CRIDs.", - "LSTZ\n" - " Print the channel list with Default Authority.", - "STOP\n" - " Stop Event data capture (retaining data).", - "STRT\n" - " Start Event data capture (erasing any existing data)", - "UPDT\n" - " Update timers and links (series link functionality)", - NULL - }; - return HelpPages; -} - -cString cPluginvdrTva::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) -{ - // Process SVDRP commands this plugin implements - isyslog ("vdrtva: processing command %s", Command); - if (strcasecmp(Command, "LSTL") == 0) { - if (Links && (Links->MaxNumber() >=1)) { - ReplyCode = 250; - for (cLinkItem *linkItem = Links->First(); linkItem; linkItem = Links->Next(linkItem)) { - Append("%s,%d;%s\n", linkItem->sCRID(), linkItem->ModTime(), linkItem->iCRIDs()); - } - } - if (buffer && length > 0) return cString(Reply(), true); - else return cString::sprintf("Nothing in the buffer!"); - } - else if (strcasecmp(Command, "LSTY") == 0) { - if (EventCRIDs && (EventCRIDs->MaxNumber() >= 1)) { - ReplyCode = 250; - for (cEventCRID *eventCRID = EventCRIDs->First(); eventCRID; eventCRID = EventCRIDs->Next(eventCRID)) { - cChanDA *chanDA = ChanDAs->GetByChannelID(eventCRID->Cid()); - if(chanDA) { - Append("%d %d %s%s %s%s\n", chanDA->Cid(), eventCRID->Eid(), chanDA->DA(), eventCRID->iCRID(), chanDA->DA(), eventCRID->sCRID()); - } - } - if (buffer && length > 0) return cString(Reply(), true); - else return cString::sprintf("Nothing in the buffer!"); - } - else - return cString::sprintf("No events defined"); - } - else if (strcasecmp(Command, "LSTZ") == 0) { - if (ChanDAs && (ChanDAs->MaxNumber() >= 1)) { - ReplyCode = 250; - for (cChanDA *chanDA = ChanDAs->First(); chanDA; chanDA = ChanDAs->Next(chanDA)) { - Append("%d %s\n", chanDA->Cid(), chanDA->DA()); - } - if (buffer && length > 0) return cString(Reply(), true); - else return cString::sprintf("Nothing in the buffer!"); - } - else - return cString::sprintf("No channels defined"); - } - else if (strcasecmp(Command, "STRT") == 0) { - if (!Filter) { - StartDataCapture(); - return cString::sprintf("Data capture started"); - } - else { - ReplyCode = 999; - return cString::sprintf("Double start attempted"); - } - } - else if (strcasecmp(Command, "STOP") == 0) { - if (Filter) { - StopDataCapture(); - return cString::sprintf("Data capture stopped"); - } - else { - ReplyCode = 999; - return cString::sprintf("Double stop attempted"); - } - } - else if (strcasecmp(Command, "UPDT") == 0) { - Update(); - Check(); - return cString::sprintf("Update completed"); - } - return NULL; -} - -bool cPluginvdrTva::Append(const char *Fmt, ...) -{ - va_list ap; - - if (!buffer) { - length = 0; - size = SVDRPOSD_BUFSIZE; - buffer = (char *) malloc(sizeof(char) * size); - } - while (buffer) { - va_start(ap, Fmt); - int n = vsnprintf(buffer + length, size - length, Fmt, ap); - va_end(ap); - - if (n < size - length) { - length += n; - return true; - } - // overflow: realloc and try again - size += SVDRPOSD_BUFSIZE; - char *tmp = (char *) realloc(buffer, sizeof(char) * size); - if (!tmp) - free(buffer); - buffer = tmp; - } - return false; -} - -const char* cPluginvdrTva::Reply() -{ - char *tmp = buffer; - buffer = NULL; - return tmp; -} - -void cPluginvdrTva::StartDataCapture() -{ - if (!Filter) { - if (EventCRIDs) delete EventCRIDs; - if (ChanDAs) delete ChanDAs; - EventCRIDs = new cEventCRIDs(); - ChanDAs = new cChanDAs(); - Filter = new cTvaFilter(); - cDevice::ActualDevice()->AttachFilter(Filter); - isyslog("vdrtva: Data capture started"); - } -} - -void cPluginvdrTva::StopDataCapture() -{ - if (Filter) { - delete Filter; - Filter = NULL; - isyslog("vdrtva: Data capture stopped"); - } -} - -void cPluginvdrTva::Update() -{ - bool status = UpdateLinksFromTimers(); - status |= AddNewEventsToSeries(); - if(status) SaveLinksFile(); - isyslog("vdrtva: Updates complete"); -} - -void cPluginvdrTva::Check() -{ - CheckChangedEvents(); - CheckTimerClashes(); - isyslog("vdrtva: Checks complete"); -} - -// add a new event to the Links table, either as an addition to an existing series or as a new series. -// return false = nothing done, true = new event for old series, or new series. - -bool cPluginvdrTva::AddSeriesLink(const char *scrid, int modtime, const char *icrid) -{ - if (Links && (Links->MaxNumber() >=1)) { - for (cLinkItem *Item = Links->First(); Item; Item = Links->Next(Item)) { - if (strcasecmp(Item->sCRID(), scrid) == 0) { - if (strstr(Item->iCRIDs(), icrid) == NULL) { - cString icrids = cString::sprintf("%s:%s", Item->iCRIDs(), icrid); - modtime = max(Item->ModTime(), modtime); - Item->Set(Item->sCRID(), modtime, icrids); - isyslog("vdrtva: Adding new event %s to series %s\n", icrid, scrid); - return true; - } - return false; - } - } - } - Links->NewLinkItem(scrid, modtime, icrid); - isyslog("vdrtva: Creating new series %s for event %s\n", scrid, icrid); - return true; -} - -void cPluginvdrTva::LoadLinksFile() -{ - Links = new cLinks(); - cString curlinks = AddDirectory(configDir, "links.data"); - FILE *f = fopen(curlinks, "r"); - if (f) { - char *s; - char *strtok_next; - cReadLine ReadLine; - cLinkItem *LinkItem; - int modtime; - while ((s = ReadLine.Read(f)) != NULL) { - char *scrid = strtok_r(s, ",", &strtok_next); - char *mtime = strtok_r(NULL, ";", &strtok_next); - char *icrids = strtok_r(NULL, "!", &strtok_next); - modtime = atoi(mtime); - LinkItem = Links->NewLinkItem(scrid, modtime, icrids); - } - fclose (f); - isyslog("vdrtva: loaded %d series links\n", Links->MaxNumber()); - } - else isyslog("vdrtva: series links file not found\n"); -} - -bool cPluginvdrTva::SaveLinksFile() -{ - cString curlinks = AddDirectory(configDir, "links.data"); - cString newlinks = AddDirectory(configDir, "links.new"); - cString oldlinks = AddDirectory(configDir, "links.old"); - FILE *f = fopen(newlinks, "w"); - if (f) { - for (cLinkItem *Item = Links->First(); Item; Item = Links->Next(Item)) { - if ((Item->ModTime() + seriesLifetime) > time(NULL)) { - fprintf(f, "%s,%d;%s\n", Item->sCRID(), Item->ModTime(), Item->iCRIDs()); - } - else { - isyslog ("vdrtva: Expiring series %s\n", Item->sCRID()); - cLinkItem *tmp = Links->Prev(Item); - if (!tmp) tmp = Links->First(); - Links->Del(Item); - Item = tmp; - } - } - fclose(f); - unlink (oldlinks); // Allow to fail if the save file does not exist - rename (curlinks, oldlinks); - rename (newlinks, curlinks); - } - return true; -} - -// Check that all timers are part of series links and update the links. - -bool cPluginvdrTva::UpdateLinksFromTimers() -{ - if ((Timers.Count() == 0) || (!EventCRIDs)) return false; - bool status = false; - for (int i = 0; i < Timers.Count(); i++) { - cTimer *timer = Timers.Get(i); - if (timer) { -// find the event for this timer - const cEvent *event = timer->Event(); - if (event) { - cChannel *channel = Channels.GetByChannelID(event->ChannelID()); -// find the sCRID and iCRID for the event - cChanDA *chanda = ChanDAs->GetByChannelID(channel->Number()); - cEventCRID *eventcrid = EventCRIDs->GetByID(channel->Number(), event->EventID()); - if (eventcrid && chanda) { - cString scrid = cString::sprintf("%s%s", chanda->DA(),eventcrid->sCRID()); - cString icrid = cString::sprintf("%s%s", chanda->DA(),eventcrid->iCRID()); -// scan the links table for the sCRID -// if found, check if the iCRID is present, if not add it -// else create a new links entry - status |= AddSeriesLink(scrid, event->StartTime(), icrid); - } - } - } - } - return status; -} - -// Find new events for series links and create timers for them. -// It would be simpler to create the timer directly from the event, but it would not then be possible to -// control the VPS parameters. - -bool cPluginvdrTva::AddNewEventsToSeries() -{ - bool saveNeeded = false; - if (!Links || (Links->MaxNumber() < 1)) return false; -// Foreach CRID - for (cEventCRID *eventCRID = EventCRIDs->First(); eventCRID; eventCRID = EventCRIDs->Next(eventCRID)) { - cChanDA *chanDA = ChanDAs->GetByChannelID(eventCRID->Cid()); - if (chanDA) { -// Check for an entry in the Links table with the same sCRID - cString scrid = cString::sprintf("%s%s", chanDA->DA(),eventCRID->sCRID()); - for (cLinkItem *Item = Links->First(); Item; Item = Links->Next(Item)) { - if (strcasecmp(Item->sCRID(), scrid) == 0) { -// if found, look for the event's icrid in ALL series - cString icrid = cString::sprintf("%s%s", chanDA->DA(),eventCRID->iCRID()); - bool done = false; - for (cLinkItem *Item2 = Links->First(); Item2; Item2 = Links->Next(Item2)) { - if (strstr(Item2->iCRIDs(), icrid) != NULL) { - done = true; - } - } -// if not found, add a new timer for the event and update the series. - if (!done) { - cChannel *channel = Channels.GetByNumber(eventCRID->Cid()); - cSchedulesLock SchedulesLock; - const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock); - if (Schedules) { - const cSchedule *schedule = Schedules->GetSchedule(channel); - if (schedule) { - const cEvent *event = schedule->GetEvent(eventCRID->Eid()); - struct tm tm_r; - char startbuff[64], endbuff[64], etitle[256]; - time_t starttime = event->StartTime(); - time_t endtime = event->EndTime(); - if (!Setup.UseVps) { - starttime -= Setup.MarginStart; - endtime += Setup.MarginStop; - } - localtime_r(&starttime, &tm_r); - strftime(startbuff, sizeof(startbuff), "%Y-%m-%d:%H%M", &tm_r); - localtime_r(&endtime, &tm_r); - strftime(endbuff, sizeof(endbuff), "%H%M", &tm_r); - strn0cpy (etitle, event->Title(), sizeof(etitle)); - strreplace(etitle, ':', '|'); - cString timercmd = cString::sprintf("%u:%d:%s:%s:%d:%d:%s:\n", flags, channel->Number(), startbuff, endbuff, priority, lifetime, etitle); - cTimer *timer = new cTimer; - if (timer->Parse(timercmd)) { - cTimer *t = Timers.GetTimer(timer); - if (!t) { - Timers.Add(timer); - Timers.SetModified(); - isyslog("vdrtva: timer %s added on %s", *timer->ToDescr(), *DateString(timer->StartTime())); - AddSeriesLink(scrid, event->StartTime(), icrid); - saveNeeded = true; - } - else isyslog("vdrtva: Duplicate timer creation attempted for %s on %s", *timer->ToDescr(), *DateString(timer->StartTime())); - } - } - } - } - } - } - } - } - return saveNeeded; -} - -// Check timers to see if the event they were set to record is still in the EPG. -// This won't work if the start time is padded. - -void cPluginvdrTva::CheckChangedEvents() -{ - if (Timers.Count() == 0) return; - for (int i = 0; i < Timers.Count(); i++) { - cTimer *timer = Timers.Get(i); - if (timer) { - const cChannel *channel = timer->Channel(); - cSchedulesLock SchedulesLock; - const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock); - if (Schedules) { - const cSchedule *schedule = Schedules->GetSchedule(channel); - if (schedule) { - const cEvent *event = schedule->GetEvent(NULL, timer->StartTime()); - if (!event) isyslog("Event for timer '%s' at %s seems to no longer exist", timer->File(), *DayDateTime(timer->StartTime())); - else if (strcmp(timer->File(), event->Title())) { - isyslog("vdrtva: Changed timer event at %s: %s <=> %s", *DayDateTime(timer->StartTime()), timer->File(), event->Title()); - } - } - } - } - } -} - -// Check for timer clashes - overlapping timers which are not on the same transponder. -// FIXME How to deal with multiple input devices?? - -void cPluginvdrTva::CheckTimerClashes(void) -{ - if (Timers.Count() < 2) return; - for (int i = 1; i < Timers.Count(); i++) { - cTimer *timer1 = Timers.Get(i); - if (timer1) { - for (int j = 0; j < i; j++) { - cTimer *timer2 = Timers.Get(j); - if (timer2) { - if((timer1->StartTime() >= timer2->StartTime() && timer1->StartTime() < timer2->StopTime()) - ||(timer2->StartTime() >= timer1->StartTime() && timer2->StartTime() < timer1->StopTime())) { - const cChannel *channel1 = timer1->Channel(); - const cChannel *channel2 = timer2->Channel(); - if (channel1->Transponder() != channel2->Transponder()) { - isyslog("vdrtva: Collision at %s. %s <=> %s", *DayDateTime(timer1->StartTime()), timer1->File(), timer2->File()); - FindAlternatives(timer1->Event()); - FindAlternatives(timer2->Event()); - } - } - } - } - } - } -} - -void cPluginvdrTva::FindAlternatives(const cEvent *event) -{ - if (!event) return; - cChannel *channel = Channels.GetByChannelID(event->ChannelID()); - cChanDA *chanda = ChanDAs->GetByChannelID(channel->Number()); - cEventCRID *eventcrid = EventCRIDs->GetByID(channel->Number(), event->EventID()); - if (!eventcrid || !chanda) return; - - bool found = false; - for (cEventCRID *eventcrid2 = EventCRIDs->First(); eventcrid2; eventcrid2 = EventCRIDs->Next(eventcrid2)) { - if ((strcmp(eventcrid->iCRID(), eventcrid2->iCRID()) == 0) && (event->EventID() != eventcrid2->Eid())) { - cChanDA *chanda2 = ChanDAs->GetByChannelID(eventcrid2->Cid()); - if (strcmp(chanda->DA(), chanda2->DA()) == 0) { - cChannel *channel2 = Channels.GetByNumber(eventcrid2->Cid()); - cSchedulesLock SchedulesLock; - const cSchedules *schedules = cSchedules::Schedules(SchedulesLock); - if (schedules) { - const cSchedule *schedule = schedules->GetSchedule(channel2); - if (schedule) { - const cEvent *event2 = schedule->GetEvent(eventcrid2->Eid(), 0); - if (!found) { - isyslog("vdrtva: Alternatives for '%s':", event->Title()); - found = true; - } - isyslog("vdrtva: %s %s", channel2->Name(), *DayDateTime(event2->StartTime())); - } - } - } - } - } - if (!found) isyslog("vdrtva: No alternatives for '%s':", event->Title()); -} - - -/* - cTvaStatusMonitor - callback for timer changes. -*/ - -cTvaStatusMonitor::cTvaStatusMonitor(void) -{ - timeradded = NULL; -} - -void cTvaStatusMonitor::TimerChange(const cTimer *Timer, eTimerChange Change) -{ - if (Change == tcAdd) timeradded = time(NULL); -} - -int cTvaStatusMonitor::GetTimerAddedDelta(void) -{ - if (timeradded) { - return (time(NULL) - timeradded); - } - return 0; -} - -void cTvaStatusMonitor::ClearTimerAdded(void) -{ - timeradded = NULL; - return; -} - - -/* - cTvaMenuSetup - setup menu function. -*/ - -cTvaMenuSetup::cTvaMenuSetup(void) -{ - newcollectionperiod = collectionperiod; - newlifetime = lifetime; - newpriority = priority; - newseriesLifetime = seriesLifetime; - newupdatetime = updatetime; - Add(new cMenuEditIntItem(tr("Collection period (min)"), &newcollectionperiod)); - Add(new cMenuEditIntItem(tr("Series link lifetime (days)"), &newseriesLifetime)); - Add(new cMenuEditIntItem(tr("New timer lifetime"), &newlifetime)); - Add(new cMenuEditIntItem(tr("New timer priority"), &newpriority)); - Add(new cMenuEditIntItem(tr("Update Time (HHMM)"), &newupdatetime)); -} - -void cTvaMenuSetup::Store(void) -{ - SetupStore("CollectionPeriod", newcollectionperiod); - SetupStore("SeriesLifetime", newseriesLifetime); - SetupStore("TimerLifetime", newlifetime); - SetupStore("TimerPriority", newpriority); - SetupStore("UpdateTime", newupdatetime); -} - - - -/* - cTvaFilter - capture the CRID data from EIT. -*/ - -cTvaFilter::cTvaFilter(void) -{ - Set(0x11, 0x42); // SDT (Actual) - Set(0x11, 0x46); // SDT (Other) - Set(0x12, 0x40, 0xC0); // event info, actual(0x4E)/other(0x4F) TS, present/following - // event info, actual TS, schedule(0x50)/schedule for future days(0x5X) - // event info, other TS, schedule(0x60)/schedule for future days(0x6X) -} - -void cTvaFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) -{ - // do something with the data here - switch (Pid) { - case 0x11: { - sectionSyncer.Reset(); - SI::SDT sdt(Data, false); - if (!sdt.CheckCRCAndParse()) { - dsyslog ("vdrtva: SDT Parse / CRC error\n"); - return; - } - if (!sectionSyncer.Sync(sdt.getVersionNumber(), sdt.getSectionNumber(), sdt.getLastSectionNumber())) { - dsyslog ("vdrtva: SDT Syncer error\n"); - return; - } - SI::SDT::Service SiSdtService; - for (SI::Loop::Iterator it; sdt.serviceLoop.getNext(SiSdtService, it); ) { - cChannel *chan = Channels.GetByChannelID(tChannelID(Source(),sdt.getOriginalNetworkId(),sdt.getTransportStreamId(),SiSdtService.getServiceId())); - if (chan) { - cChanDA *chanDA = ChanDAs->GetByChannelID(chan->Number()); - if (!chanDA) { - SI::Descriptor *d; - for (SI::Loop::Iterator it2; (d = SiSdtService.serviceDescriptors.getNext(it2)); ) { - switch (d->getDescriptorTag()) { - case SI::DefaultAuthorityDescriptorTag: { - SI::DefaultAuthorityDescriptor *da = (SI::DefaultAuthorityDescriptor *)d; - char DaBuf[Utf8BufSize(1024)]; - da->DefaultAuthority.getText(DaBuf, sizeof(DaBuf)); - chanDA = ChanDAs->NewChanDA(chan->Number()); - chanDA->SetDA(DaBuf); - } - break; - default: ; - } - delete d; - } - } - } - } - } - case 0x12: { - if (Tid >= 0x4E && Tid <= 0x6F) { -// sectionSyncer.Reset(); - SI::EIT eit(Data, false); - if (!eit.CheckCRCAndParse()) { - dsyslog ("vdrtva: EIT Parse / CRC error\n"); - return; - } - - cChannel *chan = Channels.GetByChannelID(tChannelID(Source(),eit.getOriginalNetworkId(),eit.getTransportStreamId(),eit.getServiceId())); - if (!chan) { - return; - } - SI::EIT::Event SiEitEvent; - for (SI::Loop::Iterator it; eit.eventLoop.getNext(SiEitEvent, it); ) { - cEventCRID *eventCRID = EventCRIDs->GetByID(chan->Number(), SiEitEvent.getEventId()); - if (!eventCRID) { - SI::Descriptor *d; - char iCRIDBuf[Utf8BufSize(1024)] = {'\0'}, sCRIDBuf[Utf8BufSize(1024)] = {'\0'}; - for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) { - switch (d->getDescriptorTag()) { - case SI::ContentIdentifierDescriptorTag: { - SI::ContentIdentifierDescriptor *cd = (SI::ContentIdentifierDescriptor *)d; - SI::ContentIdentifierDescriptor::Identifier cde; - for (SI::Loop::Iterator ite; (cd->identifierLoop.getNext(cde,ite)); ) { - if (cde.getCridLocation() == 0) { - switch (cde.getCridType()) { - case 0x01: // ETSI 102 363 code - case 0x31: // UK Freeview private code - cde.identifier.getText(iCRIDBuf, sizeof(iCRIDBuf)); - break; - case 0x02: // ETSI 102 363 code - case 0x32: // UK Freeview private code - cde.identifier.getText(sCRIDBuf, sizeof(sCRIDBuf)); - // ETSI 102 323 defines CRID type 0x03, which describes 'related' or 'suggested' events. - // Freeview broadcasts these as CRID type 0x33. - // There can be more than one type 0x33 descriptor per event (each with one CRID). - } - } - else { - dsyslog ("vdrtva: Incorrect CRID Loc %x\n", cde.getCridLocation()); - } - } - } - break; - default: ; - } - delete d; - } - if (iCRIDBuf[0] && sCRIDBuf[0]) { // Only log events which are part of a series. - eventCRID = EventCRIDs->NewEventCRID(chan->Number(), SiEitEvent.getEventId()); - eventCRID->SetCRIDs(iCRIDBuf, sCRIDBuf); - } - } - } - } - } - break; - } -} - - -/* - cChanDA - Default Authority for a channel. -*/ - -cChanDA::cChanDA(void) -{ - defaultAuthority = NULL; -} - -cChanDA::~cChanDA(void) -{ - free(defaultAuthority); -} - - -void cChanDA::Set(int Cid) { - cid = Cid; -} - -void cChanDA::SetDA(char *DA) { - defaultAuthority = strcpyrealloc(defaultAuthority, DA); -} - -/* - cChanDAs - in-memory list of channels and Default Authorities. -*/ - -cChanDAs::cChanDAs(void) -{ - maxNumber = 0; -} - -cChanDAs::~cChanDAs(void) -{ - chanDAHash.Clear(); -} - -cChanDA *cChanDAs::GetByChannelID(int cid) -{ - cList<cHashObject> *list = chanDAHash.GetList(cid); - if (list) { - for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { - cChanDA *chanDA = (cChanDA *)hobj->Object(); - if (chanDA->Cid() == cid) - return chanDA; - } - } - return NULL; -} - -cChanDA *cChanDAs::NewChanDA(int Cid) -{ - cChanDA *NewChanDA = new cChanDA; - NewChanDA->Set(Cid); - Add(NewChanDA); - chanDAHash.Add(NewChanDA, Cid); - ChanDAs->SetMaxNumber(ChanDAs->MaxNumber()+1); - return NewChanDA; -} - - -/* - cEventCRID - CRIDs for an event. -*/ - -cEventCRID::cEventCRID(void) -{ - iCrid = sCrid = NULL; -} - -cEventCRID::~cEventCRID(void) -{ - free (iCrid); - free (sCrid); -} - -void cEventCRID::Set(int Cid, tEventID Eid) { - eid = Eid; - cid = Cid; -} - -void cEventCRID::SetCRIDs(char *iCRID, char *sCRID) { - iCrid = strcpyrealloc(iCrid, iCRID); - sCrid = strcpyrealloc(sCrid, sCRID); -} - - -/* - cEventCRIDs - in-memory list of events and CRIDs. -*/ - -cEventCRIDs::cEventCRIDs(void) -{ - maxNumber = 0; -} - -cEventCRIDs::~cEventCRIDs(void) -{ - EventCRIDHash.Clear(); -} - -cEventCRID *cEventCRIDs::GetByID(int Cid, tEventID Eid) -{ - cList<cHashObject> *list = EventCRIDHash.GetList(Cid*33000 + Eid); - if (list) { - for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { - cEventCRID *EventCRID = (cEventCRID *)hobj->Object(); - if ((EventCRID->Eid() == Eid) && (EventCRID->Cid() == Cid)) - return EventCRID; - } - } - return NULL; -} - -cEventCRID *cEventCRIDs::NewEventCRID(int Cid, tEventID Eid) -{ - cEventCRID *NewEventCRID = new cEventCRID; - NewEventCRID->Set(Cid, Eid); - Add(NewEventCRID); - EventCRIDHash.Add(NewEventCRID, Eid + Cid*33000); - EventCRIDs->SetMaxNumber(EventCRIDs->MaxNumber()+1); - return NewEventCRID; -} - - -/* - cLinkItem - Entry from the links file -*/ - -cLinkItem::cLinkItem(void) -{ - sCrid = iCrids = NULL; -} - -cLinkItem::~cLinkItem(void) -{ - free(sCrid); - free(iCrids); -} - -void cLinkItem::Set(const char *sCRID, int ModTime, const char *iCRIDs) -{ - sCrid = strcpyrealloc(sCrid, sCRID); - modtime = ModTime; - iCrids = strcpyrealloc(iCrids, iCRIDs); -} - -/* - cLinks - list of cLinkItem entities -*/ - -cLinks::cLinks(void) -{ - maxNumber = 0; -} - -cLinkItem *cLinks::NewLinkItem(const char *sCRID, int ModTime, const char *iCRIDs) -{ - cLinkItem *NewLinkItem = new cLinkItem; - NewLinkItem->Set(sCRID, ModTime, iCRIDs); - Add(NewLinkItem); - Links->SetMaxNumber(Links->MaxNumber()+1); - return NewLinkItem; -} - -VDRPLUGINCREATOR(cPluginvdrTva); // Don't touch this! diff --git a/plugin/vdrtva.h b/plugin/vdrtva.h deleted file mode 100644 index 4149b0c..0000000 --- a/plugin/vdrtva.h +++ /dev/null @@ -1,128 +0,0 @@ -#include <vdr/filter.h> -#include <vdr/device.h> -#include <vdr/status.h> - -class cTvaFilter : public cFilter { -private: - cSectionSyncer sectionSyncer; - cPatFilter *patFilter; -protected: - virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length); -public: - cTvaFilter(void); -}; - -class cTvaStatusMonitor : public cStatus { - private: - time_t timeradded; - protected: - virtual void TimerChange(const cTimer *Timer, eTimerChange Change); - // Indicates a change in the timer settings. - // If Change is tcAdd or tcDel, Timer points to the timer that has - // 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. - public: - cTvaStatusMonitor(void); - int GetTimerAddedDelta(void); - void ClearTimerAdded(void); -}; - - -class cTvaMenuSetup : public cMenuSetupPage { -private: - int newcollectionperiod; - int newlifetime; - int newpriority; - int newseriesLifetime; - int newupdatehours; - int newupdatemins; -protected: - virtual void Store(void); -public: - cTvaMenuSetup(void); -}; - - -class cChanDA : public cListObject { - private: - int cid; - char *defaultAuthority; - public: - cChanDA(void); - ~cChanDA(void); - int Cid(void) { return cid; } - void Set(int Cid); - char * DA(void) { return defaultAuthority; } - void SetDA(char *DA); -}; - -class cChanDAs : public cRwLock, public cConfig<cChanDA> { - private: - int maxNumber; - cHash<cChanDA> chanDAHash; - public: - cChanDAs(void); - ~cChanDAs(void); - int MaxNumber(void) { return maxNumber; } - void SetMaxNumber(int number) { maxNumber = number; } - cChanDA *GetByChannelID(int cid); - cChanDA *NewChanDA(int Cid); -}; - - -class cEventCRID : public cListObject { - private: - tEventID eid; - int cid; - char *iCrid; - char *sCrid; - public: - cEventCRID(void); - ~cEventCRID(void); - tEventID Eid(void) { return eid; } - void Set(int Cid, tEventID Eid); - char * iCRID(void) { return iCrid; } - char * sCRID(void) { return sCrid; } - void SetCRIDs(char *iCRID, char *sCRID); - int Cid(void) { return cid; } -}; - -class cEventCRIDs : public cRwLock, public cConfig<cEventCRID> { - private: - int maxNumber; - cHash<cEventCRID> EventCRIDHash; - public: - cEventCRIDs(void); - ~cEventCRIDs(void); - int MaxNumber(void) { return maxNumber; } - void SetMaxNumber(int number) { maxNumber = number; } - cEventCRID *GetByID(int Cid, tEventID Eid); - cEventCRID *NewEventCRID(int Cid, tEventID Eid); -}; - - -class cLinkItem : public cListObject { - private: - char *sCrid; - int modtime; - char *iCrids; - public: - cLinkItem(void); - ~cLinkItem(void); - void Set(const char *sCRID, int ModTime, const char *iCRIDs); - char * iCRIDs(void) { return iCrids; } - char * sCRID(void) { return sCrid; } - int ModTime(void) { return modtime; } -}; - -class cLinks : public cRwLock, public cConfig<cLinkItem> { - private: - int maxNumber; - public: - cLinks(void); -// ~cLinks(void); - int MaxNumber(void) { return maxNumber; } - void SetMaxNumber(int number) { maxNumber = number; } - cLinkItem *NewLinkItem(const char *sCRID, int ModTime, const char *iCRIDs); -}; diff --git a/plugin/vdrvps-1.7.22.diff b/plugin/vdrvps-1.7.22.diff deleted file mode 100644 index c851995..0000000 --- a/plugin/vdrvps-1.7.22.diff +++ /dev/null @@ -1,61 +0,0 @@ -diff -u vdr-1.7.22/config.c vdr-1.7/config.c ---- vdr-1.7.22/config.c 2011-12-03 15:21:30.000000000 +0000 -+++ vdr-1.7/config.c 2011-12-14 15:19:34.000000000 +0000 -@@ -416,6 +416,7 @@ - UseSubtitle = 1; - UseVps = 0; - VpsMargin = 120; -+ VpsFallback = 0; - RecordingDirs = 1; - FoldersInTimerMenu = 1; - NumberKeysForChars = 1; -@@ -610,6 +611,7 @@ - else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value); - else if (!strcasecmp(Name, "UseVps")) UseVps = atoi(Value); - else if (!strcasecmp(Name, "VpsMargin")) VpsMargin = atoi(Value); -+ else if (!strcasecmp(Name, "VpsFallback")) VpsFallback = atoi(Value); - else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value); - else if (!strcasecmp(Name, "FoldersInTimerMenu")) FoldersInTimerMenu = atoi(Value); - else if (!strcasecmp(Name, "NumberKeysForChars")) NumberKeysForChars = atoi(Value); -@@ -707,6 +709,7 @@ - Store("UseSubtitle", UseSubtitle); - Store("UseVps", UseVps); - Store("VpsMargin", VpsMargin); -+ Store("VpsFallback", VpsFallback); - Store("RecordingDirs", RecordingDirs); - Store("FoldersInTimerMenu", FoldersInTimerMenu); - Store("NumberKeysForChars", NumberKeysForChars); -diff -u vdr-1.7.22/config.h vdr-1.7/config.h ---- vdr-1.7.22/config.h 2011-12-03 14:19:52.000000000 +0000 -+++ vdr-1.7/config.h 2011-12-14 15:19:34.000000000 +0000 -@@ -271,6 +271,7 @@ - int UseSubtitle; - int UseVps; - int VpsMargin; -+ int VpsFallback; - int RecordingDirs; - int FoldersInTimerMenu; - int NumberKeysForChars; -diff -u vdr-1.7.22/menu.c vdr-1.7/menu.c ---- vdr-1.7.22/menu.c 2011-12-04 14:52:38.000000000 +0000 -+++ vdr-1.7/menu.c 2011-12-14 15:19:34.000000000 +0000 -@@ -3092,6 +3092,7 @@ - Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle)); - 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$Use running status as VPS fallback"), &data.VpsFallback)); - 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)); -diff -u vdr-1.7.22/timers.c vdr-1.7/timers.c ---- vdr-1.7.22/timers.c 2011-08-06 14:13:54.000000000 +0100 -+++ vdr-1.7/timers.c 2011-12-14 15:19:34.000000000 +0000 -@@ -430,7 +430,7 @@ - deferred = 0; - - if (HasFlags(tfActive)) { -- if (HasFlags(tfVps) && event && event->Vps()) { -+ if (HasFlags(tfVps) && event && (Setup.VpsFallback || event->Vps())) { - if (Margin || !Directly) { - startTime = event->StartTime(); - stopTime = event->EndTime(); |