]> granicus.if.org Git - handbrake/commitdiff
WinGui: Build out code for active monitoring of storage and battery power on the...
authorsr55 <sr55.hb@outlook.com>
Fri, 5 Jul 2019 22:11:04 +0000 (23:11 +0100)
committersr55 <sr55.hb@outlook.com>
Fri, 5 Jul 2019 22:11:22 +0000 (23:11 +0100)
- Automatic pause on "Low" or "Critical" battery alarms.  The % level is set in Windows power settings. Automatic Resume when AC returns, if it was paused by an alarm.
- Automatic encode pause when destination drive drops below 2GB.  (May make this a preference set later)
- Behaviour of pause queue on low disk space with a user defined level in preferences is unchanged.

#2109 #2181

15 files changed:
win/CS/HandBrakeWPF/HandBrakeWPF.csproj
win/CS/HandBrakeWPF/Properties/Resources.Designer.cs
win/CS/HandBrakeWPF/Properties/Resources.resx
win/CS/HandBrakeWPF/Services/Encode/Interfaces/IEncode.cs
win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
win/CS/HandBrakeWPF/Services/Interfaces/ISystemService.cs [new file with mode: 0644]
win/CS/HandBrakeWPF/Services/Queue/QueueService.cs
win/CS/HandBrakeWPF/Services/SystemService.cs [new file with mode: 0644]
win/CS/HandBrakeWPF/Startup/AppBootstrapper.cs
win/CS/HandBrakeWPF/UserSettingConstants.cs
win/CS/HandBrakeWPF/Utilities/Win32.cs
win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs
win/CS/HandBrakeWPF/ViewModels/OptionsViewModel.cs
win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs
win/CS/HandBrakeWPF/defaultsettings.xml

index 232e4f3d994c2c94e79e861b27fb120688eef0b8..11f9682dfa6844564340833ceb27959c890bf66b 100644 (file)
     <Compile Include="Services\Encode\Model\Models\Video\VideoProfile.cs" />\r
     <Compile Include="Services\Encode\Model\Models\Video\VideoTune.cs" />\r
     <Compile Include="Services\Interfaces\INotifyIconService.cs" />\r
+    <Compile Include="Services\Interfaces\ISystemService.cs" />\r
     <Compile Include="Services\Logging\EventArgs\LogEventArgs.cs" />\r
     <Compile Include="Services\Logging\Interfaces\ILog.cs" />\r
     <Compile Include="Services\Logging\LogService.cs" />\r
     <Compile Include="Services\Scan\Model\Subtitle.cs" />\r
     <Compile Include="Services\Scan\Model\Title.cs" />\r
     <Compile Include="Services\NotifyIconService.cs" />\r
+    <Compile Include="Services\SystemService.cs" />\r
     <Compile Include="Services\UserSettingService.cs" />\r
     <Compile Include="Startup\StartupOptions.cs" />\r
     <Compile Include="Utilities\AppcastReader.cs" />\r
index 892c484bea171e26cd86c640f7567d37f5eefd1e..9ad37148db0e9165e6bce2886b8b861515478cc4 100644 (file)
@@ -5191,6 +5191,42 @@ namespace HandBrakeWPF.Properties {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to AC Mains power detected. Resuming encode... ({0} %).
+        /// </summary>
+        public static string SystemService_ACMains {
+            get {
+                return ResourceManager.GetString("SystemService_ACMains", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to System Battery Critical! ({0} %).
+        /// </summary>
+        public static string SystemService_CriticalBattery {
+            get {
+                return ResourceManager.GetString("SystemService_CriticalBattery", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to System Battery Low! ({0} %). Your encode has been paused to protect the system. System sleep is set to allowed!.
+        /// </summary>
+        public static string SystemService_LowBatteryLog {
+            get {
+                return ResourceManager.GetString("SystemService_LowBatteryLog", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Remaining drive storage has dropped below {0} GB on the destination drive. Pausing encode....
+        /// </summary>
+        public static string SystemService_LowDiskSpaceLog {
+            get {
+                return ResourceManager.GetString("SystemService_LowDiskSpaceLog", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to {1}%, Pass {2} of {3}
         ///Remaining Time: {4}.
index c850971d0121f347d1b81b345b1966c6bd3f5686..e707d01e7bc31d6f2121156ffb3ec2f6b15c6547 100644 (file)
@@ -2020,4 +2020,16 @@ Where supported, any user presets will have been imported.</value>
   <data name="Options_LowDiskspaceSizeGB" xml:space="preserve">\r
     <value>GB</value>\r
   </data>\r
+  <data name="SystemService_ACMains" xml:space="preserve">\r
+    <value>AC Mains power detected. Resuming encode... ({0} %)</value>\r
+  </data>\r
+  <data name="SystemService_CriticalBattery" xml:space="preserve">\r
+    <value>System Battery Critical! ({0} %)</value>\r
+  </data>\r
+  <data name="SystemService_LowBatteryLog" xml:space="preserve">\r
+    <value>System Battery Low! ({0} %). Your encode has been paused to protect the system. System sleep is set to allowed!</value>\r
+  </data>\r
+  <data name="SystemService_LowDiskSpaceLog" xml:space="preserve">\r
+    <value>Remaining drive storage has dropped below {0} GB on the destination drive. Pausing encode...</value>\r
+  </data>\r
 </root>
\ No newline at end of file
index 489f469253e3f2f935352ce2aafcb5e589c784e8..871f31615b7ae7422c46b8b72c1fbdc97e308375 100644 (file)
@@ -94,5 +94,11 @@ namespace HandBrakeWPF.Services.Encode.Interfaces
         /// Kill the process
         /// </summary>
         void Stop();
+
+
+        /// <summary>
+        /// Get a copy of the Active job
+        /// </summary>
+        EncodeTask GetActiveJob();
     }
 }
\ No newline at end of file
index 3b9e01280ec77e829c12dbea8a4e9323f2f9bde8..f3ff75fcc294745acc95e24fc1082dd914dbdf57 100644 (file)
@@ -169,6 +169,17 @@ namespace HandBrakeWPF.Services.Encode
             }
         }
 
+        public EncodeTask GetActiveJob()
+        {
+            if (this.currentTask != null)
+            {
+                EncodeTask task = new EncodeTask(this.currentTask); // Decouple our current copy.
+                return task;
+            }
+
+            return null;
+        }
+
         #region HandBrakeInstance Event Handlers.
 
         /// <summary>
diff --git a/win/CS/HandBrakeWPF/Services/Interfaces/ISystemService.cs b/win/CS/HandBrakeWPF/Services/Interfaces/ISystemService.cs
new file mode 100644 (file)
index 0000000..79461a8
--- /dev/null
@@ -0,0 +1,16 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="ISystemService.cs" company="HandBrake Project (http://handbrake.fr)">
+//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+//   Defines
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services.Interfaces
+{
+    public interface ISystemService
+    {
+        void Start();
+    }
+}
\ No newline at end of file
index 3d8af90b3a8ccd37551f91ddf9222dc14af8832e..90c9d7dedd196da25141bd2561137496ce52255b 100644 (file)
@@ -485,7 +485,7 @@ namespace HandBrakeWPF.Services.Queue
             QueueTask job = this.GetNextJobForProcessing();
             if (job != null)
             {
-                if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PauseOnLowDiskspace) && !DriveUtilities.HasMinimumDiskSpace(job.Task.Destination, this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseOnLowDiskspaceLevel)))
+                if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PauseOnLowDiskspace) && !DriveUtilities.HasMinimumDiskSpace(job.Task.Destination, this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseQueueOnLowDiskspaceLevel)))
                 {
                     LogService.GetLogger().LogMessage(Resources.PauseOnLowDiskspace, LogMessageType.ScanOrEncode, LogLevel.Info);
                     job.Status = QueueItemStatus.Waiting;
diff --git a/win/CS/HandBrakeWPF/Services/SystemService.cs b/win/CS/HandBrakeWPF/Services/SystemService.cs
new file mode 100644 (file)
index 0000000..4bbc89f
--- /dev/null
@@ -0,0 +1,143 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="SystemService.cs" company="HandBrake Project (http://handbrake.fr)">
+//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+//   Monitor the system health for common problems that will directly impact encodes.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services
+{
+    using System;
+    using System.Runtime.CompilerServices;
+    using System.Timers;
+
+    using HandBrakeWPF.Properties;
+    using HandBrakeWPF.Services.Encode.Interfaces;
+    using HandBrakeWPF.Services.Encode.Model;
+    using HandBrakeWPF.Services.Interfaces;
+    using HandBrakeWPF.Services.Logging;
+    using HandBrakeWPF.Services.Logging.Interfaces;
+    using HandBrakeWPF.Services.Logging.Model;
+    using HandBrakeWPF.Utilities;
+
+    using Ookii.Dialogs.Wpf;
+
+    public class SystemService : ISystemService
+    {
+        private readonly IUserSettingService userSettingService;
+        private readonly IEncode encodeService;
+        private readonly ILog log = LogService.GetLogger();
+        private Timer pollTimer;
+
+        private bool criticalStateHit = false;
+        private bool lowStateHit = false;
+        private bool lowPowerPause = false;
+        private bool storageLowPause = false;
+
+        public SystemService(IUserSettingService userSettingService, IEncode encodeService)
+        {
+            this.userSettingService = userSettingService;
+            this.encodeService = encodeService;
+        }
+
+        public void Start()
+        {
+            if (this.pollTimer == null)
+            {
+                this.pollTimer = new Timer();
+                this.pollTimer.Interval = 10000; // Check every 10 seconds. 
+                this.pollTimer.Elapsed += (o, e) =>
+                {
+                    this.CheckSystem();
+                };
+
+                this.pollTimer.Start();
+            }
+        }
+
+        private void CheckSystem()
+        {
+            this.PowerCheck();
+            this.StorageCheck();
+        }
+
+        private void StorageCheck()
+        {
+            string directory = this.encodeService.GetActiveJob()?.Destination;
+            if (!string.IsNullOrEmpty(directory)  && this.encodeService.IsEncoding)
+            {
+                long lowLevel = this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseEncodeOnLowDiskspaceLevel);
+                if (!this.storageLowPause && this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PauseOnLowDiskspace) && !DriveUtilities.HasMinimumDiskSpace(directory, lowLevel))
+                {
+                    LogService.GetLogger().LogMessage(
+                        string.Format(
+                            Resources.SystemService_LowDiskSpaceLog,
+                            lowLevel / 1000 / 1000 / 1000),
+                        LogMessageType.Application,
+                        LogLevel.Info);
+                    this.encodeService.Pause();
+                    this.storageLowPause = true;
+                }
+            }
+        }
+
+        private void PowerCheck()
+        {
+            Win32.PowerState state = Win32.PowerState.GetPowerState();
+
+            if (state == null || state.BatteryFlag == Win32.BatteryFlag.NoSystemBattery || state.BatteryFlag == Win32.BatteryFlag.Unknown)
+            {
+                return; // Only run if we have a battery.
+            }
+
+            if (state.ACLineStatus == Win32.ACLineStatus.Offline && state.BatteryFlag == Win32.BatteryFlag.Low && !this.lowStateHit)
+            {
+                if (this.encodeService.IsEncoding && !this.encodeService.IsPasued)
+                {
+                    this.lowPowerPause = true;
+                    this.encodeService.Pause();
+                }
+
+                Win32.AllowSleep();
+
+                this.ServiceLogMessage(string.Format(Resources.SystemService_LowBatteryLog, state.BatteryLifePercent));
+                this.lowStateHit = true;
+            }
+
+            if (state.ACLineStatus == Win32.ACLineStatus.Offline && state.BatteryFlag == Win32.BatteryFlag.Critical && !this.criticalStateHit)
+            {
+                if (this.encodeService.IsEncoding && !this.encodeService.IsPasued)
+                {
+                    this.lowPowerPause = true;
+                    this.encodeService.Pause(); // In case we missed the low state!
+                }
+
+                Win32.AllowSleep();
+
+                this.ServiceLogMessage(string.Format(Resources.SystemService_CriticalBattery, state.BatteryLifePercent));
+                this.criticalStateHit = true;
+            }
+
+            // Reset the flags when we start charging. 
+            if (state.ACLineStatus == Win32.ACLineStatus.Online && state.BatteryFlag >= Win32.BatteryFlag.Low)
+            {
+                if (this.lowPowerPause && this.encodeService.IsPasued)
+                {
+                    this.encodeService.Resume();
+                    this.ServiceLogMessage(string.Format(Resources.SystemService_ACMains, state.BatteryLifePercent));
+                }
+
+                this.lowPowerPause = false;
+                this.criticalStateHit = false;
+                this.lowStateHit = false;
+            }
+        }
+
+        private void ServiceLogMessage(string message)
+        {
+            this.log.LogMessage(string.Format("{0}# {1}{0}", Environment.NewLine, message), LogMessageType.Application, LogLevel.Info);
+        }
+    }
+}
index 4f1f6c1599674644cef0c674e94ac7fdfa8c9ba1..69be733604cfa5740c4317d30db45fdf605db340 100644 (file)
@@ -79,7 +79,8 @@ namespace HandBrakeWPF.Startup
             this.container.Singleton<ICountdownAlertViewModel, CountdownAlertViewModel>();\r
             this.container.Singleton<IMiniViewModel, MiniViewModel>();\r
             this.container.Singleton<IStaticPreviewViewModel, StaticPreviewViewModel>();\r
-\r
+            this.container.Singleton<ISystemService, SystemService>();\r
+            \r
             // Tab Components\r
             this.container.Singleton<IAudioViewModel, AudioViewModel>();\r
             this.container.Singleton<IPictureSettingsViewModel, PictureSettingsViewModel>();\r
index 1f6ed72dbf9d54b3b9cbfc2f7659accc7f3679ad..c5c9d5ad78598751a0d2a1fd5d8b9aef0fdb0eec 100644 (file)
@@ -36,7 +36,8 @@ namespace HandBrakeWPF
         public const string SendFileToArgs = "SendFileToArgs";\r
         public const string PreventSleep = "PreventSleep";\r
         public const string PauseOnLowDiskspace = "PauseOnLowDiskspace";\r
-        public const string PauseOnLowDiskspaceLevel = "LowDiskSpaceWarningLevelInBytes";\r
+        public const string PauseQueueOnLowDiskspaceLevel = "LowDiskSpaceWarningLevelInBytes";\r
+        public const string PauseEncodeOnLowDiskspaceLevel = "LowDiskSpaceEncodePauseLevelInBytes";\r
         public const string RemovePunctuation = "RemovePunctuation";\r
         public const string ShowPresetPanel = "ShowPresetPanelOption";\r
         public const string ResetWhenDoneAction = "ResetWhenDoneAction";\r
index 12154331ac4c4f2320d0ef5ebb3fd17b9750de1b..f999e76284d90bcee6a351e5cddfb302829c5073 100644 (file)
@@ -195,5 +195,48 @@ namespace HandBrakeWPF.Utilities
         {
             executor = marshaller;
         }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public class PowerState
+        {
+            public ACLineStatus ACLineStatus;
+            public BatteryFlag BatteryFlag;
+            public Byte BatteryLifePercent;
+            public Byte SystemStatusFlag;
+            public Int32 BatteryLifeTime;
+            public Int32 BatteryFullLifeTime;
+
+            public static PowerState GetPowerState()
+            {
+                PowerState state = new PowerState();
+                if (GetSystemPowerStatusRef(state))
+                {
+                    return state;
+                }
+
+                return null;
+            }
+
+            [DllImport("Kernel32", EntryPoint = "GetSystemPowerStatus")]
+            private static extern bool GetSystemPowerStatusRef(PowerState sps);
+        }
+
+        public enum ACLineStatus : byte
+        {
+            Offline = 0,
+            Online = 1,
+            Unknown = 255
+        }
+
+        public enum BatteryFlag : byte
+        {
+            High = 1,
+            Low = 2,
+            Critical = 4,
+            Charging = 8,
+            NoSystemBattery = 128,
+            Unknown = 255
+        }
     }
 }
+
index c1cd1aafbc8a39c989160236d6a113e69be1be0c..731a2e0903422b90fedfb107710ae4381c15e061 100644 (file)
@@ -110,12 +110,26 @@ namespace HandBrakeWPF.ViewModels
         /// The viewmodel for HandBrakes main window.\r
         /// </summary>\r
         /// <remarks>whenDoneService must be a serivce here!</remarks>\r
-        public MainViewModel(IUserSettingService userSettingService, IScan scanService, IPresetService presetService, \r
-            IErrorService errorService, IUpdateService updateService, \r
-            IPrePostActionService whenDoneService, IWindowManager windowManager, IPictureSettingsViewModel pictureSettingsViewModel, IVideoViewModel videoViewModel, ISummaryViewModel summaryViewModel,\r
-            IFiltersViewModel filtersViewModel, IAudioViewModel audioViewModel, ISubtitlesViewModel subtitlesViewModel,\r
-            IChaptersViewModel chaptersViewModel, IStaticPreviewViewModel staticPreviewViewModel,\r
-            IQueueViewModel queueViewModel, IMetaDataViewModel metaDataViewModel, INotifyIconService notifyIconService)\r
+        public MainViewModel(\r
+            IUserSettingService userSettingService,\r
+            IScan scanService,\r
+            IPresetService presetService,\r
+            IErrorService errorService,\r
+            IUpdateService updateService,\r
+            IPrePostActionService whenDoneService,\r
+            IWindowManager windowManager,\r
+            IPictureSettingsViewModel pictureSettingsViewModel,\r
+            IVideoViewModel videoViewModel,\r
+            ISummaryViewModel summaryViewModel,\r
+            IFiltersViewModel filtersViewModel,\r
+            IAudioViewModel audioViewModel,\r
+            ISubtitlesViewModel subtitlesViewModel,\r
+            IChaptersViewModel chaptersViewModel,\r
+            IStaticPreviewViewModel staticPreviewViewModel,\r
+            IQueueViewModel queueViewModel,\r
+            IMetaDataViewModel metaDataViewModel,\r
+            INotifyIconService notifyIconService,\r
+            ISystemService systemService)\r
             : base(userSettingService)\r
         {\r
             this.scanService = scanService;\r
@@ -184,6 +198,8 @@ namespace HandBrakeWPF.ViewModels
             // Setup Commands\r
             this.QueueCommand = new QueueCommands(this.QueueViewModel);\r
 \r
+            // Monitor the system.\r
+            systemService.Start();\r
         }\r
 \r
         #region View Model Properties\r
@@ -1377,7 +1393,7 @@ namespace HandBrakeWPF.ViewModels
 \r
             if (!DriveUtilities.HasMinimumDiskSpace(\r
                 this.Destination,\r
-                this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseOnLowDiskspaceLevel)))\r
+                this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseQueueOnLowDiskspaceLevel)))\r
             {\r
                 return new AddQueueError(Resources.Main_LowDiskspace, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);\r
             }\r
index 4375e2a08367c4506ae223c14e3cfcdd48600d13..b8d9b89f23b2f9fa9dbf03808bf851a24e71abee 100644 (file)
@@ -1582,7 +1582,7 @@ namespace HandBrakeWPF.ViewModels
 \r
             this.PreventSleep = userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep);\r
             this.PauseOnLowDiskspace = userSettingService.GetUserSetting<bool>(UserSettingConstants.PauseOnLowDiskspace);\r
-            this.PauseOnLowDiskspaceLevel = this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseOnLowDiskspaceLevel);\r
+            this.PauseOnLowDiskspaceLevel = this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseQueueOnLowDiskspaceLevel);\r
 \r
             // Log Verbosity Level\r
             this.logVerbosityOptions.Clear();\r
@@ -1723,7 +1723,7 @@ namespace HandBrakeWPF.ViewModels
             this.userSettingService.SetUserSetting(UserSettingConstants.ProcessPriority, this.SelectedPriority);\r
             this.userSettingService.SetUserSetting(UserSettingConstants.PreventSleep, this.PreventSleep);\r
             this.userSettingService.SetUserSetting(UserSettingConstants.PauseOnLowDiskspace, this.PauseOnLowDiskspace);\r
-            this.userSettingService.SetUserSetting(UserSettingConstants.PauseOnLowDiskspaceLevel, this.PauseOnLowDiskspaceLevel);\r
+            this.userSettingService.SetUserSetting(UserSettingConstants.PauseQueueOnLowDiskspaceLevel, this.PauseOnLowDiskspaceLevel);\r
             this.userSettingService.SetUserSetting(UserSettingConstants.Verbosity, this.SelectedVerbosity);\r
             this.userSettingService.SetUserSetting(UserSettingConstants.SaveLogWithVideo, this.CopyLogToEncodeDirectory);\r
             this.userSettingService.SetUserSetting(UserSettingConstants.SaveLogToCopyDirectory, this.CopyLogToSepcficedLocation);\r
index 362f10ec6c1972e8ec12fa6c4db319e6c1c92301..f82ec962144d7731c2891c06668192f24da83aa1 100644 (file)
@@ -487,7 +487,7 @@ namespace HandBrakeWPF.ViewModels
 \r
             var firstOrDefault = this.QueueTasks.FirstOrDefault(s => s.Status == QueueItemStatus.Waiting);\r
             if (firstOrDefault != null && !DriveUtilities.HasMinimumDiskSpace(firstOrDefault.Task.Destination,\r
-                    this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseOnLowDiskspaceLevel)))\r
+                    this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseQueueOnLowDiskspaceLevel)))\r
             {\r
                 this.errorService.ShowMessageBox(Resources.Main_LowDiskspace, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);\r
                 return;\r
index 91ecbb49408fef332212b0b26ebbc514b06bab22..08ef765575fae5162a129600b701a5f8bd99ea20 100644 (file)
       <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:long" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">10000000000</anyType>\r
     </value>\r
   </item>\r
+  <item>\r
+    <key>\r
+      <string>LowDiskSpaceEncodePauseLevelInBytes</string>\r
+    </key>\r
+    <value>\r
+      <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d4p1:type="q1:long" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance">2000000000</anyType>\r
+    </value>\r
+  </item>\r
   <item>\r
     <key>\r
       <string>ForcePresetReset</string>\r