/// <summary> /// Aktualisiert einen Auftrag oder legt einen neue an. /// </summary> /// <param name="job">Der betroffene Auftrag.</param> /// <param name="scheduleIdentifier">Die eindeutige Kennung der veränderten Aufzeichnung.</param> public void UpdateJob(VCRJob job, Guid?scheduleIdentifier) { // Client is talking to us - do not hibernate after update m_PendingHibernation = false; // Cleanup if (scheduleIdentifier.HasValue) { foreach (var schedule in job.Schedules) { if (schedule.UniqueID.HasValue) { if (schedule.UniqueID.Value.Equals(scheduleIdentifier.Value)) { schedule.NoStartBefore = null; } } } } // Add to job manager JobManager.Update(job, scheduleIdentifier); // Recalculate BeginNewPlan(); }
/// <summary> /// Aktualisiert einen Auftrag oder legt einen Auftrag neu an. /// </summary> /// <param name="job">Der neue oder veränderte Auftrag.</param> /// <param name="scheduleIdentifier">Die eindeutige Kennung der veränderten Aufzeichnung.</param> public void Update(VCRJob job, Guid?scheduleIdentifier) { // Report if (job != null) { Tools.ExtendedLogging("Updating Job {0}", job.UniqueID); } // Load default profile name job.SetProfile(); // Validate job.Validate(scheduleIdentifier); // Cleanup schedules job.CleanupExceptions(); // Remove from archive - if job has been recovered job.Delete(ArchiveDirectory); // Try to store to disk - actually this is inside the lock because the directory virtually is part of our map lock (m_Jobs) if (job.Save(JobDirectory).GetValueOrDefault()) { m_Jobs[job.UniqueID.Value] = job; } else { throw new ArgumentException(string.Format(Properties.Resources.SaveJobFailed, job.UniqueID), "job"); } }
/// <summary> /// Entfernt einen Auftrag. /// </summary> /// <param name="job">Der betroffene Auftrag.</param> public void DeleteJob(VCRJob job) { // Client is talking to us - do not hibernate after change m_PendingHibernation = false; // Remove from job manager JobManager.Delete(job); // Recalculate BeginNewPlan(); }
/// <summary> /// Erstellt einen passenden Auftrag für die persistente Ablage. /// </summary> /// <param name="jobIdentifier">Die eindeutige Kennung des Auftrags.</param> /// <returns>Der zugehörige Auftrag.</returns> public VCRJob CreateJob(Guid jobIdentifier) { // Create core var job = new VCRJob { AutomaticResourceSelection = !UseProfileForRecording, Directory = RecordingDirectory, UniqueID = jobIdentifier, Name = Name, }; // Check source var profile = Profile; if (string.IsNullOrEmpty(profile)) { return(job); } // Get the name of the source var sourceName = Source; if (string.IsNullOrEmpty(sourceName)) { // Create profile reference job.Source = new SourceSelection { ProfileName = profile }; // Done return(job); } // Locate the source job.Source = ServerRuntime.VCRServer.FindSource(profile, sourceName); if (job.Source == null) { return(job); } // Configure streams job.Streams = new StreamSelection(); // Set all - oder of audio settings is relevant, dolby MUST come last job.Streams.SetUsesAllAudio(AllLanguages); job.Streams.SetUsesDolbyAudio(DolbyDigital); job.Streams.SetUsesSubtitles(DVBSubtitles); job.Streams.SetUsesVideotext(Videotext); job.Streams.ProgramGuide = true; // Report return(job); }
/// <summary> /// Legt eine neue Information an. /// </summary> /// <param name="job">Der Auftrag.</param> /// <param name="schedule">Die Aufzeichnung.</param> /// <param name="guide">Ein Eintrag der Programmzeitschrift.</param> /// <param name="profile">Vorgabe für das Geräteprofil.</param> /// <returns>Die Information.</returns> public static JobScheduleInfo Create(VCRJob job, VCRSchedule schedule, ProgramGuideEntry guide, string profile) { // Process return (new JobScheduleInfo { ScheduleIdentifier = (schedule == null) ? null : schedule.UniqueID.Value.ToString("N"), JobIdentifier = (job == null) ? null : job.UniqueID.Value.ToString("N"), Schedule = EditSchedule.Create(schedule, job, guide), Job = EditJob.Create(job, guide, profile), }); }
/// <summary> /// Erstellt eine neue Beschreibung. /// </summary> /// <param name="job">Ein Auftrag.</param> /// <param name="active">Gesetzt, wenn es sich um einen aktiven Auftrag handelt.</param> /// <returns>Die gewünschte Beschreibung.</returns> public static InfoJob Create(VCRJob job, bool active) { // Report return (new InfoJob { Schedules = job.Schedules.Select(schedule => InfoSchedule.Create(schedule, job)).OrderBy(schedule => schedule.Name ?? string.Empty, StringComparer.InvariantCultureIgnoreCase).ToArray(), WebId = ServerRuntime.GetUniqueWebId(job, null), ProfileName = job.Source.ProfileName, SourceName = job.Source.DisplayName, IsActive = active, Name = job.Name, }); }
/// <summary> /// Meldet die Daten zu einer Aufzeichnung. /// </summary> /// <param name="schedule">Die Aufzeichnung.</param> /// <param name="job">Der zugehörige Auftrag.</param> /// <returns></returns> public static InfoSchedule Create(VCRSchedule schedule, VCRJob job) { // Create return (new InfoSchedule { Source = (schedule.Source ?? job.Source).GetUniqueName(), WebId = ServerRuntime.GetUniqueWebId(job, schedule), StartTime = schedule.FirstStart, RepeatPattern = schedule.Days, Duration = schedule.Duration, Name = schedule.Name, }); }
/// <summary> /// Erstellt die Beschreibung der Aufzeichnung für die persistente Ablage. /// </summary> /// <param name="scheduleIdentifier">Die eindeutige Kennung der Aufzeichnung.</param> /// <param name="job">Der zugehörige Auftrag.</param> /// <returns>Die gewünschte Beschreibung.</returns> public VCRSchedule CreateSchedule(Guid scheduleIdentifier, VCRJob job) { // Create var schedule = new VCRSchedule { UniqueID = scheduleIdentifier, FirstStart = FirstStart, Days = RepeatPattern, Duration = Duration, LastDay = LastDay, Name = Name, }; // See if we have a source var sourceName = Source; if (string.IsNullOrEmpty(sourceName)) { return(schedule); } // See if there is a profile var jobSource = job.Source; if (jobSource == null) { return(schedule); } // Locate the source schedule.Source = ServerRuntime.VCRServer.FindSource(jobSource.ProfileName, sourceName); if (schedule.Source == null) { return(schedule); } // Configure streams schedule.Streams = new StreamSelection(); // Set all - oder of audio settings is relevant, dolby MUST come last schedule.Streams.SetUsesAllAudio(AllLanguages); schedule.Streams.SetUsesDolbyAudio(DolbyDigital); schedule.Streams.SetUsesSubtitles(DVBSubtitles); schedule.Streams.SetUsesVideotext(Videotext); schedule.Streams.ProgramGuide = true; // Report return(schedule); }
/// <summary> /// Erzeugt eine Beschreibung. /// </summary> /// <param name="job">Ein Auftrag.</param> /// <param name="active">Gesetzt, wenn es sich um einen aktiven Auftrag handel.</param> /// <returns>Die gewünschte Beschreibung.</returns> public static ProfileJobInfo Create(VCRJob job, bool active) { // Process if (active) { return new ProfileJobInfo { Profile = job.Source.ProfileName, Name = job.Name, JobIdentifier = job.UniqueID.Value.ToString("N").ToLower() } } ; else { return(null); } }
/// <summary> /// Ermittelt eine Referenz für eine bestimmte Aufzeichung in einem Auftrag, so dass diese /// auch in einer URL verwendet werden kann. /// </summary> /// <param name="job">Ein Auftrag.</param> /// <param name="schedule">Eine Aufzeichnung.</param> /// <returns>Die eindeutige Referenz.</returns> public static string GetUniqueWebId(VCRJob job, VCRSchedule schedule) { // Forward if (job == null) { return("*"); } else if (schedule == null) { return(string.Format("*{0:N}", job.UniqueID.Value)); } else { return(GetUniqueWebId(job.UniqueID.Value, schedule.UniqueID.Value)); } }
/// <summary> /// Erstellt eine neue Beschreibung. /// </summary> /// <param name="job">Der konkrete Auftag.</param> /// <param name="guide">Ein Eintrag der Programmzeitschrift.</param> /// <param name="profile">Vorgabe für das Geräteprofil.</param> /// <returns>Die zugehörige Beschreibung.</returns> public static EditJob Create(VCRJob job, ProgramGuideEntry guide, string profile) { // Process if (job == null) { // No hope if (guide == null) { return(null); } // Create from program guide return (new EditJob { Source = ServerRuntime.VCRServer.GetUniqueName(new SourceSelection { ProfileName = profile, Source = guide.Source }), DVBSubtitles = UserProfileSettings.UseSubTitles, DolbyDigital = UserProfileSettings.UseAC3, AllLanguages = UserProfileSettings.UseMP2, Videotext = UserProfileSettings.UseTTX, UseProfileForRecording = false, Name = guide.Name.MakeValid(), Profile = profile, }); } // Optionen ermitteln var streams = job.Streams; var sourceName = ServerRuntime.VCRServer.GetUniqueName(job.Source); // Report return (new EditJob { UseProfileForRecording = !job.AutomaticResourceSelection, DolbyDigital = streams.GetUsesDolbyAudio(), AllLanguages = streams.GetUsesAllAudio(), DVBSubtitles = streams.GetUsesSubtitles(), Videotext = streams.GetUsesVideotext(), RecordingDirectory = job.Directory, Profile = job.Source.ProfileName, Source = sourceName, Name = job.Name, }); }
/// <summary> /// Rekonstruiert einen Auftrag und eine Aufzeichnung aus einer Textdarstellung. /// </summary> /// <param name="id">Die Textdarstellung.</param> /// <param name="job">Der ermittelte Auftrag.</param> /// <returns>Die zugehörige Aufzeichnung im Auftrag.</returns> public static VCRSchedule ParseUniqueWebId(string id, out VCRJob job) { ParseUniqueWebId(id, out Guid jobID, out Guid scheduleID); // Find the job job = VCRServer.FindJob(jobID); // Report schedule if job exists if (job == null) { return(null); } else { return(job[scheduleID]); } }
/// <summary> /// Ermittelt einen Auftrag nach seiner eindeutigen Kennung. /// </summary> /// <param name="jobIdentifier">Die Kennung des Auftrags.</param> /// <returns>Der gewünschte Auftrag oder <i>null</i>, wenn kein derartiger /// Auftrag existiert.</returns> public VCRJob FindJob(Guid jobIdentifier) { // The result VCRJob result = null; // Synchronize lock (m_Jobs) { // Try map if (m_Jobs.TryGetValue(jobIdentifier, out result)) { return(result); } // Create file name var jobFile = new FileInfo(Path.Combine(ArchiveDirectory.FullName, jobIdentifier.ToString("N").ToUpper() + VCRJob.FileSuffix)); if (!jobFile.Exists) { return(null); } // Load result = SerializationTools.Load <VCRJob>(jobFile); if (result == null) { return(null); } } // Check identifier and finalize settings - for pre-3.0 files if (!result.UniqueID.HasValue) { return(null); } if (!jobIdentifier.Equals(result.UniqueID.Value)) { return(null); } // Finish result.SetProfile(); // Found in archive return(result); }
/// <summary> /// Ergänz die Abbildung von einer Aufzeichnung auf einen Auftrag. /// </summary> /// <param name="schedule">Eine Aufzeichnung.</param> /// <param name="job">Der zugehörige Auftrag.</param> public void RegisterSchedule(VCRSchedule schedule, VCRJob job) { // Validate if (schedule == null) { throw new ArgumentNullException(nameof(schedule)); } if (job == null) { throw new ArgumentNullException(nameof(job)); } // Skip on missing identifier var scheduleIdentifier = schedule.UniqueID; if (scheduleIdentifier.HasValue) { m_jobsBySchedule.Add(scheduleIdentifier.Value, job); } }
/// <summary> /// Löscht einen aktiven oder archivierten Auftrag. /// </summary> /// <param name="job">Der zu löschende Auftrag.</param> public void Delete(VCRJob job) { // Check unique identifier if (!job.UniqueID.HasValue) { throw new InvalidJobDataException(Properties.Resources.BadUniqueID); } // Report Tools.ExtendedLogging("Deleting Job {0}", job.UniqueID); // Must synchronize lock (m_Jobs) { // Load from the map var internalJob = this[job.UniqueID.Value]; // See if this is active if (internalJob != null) { // Delete it internalJob.Delete(JobDirectory); // Remove from map m_Jobs.Remove(internalJob.UniqueID.Value); // Save to file internalJob.Save(ArchiveDirectory); } else { // Report Tools.ExtendedLogging("Job not found in Active Directory - trying Archive"); // Must be archived job.Delete(ArchiveDirectory); } } }
/// <summary> /// Erzeugt eine neue Verwaltungsinstanz und lädt die aktuellen Auftragsliste. /// </summary> /// <param name="rootDirectory">Meldet das Verzeichnis, unterhalb dessen alle /// Aufträge und Protokolle angelegt werden.</param> /// <param name="server">Die VCR.NET Instanz, der diese Verwaltung zugeordnet ist.</param> internal JobManager(DirectoryInfo rootDirectory, VCRServer server) { // Remember RootDirectory = rootDirectory; Server = server; // Create root directory RootDirectory.Create(); // Create working directories CollectorDirectory.Create(); ArchiveDirectory.Create(); JobDirectory.Create(); LogDirectory.Create(); // Load all jobs foreach (var job in VCRJob.Load(JobDirectory)) { if (job.UniqueID.HasValue) { m_Jobs[job.UniqueID.Value] = job; } } }
/// <summary> /// Erstellt die Beschreibung der Aufzeichnung für die persistente Ablage. /// </summary> /// <param name="job">Der zugehörige Auftrag.</param> /// <returns>Die gewünschte Beschreibung.</returns> public VCRSchedule CreateSchedule(VCRJob job) { // Forward return(CreateSchedule(Guid.NewGuid(), job)); }
/// <summary> /// Erstellt eine Beschreibung zu dieser Aufzeichnung. /// </summary> /// <param name="schedule">Eine Aufzeichnung.</param> /// <param name="job">Der bereits vorhandene Auftrag.</param> /// <param name="guide">Ein Eintrag aus der Programmzeitschrift.</param> /// <returns>Die gewünschte Beschreibung.</returns> public static EditSchedule Create(VCRSchedule schedule, VCRJob job, ProgramGuideEntry guide) { // None if (schedule == null) { // No hope if (guide == null) { return(null); } // Calculate var start = guide.StartTime - TimeSpan.FromMinutes(UserProfileSettings.EPGPreTime); var duration = checked ((int)(UserProfileSettings.EPGPreTime + (guide.Duration / 60) + UserProfileSettings.EPGPostTime)); // Partial - we have a brand new job which is pre-initialized with the source if (job == null) { return new EditSchedule { FirstStart = start, Duration = duration } } ; // Full monty - we have to overwrite the jobs settings since we are not the first schedule return (new EditSchedule { Source = ServerRuntime.VCRServer.GetUniqueName(new SourceSelection { ProfileName = job.Source.ProfileName, Source = guide.Source }), DVBSubtitles = UserProfileSettings.UseSubTitles, DolbyDigital = UserProfileSettings.UseAC3, AllLanguages = UserProfileSettings.UseMP2, Videotext = UserProfileSettings.UseTTX, Name = guide.Name.MakeValid(), Duration = duration, FirstStart = start, }); } // Consolidate exceptions schedule.CleanupExceptions(); // Optionen ermitteln var streams = schedule.Streams; var sourceName = ServerRuntime.VCRServer.GetUniqueName(schedule.Source); // Create return (new EditSchedule { Exceptions = schedule.Exceptions.Select(exception => PlanException.Create(exception, schedule)).ToArray(), LastDay = schedule.LastDay.GetValueOrDefault(VCRSchedule.MaxMovableDay), DolbyDigital = streams.GetUsesDolbyAudio(), DVBSubtitles = streams.GetUsesSubtitles(), AllLanguages = streams.GetUsesAllAudio(), Videotext = streams.GetUsesVideotext(), FirstStart = schedule.FirstStart, RepeatPattern = schedule.Days, Duration = schedule.Duration, Name = schedule.Name, Source = sourceName, }); }
/// <summary> /// Erstellt einen neuen Eintrag. /// </summary> /// <param name="schedule">Die zugehörige Beschreibung der geplanten Aktivität.</param> /// <param name="context">Die Abbildung auf die Aufträge.</param> /// <param name="profiles">Die Verwaltung der Geräteprofile.</param> /// <returns>Die angeforderte Repräsentation.</returns> public static PlanActivity Create(IScheduleInformation schedule, PlanContext context, ProfileStateCollection profiles) { // Request context information var definition = schedule.Definition; var runningInfo = context.GetRunState(definition.UniqueIdentifier); var isAllocation = definition is IResourceAllocationInformation; // Maybe it's an resource allocation if (isAllocation) { if (runningInfo != null) { definition = runningInfo.Schedule.Definition; } else { return(null); } } // Create initial entry var time = schedule.Time; var start = time.Start; var end = time.End; var activity = new PlanActivity { IsHidden = (schedule.Resource == null), IsLate = schedule.StartsLate, }; // May need some correction if (runningInfo != null) { if (end == runningInfo.Schedule.Time.End) { // Only report the allocation itself if (!isAllocation) { return(null); } // Reload the real start and times - just in case someone manipulated start = runningInfo.Schedule.Time.Start; end = runningInfo.RealTime.End; // Never report as late - actually since we have some spin up time most of the time the recording is late activity.IsLate = false; } } // Get the beautified range start = PlanCurrent.RoundToSecond(start); end = PlanCurrent.RoundToSecond(end); // Set times activity.Duration = end - start; activity.StartTime = start; // Set name if (definition != null) { activity.FullName = definition.Name; } // Set resource var resource = schedule.Resource; if (resource != null) { activity.Device = resource.Name; } // Schedule to process VCRSchedule vcrSchedule = null; VCRJob vcrJob = null; // Analyse definition var scheduleDefinition = definition as IScheduleDefinition <VCRSchedule>; if (scheduleDefinition != null) { // Regular plan vcrSchedule = scheduleDefinition.Context; vcrJob = context.TryFindJob(vcrSchedule); } // Process if we found one if (vcrSchedule != null) { // See if we have a job if (vcrJob != null) { activity.LegacyReference = ServerRuntime.GetUniqueWebId(vcrJob, vcrSchedule); } // Find the source to use - stream selection is always bound to the context of the source var streams = vcrSchedule.Streams; var source = vcrSchedule.Source; if (source == null) { if (vcrJob != null) { // Try job source = vcrJob.Source; // Adjust stream flags to use if (source == null) { streams = null; } else { streams = vcrJob.Streams; } } } // Copy station name if (source != null) { // Remember activity.Source = SourceIdentifier.ToString(source.Source).Replace(" ", ""); activity.Station = source.DisplayName; // Load the profile var profile = profiles[activity.GuideEntryDevice = source.ProfileName]; if (profile != null) { activity.HasGuideEntry = profile.ProgramGuide.HasEntry(source.Source, activity.StartTime, activity.StartTime + activity.Duration); } } // Apply special settings activity.CurrentProgramGuide = streams.GetUsesProgramGuide(); activity.AllLanguages = streams.GetUsesAllAudio(); activity.SubTitles = streams.GetUsesSubtitles(); activity.VideoText = streams.GetUsesVideotext(); activity.Dolby = streams.GetUsesDolbyAudio(); // Check for exception rule on the day var exception = vcrSchedule.FindException(time.End); if (exception != null) { activity.ExceptionRule = PlanException.Create(exception, vcrSchedule); } // May want to add end time checks if (!isAllocation) { if (!activity.IsLate) { if (!activity.IsHidden) { if ((exception == null) || exception.IsEmpty) { activity.EndTimeCouldBeWrong = activity.CheckEndTime(vcrSchedule.FirstStart); } } } } } else if (definition is ProgramGuideTask) { activity.Station = VCRJob.ProgramGuideName; } else if (definition is SourceListTask) { activity.Station = VCRJob.SourceScanName; } // Report return(activity); }
static void Main1(string[] args) { // Attach to job manager VCRServer server = new VCRServer(new DirectoryInfo(@"C:\temp\VCR.NET 3.9 Alpha\Jobs")); JobManager jobs = server.JobManager; // Process all profiles foreach (Profile profile in VCRProfiles.Profiles) { // Report Console.WriteLine(profile.Name); // Start time DateTime start = DateTime.UtcNow; // Process a bit for (int i = 10; i-- > 0;) { // Helper data VCRRecordingInfo[] included; bool inComplete; // Find the recording FullInfo info = jobs.FindNextRecording(start, profile, out inComplete, out included); VCRRecordingInfo rec = info.Recording; VCRJob job = jobs[rec.JobUniqueID.Value]; VCRSchedule sched = job[rec.ScheduleUniqueID.Value]; // Report Console.WriteLine("\t{0} {1} {2} ({3}) {4} {5} {6} {7}", rec.StartsAt.Value.ToLocalTime(), rec.EndsAt.ToLocalTime().TimeOfDay, job.Name, sched.Name, inComplete, included.Length, rec.JobUniqueID, rec.ScheduleUniqueID); // Report foreach (VCRRecordingInfo include in included) { Console.WriteLine("\t\t{0} {1} {2} {3} {4}", include.Source.GetUniqueName(), include.StartsAt.Value.ToLocalTime(), include.EndsAt.ToLocalTime().TimeOfDay, include.JobUniqueID, include.ScheduleUniqueID); } // Report foreach (StreamInfo stream in info.Streams) { foreach (ScheduleInfo schedule in stream.Schedules) { Console.WriteLine("\t\t{0} {1} {2} {3}", schedule.JobUniqueID, schedule.ScheduleUniqueID, schedule.StartsAt.ToLocalTime(), schedule.EndsAt.ToLocalTime().TimeOfDay); } } // Advance start = rec.EndsAt; } // Helper data VCRRecordingInfo[] incDummy; bool dummyFlag; // Start timer Stopwatch timer = Stopwatch.StartNew(); // Measure for (int n = 0; ++n > 0;) { // Find the recording jobs.FindNextRecording(DateTime.UtcNow, profile, out dummyFlag, out incDummy); // Get the time TimeSpan delta = timer.Elapsed; if (delta.TotalSeconds >= 5) { // Report Console.WriteLine("{0}ms", delta.TotalMilliseconds / n); // Done break; } } } // Get the profile Profile nexus = VCRProfiles.FindProfile("Nexus"); // Find the next recording VCRRecordingInfo rec2 = jobs.FindNextJob(new DateTime(2009, 2, 19, 20, 0, 0), null, nexus); if (null != rec2) { if (rec2.StartsAt.HasValue) { using (RecordingRequest recording = jobs.CreateRecording(rec2, rec2.StartsAt.Value, nexus)) { // Get the information FullInfo info0 = recording.CreateFullInformation(); #if EXEC // Start it recording.BeginExecute(false); // Report Console.WriteLine("Recording..."); Console.ReadLine(); // Get the information FullInfo info1 = recording.CreateFullInformation(); #endif } } } // Done Console.WriteLine("Done"); Console.ReadLine(); }