/* Scan.cs $ This file is part of the HandBrake source code. Homepage: . It may be used under the terms of the GNU General Public License. */ namespace Handbrake.Services { using System; using System.Diagnostics; using System.IO; using System.Text; using System.Threading; using System.Windows.Forms; using Parsing; /// /// Scan a Source /// public class ScanService { /* Private Variables */ /// /// A Lock object /// private static readonly object locker = new object(); /// /// The CLI data parser /// private Parser readData; /// /// The Log Buffer /// private StringBuilder logBuffer; /// /// The line number thats been read to in the log file /// private int logFilePosition; /// /// The Process belonging to the CLI /// private Process hbProc; /* Event Handlers */ /// /// Scan has Started /// public event EventHandler ScanStared; /// /// Scan has completed /// public event EventHandler ScanCompleted; /// /// Scan process has changed to a new title /// public event EventHandler ScanStatusChanged; /* Properties */ /// /// Gets a value indicating whether IsScanning. /// public bool IsScanning { get; private set; } /// /// Gets the Scan Status. /// public string ScanStatus { get; private set; } /// /// Gets the Souce Data. /// public DVD SouceData { get; private set; } /// /// Gets ActivityLog. /// public string ActivityLog { get { if (IsScanning) return readData.Buffer.ToString(); if (logBuffer == null) { ResetLogReader(); ReadLastScanFile(); } return logBuffer != null ? logBuffer.ToString() : string.Empty; } } /* Public Methods */ /// /// Scan a Source Path. /// Title 0: scan all /// /// Path to the file to scan /// int title number. 0 for scan all public void Scan(string sourcePath, int title) { Thread t = new Thread(unused => this.ScanSource(sourcePath, title)); t.Start(); } /// /// Kill the scan /// public void Stop() { try { if (hbProc != null) hbProc.Kill(); } catch (Exception ex) { MessageBox.Show( "Unable to kill HandBrakeCLI.exe \nYou may need to manually kill HandBrakeCLI.exe using the Windows Task Manager if it does not close automatically within the next few minutes. \n\nError Information: \n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /* Private Methods */ /// /// Start a scan for a given source path and title /// /// Path to the source file /// the title number to look at private void ScanSource(object sourcePath, int title) { try { IsScanning = true; if (this.ScanStared != null) this.ScanStared(this, new EventArgs()); ResetLogReader(); string handbrakeCLIPath = Path.Combine(Application.StartupPath, "HandBrakeCLI.exe"); string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs"; string dvdInfoPath = Path.Combine(logDir, "last_scan_log.txt"); // Make we don't pick up a stale last_encode_log.txt (and that we have rights to the file) if (File.Exists(dvdInfoPath)) File.Delete(dvdInfoPath); string extraArguments = string.Empty; if (Properties.Settings.Default.noDvdNav) extraArguments = " --no-dvdnav"; if (title > 0) extraArguments += " --scan "; this.hbProc = new Process { StartInfo = { FileName = handbrakeCLIPath, Arguments = String.Format(@" -i ""{0}"" -t{1} {2} -v ", sourcePath, title, extraArguments), RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true } }; // Start the Scan this.hbProc.Start(); this.readData = new Parser(this.hbProc.StandardError.BaseStream); this.readData.OnScanProgress += new ScanProgressEventHandler(this.OnScanProgress); this.SouceData = DVD.Parse(this.readData); // Write the Buffer out to file. StreamWriter scanLog = new StreamWriter(dvdInfoPath); scanLog.Write(this.readData.Buffer); scanLog.Flush(); scanLog.Close(); logBuffer = readData.Buffer; IsScanning = false; if (this.ScanCompleted != null) this.ScanCompleted(this, new EventArgs()); } catch (Exception exc) { frmExceptionWindow exceptionWindow = new frmExceptionWindow(); exceptionWindow.Setup("frmMain.cs - scanProcess() Error", exc.ToString()); exceptionWindow.ShowDialog(); } } /// /// Read the log file /// private void ReadLastScanFile() { lock (locker) { // last_encode_log.txt is the primary log file. Since .NET can't read this file whilst the CLI is outputing to it (Not even in read only mode), // we'll need to make a copy of it. string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs"; string logFile = Path.Combine(logDir, "last_scan_log.txt"); string logFile2 = Path.Combine(logDir, "tmp_appReadable_log.txt"); try { // Make sure the application readable log file does not already exist. FileCopy fill fail if it does. if (File.Exists(logFile2)) File.Delete(logFile2); // Copy the log file. if (File.Exists(logFile)) File.Copy(logFile, logFile2, true); else { ResetLogReader(); return; } // Start the Reader // Only use text which continues on from the last read line StreamReader sr = new StreamReader(logFile2); string line; int i = 1; while ((line = sr.ReadLine()) != null) { if (i > logFilePosition) { logBuffer.AppendLine(line); logFilePosition++; } i++; } sr.Close(); sr.Dispose(); } catch (Exception exc) { Console.WriteLine(exc.ToString()); ResetLogReader(); } } } /// /// Reset the Log Reader /// private void ResetLogReader() { logFilePosition = 0; logBuffer = new StringBuilder(); } /// /// Fire an event when the scan process progresses /// /// the sender /// the current title being scanned /// the total number of titles private void OnScanProgress(object sender, int currentTitle, int titleCount) { this.ScanStatus = string.Format("Processing Title: {0} of {1}", currentTitle, titleCount); if (this.ScanStatusChanged != null) this.ScanStatusChanged(this, new EventArgs()); } } }