// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // Defines the QueueRecoveryHelper type. // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrakeWPF.Helpers { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Windows; using System.Xml.Serialization; using HandBrake.Interop.Utilities; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.Services.Queue.Model; using HandBrakeWPF.Utilities; using IQueueProcessor = HandBrakeWPF.Services.Queue.Interfaces.IQueueProcessor; /// /// Queue Recovery Helper /// public class QueueRecoveryHelper { /// /// Check if the queue recovery file contains records. /// If it does, it means the last queue did not complete before HandBrake closed. /// So, return a boolean if true. /// /// /// The filter Queue Files. /// /// /// True if there is a queue to recover. /// public static List CheckQueueRecovery(List filterQueueFiles) { try { string tempPath = DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()); DirectoryInfo info = new DirectoryInfo(tempPath); IEnumerable foundFiles = info.GetFiles("*.xml").Where(f => f.Name.StartsWith("hb_queue_recovery")); var queueFiles = GetFilesExcludingActiveProcesses(foundFiles, filterQueueFiles); if (!queueFiles.Any()) { return queueFiles; } List removeFiles = new List(); List acceptedFiles = new List(); XmlSerializer ser = new XmlSerializer(typeof(List)); foreach (string file in queueFiles) { try { using (FileStream strm = new FileStream(file, FileMode.Open, FileAccess.Read)) { List list = ser.Deserialize(strm) as List; if (list != null && list.Count == 0) { removeFiles.Add(file); } if (list != null && list.Count != 0) { List tasks = list.Where(l => l.Status != QueueItemStatus.Completed).ToList(); if (tasks.Count != 0) { acceptedFiles.Add(Path.GetFileName(file)); } else { removeFiles.Add(file); } } } } catch (Exception exc) { Debug.WriteLine(exc); } } CleanupFiles(removeFiles, false); return acceptedFiles; } catch (Exception exc) { Debug.WriteLine(exc); return new List(); // Keep quiet about the error. } } /// /// Recover a queue from file. /// /// /// The encode Queue. /// /// /// The error Service. /// /// /// The silent Recovery. /// /// /// The . /// public static bool RecoverQueue(IQueueProcessor encodeQueue, IErrorService errorService, bool silentRecovery, List queueFilter) { string appDataPath = DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()); List queueFiles = CheckQueueRecovery(queueFilter); MessageBoxResult result = MessageBoxResult.None; if (!silentRecovery) { if (queueFiles.Count == 1) { result = errorService.ShowMessageBox( "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?", "Queue Recovery Possible", MessageBoxButton.YesNo, MessageBoxImage.Question); } else if (queueFiles.Count > 1) { result = errorService.ShowMessageBox( "HandBrake has detected multiple unfinished queue files. These will be from multiple instances of HandBrake running. Would you like to recover all unfinished jobs?", "Queue Recovery Possible", MessageBoxButton.YesNo, MessageBoxImage.Question); } } else { result = MessageBoxResult.Yes; } if (result == MessageBoxResult.Yes) { bool isRecovered = false; foreach (string file in queueFiles) { // Recover the Queue encodeQueue.RestoreQueue(Path.Combine(appDataPath, file)); isRecovered = true; // Cleanup CleanupFiles(new List { file }, false); } return isRecovered; } CleanupFiles(queueFiles, true); return false; } public static bool ArchivesExist() { string appDataPath = DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()); DirectoryInfo info = new DirectoryInfo(appDataPath); IEnumerable foundFiles = info.GetFiles("*.archive").Where(f => f.Name.StartsWith("hb_queue_recovery")); return foundFiles.Any(); } private static List GetFilesExcludingActiveProcesses(IEnumerable foundFiles, List filterQueueFiles) { List queueFiles = new List(); // Remove any files where we have an active instnace. foreach (FileInfo file in foundFiles) { string fileProcessId = file.Name.Replace("hb_queue_recovery", string.Empty).Replace(".xml", string.Empty); int processId; if (!string.IsNullOrEmpty(fileProcessId) && int.TryParse(fileProcessId, out processId)) { if (!GeneralUtilities.IsPidACurrentHandBrakeInstance(processId)) { if (filterQueueFiles != null && filterQueueFiles.Count > 0) { if (filterQueueFiles.Contains(processId.ToString())) { queueFiles.Add(file.FullName); } } else { queueFiles.Add(file.FullName); } } } } return queueFiles; } private static void CleanupFiles(List removeFiles, bool archive) { string appDataPath = DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()); // Cleanup old/unused queue files for now. foreach (string file in removeFiles) { Match m = Regex.Match(file, @"([0-9]+).xml"); if (m.Success) { int processId = int.Parse(m.Groups[1].ToString()); if (GeneralUtilities.IsPidACurrentHandBrakeInstance(processId)) { continue; } } string fullPath = Path.Combine(appDataPath, file); if (archive) { File.Move(fullPath, fullPath + ".archive"); } else { File.Delete(fullPath); } } TidyArchiveFiles(); } /// /// Tidy up archive files older than 7 days. /// Gives the user an opportunity to recover a queue file they accidentally chose not to import. /// private static void TidyArchiveFiles() { string appDataPath = DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()); DirectoryInfo info = new DirectoryInfo(appDataPath); IEnumerable foundFiles = info.GetFiles("*.archive").Where(f => f.Name.StartsWith("hb_queue_recovery")); DateTime LastWeek = DateTime.Now.AddDays(-7); foreach (FileInfo file in foundFiles) { if (file.CreationTime < LastWeek) { string fullPath = Path.Combine(appDataPath, file.Name); File.Delete(fullPath); } } } public static void ResetArchives() { string appDataPath = DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()); DirectoryInfo info = new DirectoryInfo(appDataPath); IEnumerable foundFiles = info.GetFiles("*.archive").Where(f => f.Name.StartsWith("hb_queue_recovery")); foreach (FileInfo file in foundFiles) { string fullPath = Path.Combine(appDataPath, file.Name); File.Move(fullPath, fullPath.Replace(".archive", string.Empty)); } } } }