/// <summary> /// Erzeugt eine neue Planung. /// </summary> /// <param name="resource">Das zugehörige Gerät.</param> /// <param name="schedulePlan">Die zugehörige Gesamtplanung.</param> /// <param name="decryptionCounter">Die Zähler für die Entschlüsselung.</param> /// <param name="allocations">Optional alle bereits vorgenommenen Zuordnungen.</param> /// <param name="planTime">Der aktuelle Planungsbeginn, sofern bekannt.</param> /// <exception cref="ArgumentNullException">Es wurde kein Gerät angegeben.</exception> public ResourcePlan(IScheduleResource resource, SchedulePlan schedulePlan, HashSet <Guid> decryptionCounter = null, AllocationMap allocations = null, DateTime?planTime = null) { // Remember SchedulePlan = schedulePlan; Resource = resource; // Register a single decryption counter DecryptionCounters = decryptionCounter ?? new HashSet <Guid> { schedulePlan.RegisterDecryption(Resource.Decryption.MaximumParallelSources) }; // Check for allocation if (allocations != null) { // Just clone Allocations = allocations.Clone(planTime); } else { // Number of sources we may use var sourceLimit = resource.SourceLimit; if (sourceLimit < 1) { sourceLimit = int.MaxValue; } // Create brand new Allocations = new AllocationMap(sourceLimit, CheckForSourceGroupMatch); } }
/// <summary> /// Erzeugt eine neue Beschreibung. /// </summary> /// <param name="definition">Die ursprüngliche Beschreibung der Aufzeichnung.</param> /// <param name="resource">Das zu verwendende Gerät.</param> /// <param name="time">Die tatsächliche Ausführungszeit.</param> /// <param name="late">Gesetzt, wenn die Ausführung verspätet beginnt.</param> internal ScheduleInfo( IScheduleDefinition definition, IScheduleResource resource, PlannedTime time, bool late ) { // Remember Definition = definition; Resource = resource; StartsLate = late; Time = time; }
/// <summary> /// Erzeugt eine neue Beschreibung. /// </summary> /// <param name="definition">Die ursprüngliche Beschreibung der Aufzeichnung.</param> /// <param name="resource">Das zu verwendende Gerät.</param> /// <param name="time">Die tatsächliche Ausführungszeit.</param> /// <param name="late">Gesetzt, wenn die Ausführung verspätet beginnt.</param> internal ScheduleInfo(IScheduleDefinition definition, IScheduleResource resource, PlannedTime time, bool late) { // Remember Definition = definition; Resource = resource; StartsLate = late; Time = time; }
/// <summary> /// Ergänzt ein Gerät. /// </summary> /// <param name="resource">Das gewünschte Gerät.</param> public void Add(IScheduleResource resource) { // Not allowed if (m_CurrentPlan != null) { throw new NotSupportedException("Add"); } // Forward m_Resources.Add(resource); }
/// <summary> /// Aktiviert eine Aufzeichnung auf einem Gerät. /// </summary> /// <param name="resource">Eines der verwalteten Geräte.</param> /// <param name="source">Optional eine Quelle, die auf dem Gerät angesteuert werden kann.</param> /// <param name="scheduleIdentifier">Die eindeutige Kennung der Aufzeichnung.</param> /// <param name="scheduleName">Der Anzeigename der Aufzeichnung.</param> /// <param name="plannedStart">Der ursprüngliche Start der Aufzeichnung in UTC / GMT Notation.</param> /// <param name="currentEnd">Das aktuelle Ende der Aufzeichnung in UTC / GMT Notation.</param> /// <returns>Gesetzt, wenn die Aufzeichnung auf dem gewünschten Gerät aktiviert werden kann.</returns> /// <exception cref="ArgumentNullException">Es wurde kein Gerät angegeben.</exception> /// <exception cref="ArgumentException">Das Gerät ist nicht bekannt oder kann die Quelle nicht empfangen.</exception> /// <exception cref="ArgumentOutOfRangeException">Die Laufzeit der Aufzeichnung ist nicht positiv.</exception> public bool Start(IScheduleResource resource, IScheduleSource source, Guid scheduleIdentifier, string scheduleName, DateTime plannedStart, DateTime currentEnd) { // Validate if (resource == null) { throw new ArgumentNullException("resource"); } if (!m_Resources.Contains(resource)) { throw new ArgumentException(resource.Name, "resource"); } if (plannedStart >= currentEnd) { throw new ArgumentOutOfRangeException("currentEnd"); } if (m_Recordings.Any(r => r.UniqueIdentifier == scheduleIdentifier)) { throw new ArgumentException("resource"); } // Create helper entry m_Recordings.Add(new ResourceAllocationInformation(resource, source, scheduleIdentifier, scheduleName, plannedStart, currentEnd - plannedStart)); // May require cleanup try { // Create the new plan var plan = CreateSchedulePlan(); // Did it if (plan != null) { // Remember as current m_CurrentPlan = plan; // Report return(true); } } catch { // Cleanup m_Recordings.RemoveAt(m_Recordings.Count - 1); // Report throw; } // Cleanup m_Recordings.RemoveAt(m_Recordings.Count - 1); // Add to list return(false); }
/// <summary> /// Erstellt einen periodischen Auftrag für die Aktualisierung der Liste der Quellen. /// </summary> /// <param name="resource">Die zu verwendende Ressource.</param> /// <param name="profile">Das zugehörige Geräteprofil.</param> /// <returns>Der gewünschte Auftrag.</returns> PeriodicScheduler IRecordingPlannerSite.CreateSourceScanTask(IScheduleResource resource, Profile profile) { // Protect against misuse if (m_profiles.TryGetValue(profile.Name, out ProfileState state)) { return(new SourceListTask(resource, state)); } else { return(null); } }
/// <summary> /// Erzeugt eine neue Beschreibung. /// </summary> /// <param name="resource">Das zugehörige Gerät.</param> /// <param name="source">Optional die zu verwendende Quelle.</param> /// <param name="identifier">Die eindeutige Kennung der zugehörigen Aufzeichnung oder Aufgabe.</param> /// <param name="name">Der Name der Aufzeichnung.</param> /// <param name="start">Der Startzeitpunkt.</param> /// <param name="duration">Die Dauer der Aufzeichnung.</param> /// <exception cref="ArgumentOutOfRangeException">Die Dauer der Aufzeichnung ist negativ.</exception> public ResourceAllocationInformation( IScheduleResource resource, IScheduleSource source, Guid identifier, string name, DateTime start, TimeSpan duration ) { // Validate if (duration.TotalSeconds <= 0) throw new ArgumentOutOfRangeException( "duration" ); // Remember all Time = new PlannedTime { Start = start, Duration = duration }; Resources = new[] { resource }; UniqueIdentifier = identifier; Source = source; Name = name; }
/// <summary> /// Erstellt einen periodischen Auftrag für die Aktualisierung der Programmzeitschrift. /// </summary> /// <param name="resource">Die zu verwendende Ressource.</param> /// <param name="profile">Das zugehörige Geräteprofil.</param> /// <returns>Der gewünschte Auftrag.</returns> PeriodicScheduler IRecordingPlannerSite.CreateProgramGuideTask(IScheduleResource resource, Profile profile) { // Protect against misuse ProfileState state; if (m_profiles.TryGetValue(profile.Name, out state)) { return(new ProgramGuideTask(resource, state)); } else { return(null); } }
/// <summary> /// Default constructor for <see cref="FeedingManager"/> /// </summary> /// <param name="schedulingEngine"></param> public DefaultFeedingManager(IOptions <FeedingManagerOptions> options, ILogger <DefaultFeedingManager> logger, ISchedulingEngine schedulingEngine, IThingsResource thingsResource, IScheduleResource scheduleResource) { _schedulingEngine = schedulingEngine; _logger = logger; _scheduleResource = scheduleResource; Slots = new List <FeedingSlot>(); if (options.Value?.FeedingSlots?.Any() == true) { foreach (var slotConfig in options.Value.FeedingSlots) { Slots.Add(new FeedingSlot(slotConfig, Slots, thingsResource)); } } }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Geräteprofil, auf dem der Lauf erfolgen soll.</param> /// <param name="profile">Das zugehörige Geräteprofil.</param> /// <param name="lastUpdate">Methode zur Ermittelung des letzten Aktualisierungszeitpunktes.</param> /// <exception cref="ArgumentNullException">Der letzte Aktualisierungszeitpunkt ist nicht gesetzt.</exception> private SourceListTask( IScheduleResource forResource, ProfileState profile, Func<DateTime?> lastUpdate ) : base( "Sendersuchlauf", Guid.NewGuid() ) { // Validate if (forResource == null) throw new ArgumentNullException( nameof( forResource ) ); if (lastUpdate == null) throw new ArgumentNullException( nameof( lastUpdate ) ); // Remember m_Resources = new[] { forResource }; m_LastUpdate = lastUpdate; // Set the job directory if (profile != null) CollectorDirectory = profile.Server.JobManager.CollectorDirectory; }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Geräteprofil, auf dem der Lauf erfolgen soll.</param> /// <param name="profile">Das zugehörige Geräteprofil.</param> /// <param name="lastUpdate">Methode zur Ermittelung des letzten Aktualisierungszeitpunktes.</param> /// <exception cref="ArgumentNullException">Der letzte Aktualisierungszeitpunkt ist nicht gesetzt.</exception> private SourceListTask(IScheduleResource forResource, ProfileState profile, Func <DateTime?> lastUpdate) : base("Sendersuchlauf", Guid.NewGuid()) { // Validate if (forResource == null) { throw new ArgumentNullException(nameof(forResource)); } if (lastUpdate == null) { throw new ArgumentNullException(nameof(lastUpdate)); } // Remember m_Resources = new[] { forResource }; m_LastUpdate = lastUpdate; // Set the job directory if (profile != null) { CollectorDirectory = profile.Server.JobManager.CollectorDirectory; } }
/// <summary> /// Erstellt eine periodische Aufgabe zum Aktualisieren der Quellen. /// </summary> /// <param name="resource">Die zugehörige Ressource.</param> /// <param name="profile">Die vollen Informationen zum Geräteprofil.</param> /// <returns>Die Beschreibung der Aufgabe oder <i>null</i>.</returns> public PeriodicScheduler CreateSourceScanTask(IScheduleResource resource, Profile profile) { // Forward return(new SourceListTask(resource, () => m_lastRunScan[resource.Name])); }
/// <summary> /// Erstellt eine periodische Aufgabe zum Aktualisieren der Programmzeitschrift. /// </summary> /// <param name="resource">Die zugehörige Ressource.</param> /// <param name="profile">Die vollen Informationen zum Geräteprofil.</param> /// <returns>Die Beschreibung der Aufgabe oder <i>null</i>.</returns> public PeriodicScheduler CreateProgramGuideTask(IScheduleResource resource, Profile profile) { // Forward return(new ProgramGuideTask(resource, () => m_lastRunGuide[resource.Name])); }
/// <summary> /// Erzeugt eine neue Simulation. /// </summary> /// <param name="resource">Das zu verwendende Gerät.</param> public _TaskMock( IScheduleResource resource ) : base( "task", Guid.NewGuid() ) { // Remember m_Resources = new[] { resource }; }
public SystemController(IThingsResource thingsResource, IScheduleResource scheduleResource, IFeedingManager feedingManager) { _thingsResource = thingsResource; _scheduleResource = scheduleResource; _feedingManager = feedingManager; }
/// <summary> /// Erzeugt eine neue Simulation. /// </summary> /// <param name="resource">Das zu verwendende Gerät.</param> public _TaskMock(IScheduleResource resource) : base("task", Guid.NewGuid()) { // Remember m_Resources = new[] { resource }; }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Geräteprofil, auf dem der Lauf erfolgen soll.</param> /// <param name="profile">Das zugehörige Geräteprofil.</param> public SourceListTask(IScheduleResource forResource, ProfileState profile) : this(forResource, profile, () => profile.LastSourceUpdateTime) { }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Geräteprofil, auf dem der Lauf erfolgen soll.</param> /// <param name="lastUpdate">Methode zur Ermittelung des letzten Aktualisierungszeitpunktes.</param> public SourceListTask(IScheduleResource forResource, Func <DateTime?> lastUpdate) : this(forResource, null, lastUpdate) { }
/// <summary> /// Erstellt eine periodische Aufgabe zum Aktualisieren der Programmzeitschrift. /// </summary> /// <param name="resource">Die zugehörige Ressource.</param> /// <param name="profile">Die vollen Informationen zum Geräteprofil.</param> /// <returns>Die Beschreibung der Aufgabe oder <i>null</i>.</returns> public PeriodicScheduler CreateProgramGuideTask( IScheduleResource resource, Profile profile ) { // Forward return new ProgramGuideTask( resource, () => m_lastRunGuide[resource.Name] ); }
/// <summary> /// Meldet ein Gerät zur Verwendung an. /// </summary> /// <param name="resource">Das gewünschte Gerät.</param> public void Add(IScheduleResource resource) { // Blind forward Resources.Add(resource); }
/// <summary> /// Diese Methode verteilt Aufgaben an Geräte, die eine Zeitlang nicht in Benutzung sind. /// </summary> /// <param name="resource">Das zu verwendende Gerät.</param> /// <param name="startFree">Der Anfang des unbenutzten Bereiches.</param> /// <param name="endFree">Das Ende des unbenutzten Bereiches.</param> /// <param name="tasks">Die Liste der Aufgaben.</param> /// <returns>Alle Aufgaben, die dem Gerät in der unbenutzten Zeit zugeordnet wurden.</returns> private IEnumerable <ScheduleInfo> DispatchTasksForResource(IScheduleResource resource, DateTime startFree, DateTime endFree, List <_Task> tasks) { // See if there is room left to run a task while ((tasks.Count > 0) && (endFree > startFree)) { // Load duration var duration = endFree - startFree; // Best task var tiBest = -1; // From all tasks fitting choose the one which starts first for (var ti = 0; ti < tasks.Count; ti++) { // See if resource could be used var task = tasks[ti]; if (!task.AllowedResources.Contains(resource, ReferenceComparer <IScheduleResource> .Default)) { continue; } // Not enough time - skip var planned = task.Current.Planned; if (planned.Duration.Ticks <= 0) { continue; } if (planned.Duration > duration) { continue; } // Will not end before resource is reused if (planned.End > endFree) { continue; } // Check for best if (tiBest < 0) { tiBest = ti; } else if (planned.Start < tasks[tiBest].Current.Planned.Start) { tiBest = ti; } } // Found nothing if (tiBest < 0) { break; } // Reload var bestTask = tasks[tiBest]; var bestPlan = bestTask.Current; // Check mode var startsLate = bestPlan.Planned.Start < startFree; if (startsLate) { bestPlan.Planned.Start = startFree; } // Set the new free area startFree = bestPlan.Planned.End; #if !SILVERLIGHT // Trace if (SchedulerTrace.TraceInfo) { Trace.TraceInformation ( startsLate ? Properties.SchedulerResources.Trace_LateTask : Properties.SchedulerResources.Trace_NormalTask, resource, bestPlan.Planned.Start, bestPlan.Planned.Duration ); } #endif // Report yield return(new ScheduleInfo(bestTask.Definition, resource, bestPlan.Planned, startsLate)); // Advance bestTask.MoveNext(); // Get rid of it if (bestTask.Current == null) { tasks.RemoveAt(tiBest); } } }
/// <summary> /// Diese Methode verteilt Aufgaben an Geräte, die eine Zeitlang nicht in Benutzung sind. /// </summary> /// <param name="resource">Das zu verwendende Gerät.</param> /// <param name="startFree">Der Anfang des unbenutzten Bereiches.</param> /// <param name="endFree">Das Ende des unbenutzten Bereiches.</param> /// <param name="tasks">Die Liste der Aufgaben.</param> /// <returns>Alle Aufgaben, die dem Gerät in der unbenutzten Zeit zugeordnet wurden.</returns> private IEnumerable<ScheduleInfo> DispatchTasksForResource( IScheduleResource resource, DateTime startFree, DateTime endFree, List<_Task> tasks ) { // See if there is room left to run a task while ((tasks.Count > 0) && (endFree > startFree)) { // Load duration var duration = endFree - startFree; // Best task var tiBest = -1; // From all tasks fitting choose the one which starts first for (var ti = 0; ti < tasks.Count; ti++) { // See if resource could be used var task = tasks[ti]; if (!task.AllowedResources.Contains( resource, ReferenceComparer<IScheduleResource>.Default )) continue; // Not enough time - skip var planned = task.Current.Planned; if (planned.Duration.Ticks <= 0) continue; if (planned.Duration > duration) continue; // Will not end before resource is reused if (planned.End > endFree) continue; // Check for best if (tiBest < 0) tiBest = ti; else if (planned.Start < tasks[tiBest].Current.Planned.Start) tiBest = ti; } // Found nothing if (tiBest < 0) break; // Reload var bestTask = tasks[tiBest]; var bestPlan = bestTask.Current; // Check mode var startsLate = bestPlan.Planned.Start < startFree; if (startsLate) bestPlan.Planned.Start = startFree; // Set the new free area startFree = bestPlan.Planned.End; #if !SILVERLIGHT // Trace if (SchedulerTrace.TraceInfo) Trace.TraceInformation ( startsLate ? Properties.SchedulerResources.Trace_LateTask : Properties.SchedulerResources.Trace_NormalTask, resource, bestPlan.Planned.Start, bestPlan.Planned.Duration ); #endif // Report yield return new ScheduleInfo( bestTask.Definition, resource, bestPlan.Planned, startsLate ); // Advance bestTask.MoveNext(); // Get rid of it if (bestTask.Current == null) tasks.RemoveAt( tiBest ); } }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Geräteprofil, auf dem der Lauf erfolgen soll.</param> /// <param name="profile">Das zugehörige Geräteprofil.</param> public SourceListTask( IScheduleResource forResource, ProfileState profile ) : this( forResource, profile, () => profile.LastSourceUpdateTime ) { }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Geräteprofil, auf dem der Lauf erfolgen soll.</param> /// <param name="lastUpdate">Methode zur Ermittelung des letzten Aktualisierungszeitpunktes.</param> public SourceListTask( IScheduleResource forResource, Func<DateTime?> lastUpdate ) : this( forResource, null, lastUpdate ) { }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Gerät, für das die Sammlung erfolgt.</param> /// <param name="lastUpdate">Methode zur Ermittelung des letzten Aktualisierungszeitpunktes.</param> public ProgramGuideTask(IScheduleResource forResource, Func <DateTime?> lastUpdate) : this(forResource, null, lastUpdate) { }
/// <summary> /// Default constructor for <see cref="SchedulingEngine"/> /// </summary> /// <param name="scheduleResource"></param> public SchedulingEngine(IScheduleResource scheduleResource) { _scheduleResource = scheduleResource; }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Gerät, für das die Sammlung erfolgt.</param> /// <param name="profile">Das zugehörige Geräteprofil.</param> public ProgramGuideTask( IScheduleResource forResource, ProfileState profile ) : this( forResource, profile, () => profile.ProgramGuide.LastUpdateTime ) { }
/// <summary> /// Erstellt eine periodische Aufgabe zum Aktualisieren der Quellen. /// </summary> /// <param name="resource">Die zugehörige Ressource.</param> /// <param name="profile">Die vollen Informationen zum Geräteprofil.</param> /// <returns>Die Beschreibung der Aufgabe oder <i>null</i>.</returns> public PeriodicScheduler CreateSourceScanTask( IScheduleResource resource, Profile profile ) { // Forward return new SourceListTask( resource, () => m_lastRunScan[resource.Name] ); }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Gerät, für das die Sammlung erfolgt.</param> /// <param name="lastUpdate">Methode zur Ermittelung des letzten Aktualisierungszeitpunktes.</param> public ProgramGuideTask( IScheduleResource forResource, Func<DateTime?> lastUpdate ) : this( forResource, null, lastUpdate ) { }
/// <summary> /// Ergänzt ein Gerät. /// </summary> /// <param name="resource">Das gewünschte Gerät.</param> public void Add( IScheduleResource resource ) { // Not allowed if (m_CurrentPlan != null) throw new NotSupportedException( "Add" ); // Forward m_Resources.Add( resource ); }
/// <summary> /// Aktiviert eine Aufzeichnung auf einem Gerät. /// </summary> /// <param name="resource">Eines der verwalteten Geräte.</param> /// <param name="source">Optional eine Quelle, die auf dem Gerät angesteuert werden kann.</param> /// <param name="scheduleIdentifier">Die eindeutige Kennung der Aufzeichnung.</param> /// <param name="scheduleName">Der Anzeigename der Aufzeichnung.</param> /// <param name="plannedStart">Der ursprüngliche Start der Aufzeichnung in UTC / GMT Notation.</param> /// <param name="currentEnd">Das aktuelle Ende der Aufzeichnung in UTC / GMT Notation.</param> /// <returns>Gesetzt, wenn die Aufzeichnung auf dem gewünschten Gerät aktiviert werden kann.</returns> /// <exception cref="ArgumentNullException">Es wurde kein Gerät angegeben.</exception> /// <exception cref="ArgumentException">Das Gerät ist nicht bekannt oder kann die Quelle nicht empfangen.</exception> /// <exception cref="ArgumentOutOfRangeException">Die Laufzeit der Aufzeichnung ist nicht positiv.</exception> public bool Start( IScheduleResource resource, IScheduleSource source, Guid scheduleIdentifier, string scheduleName, DateTime plannedStart, DateTime currentEnd ) { // Validate if (resource == null) throw new ArgumentNullException( "resource" ); if (!m_Resources.Contains( resource )) throw new ArgumentException( resource.Name, "resource" ); if (plannedStart >= currentEnd) throw new ArgumentOutOfRangeException( "currentEnd" ); if (m_Recordings.Any( r => r.UniqueIdentifier == scheduleIdentifier )) throw new ArgumentException( "resource" ); // Create helper entry m_Recordings.Add( new ResourceAllocationInformation( resource, source, scheduleIdentifier, scheduleName, plannedStart, currentEnd - plannedStart ) ); // May require cleanup try { // Create the new plan var plan = CreateSchedulePlan(); // Did it if (plan != null) { // Remember as current m_CurrentPlan = plan; // Report return true; } } catch { // Cleanup m_Recordings.RemoveAt( m_Recordings.Count - 1 ); // Report throw; } // Cleanup m_Recordings.RemoveAt( m_Recordings.Count - 1 ); // Add to list return false; }
/// <summary> /// Registriert diese Aufzeichnung in einer Planungsinstanz. /// </summary> /// <param name="scheduler">Die zu verwendende Planungsinstanz.</param> /// <param name="job">Der zugehörige Auftrag.</param> /// <param name="devices">Die Liste der Geräte, auf denen die Aufzeichnung ausgeführt werden darf.</param> /// <param name="findSource">Dient zum Prüfen einer Quelle.</param> /// <param name="disabled">Alle deaktivierten Aufträge.</param> /// <param name="context">Die aktuelle Planungsumgebung.</param> /// <exception cref="ArgumentNullException">Es wurden nicht alle Parameter angegeben.</exception> public void AddToScheduler( RecordingScheduler scheduler, VCRJob job, IScheduleResource[] devices, Func<SourceSelection, SourceSelection> findSource, Func<Guid, bool> disabled, PlanContext context ) { // Validate if (scheduler == null) throw new ArgumentNullException( nameof( scheduler ) ); if (job == null) throw new ArgumentNullException( nameof( job ) ); if (findSource == null) throw new ArgumentNullException( nameof( findSource ) ); // Let VCR.NET choose a profile to do the work if (job.AutomaticResourceSelection) devices = null; // Create the source selection var persistedSource = Source ?? job.Source; var selection = findSource( persistedSource ); // Station no longer available if (selection == null) if (persistedSource != null) selection = new SourceSelection { DisplayName = persistedSource.DisplayName, ProfileName = persistedSource.ProfileName, Location = persistedSource.Location, Group = persistedSource.Group, Source = new Station { TransportStream = persistedSource.Source?.TransportStream ?? 0, Network = persistedSource.Source?.Network ?? 0, Service = persistedSource.Source?.Service ?? 0, Name = persistedSource.DisplayName, }, }; // See if we are allowed to process var identifier = UniqueID.Value; if (disabled != null) if (disabled( identifier )) return; // Load all var name = string.IsNullOrEmpty( Name ) ? job.Name : $"{job.Name} ({Name})"; var source = ProfileScheduleResource.CreateSource( selection ); var duration = TimeSpan.FromMinutes( Duration ); var noStartBefore = NoStartBefore; var start = FirstStart; // Check repetition var repeat = CreateRepeatPattern(); if (repeat == null) { // Only if not being recorded if (!noStartBefore.HasValue) scheduler.Add( RecordingDefinition.Create( this, name, identifier, devices, source, start, duration ) ); } else { // See if we have to adjust the start day if (noStartBefore.HasValue) { // Attach to the limit - actually we shift it a bit further assuming that we did have no large exception towards the past and the duration is moderate var startAfter = noStartBefore.Value.AddHours( 12 ); var startAfterDay = startAfter.ToLocalTime().Date; // Localize the start time var startTime = start.ToLocalTime().TimeOfDay; // First adjust start = (startAfterDay + startTime).ToUniversalTime(); // One more day if (start < startAfter) start = (startAfterDay.AddDays( 1 ) + startTime).ToUniversalTime(); } // Read the rest var exceptions = Exceptions.Select( e => e.ToPlanException( duration ) ).ToArray(); var endDay = LastDay.GetValueOrDefault( MaxMovableDay ); // A bit more complex if (start.Date <= endDay.Date) scheduler.Add( RecordingDefinition.Create( this, name, identifier, devices, source, start, duration, endDay, repeat ), exceptions ); } }
/// <summary> /// Erzeugt eine neue Verwaltung. /// </summary> /// <param name="forResource">Das Gerät, für das die Sammlung erfolgt.</param> /// <param name="profile">Das zugehörige Geräteprofil.</param> public ProgramGuideTask(IScheduleResource forResource, ProfileState profile) : this(forResource, profile, () => profile.ProgramGuide.LastUpdateTime) { }