2 This file is part of the HandBrake source code.
\r
3 Homepage: <http://handbrake.fr>.
\r
4 It may be used under the terms of the GNU General Public License. */
\r
6 namespace HandBrake.ApplicationServices.Services
\r
9 using System.Diagnostics;
\r
12 using System.Threading;
\r
13 using System.Windows.Forms;
\r
15 using HandBrake.Framework.Services;
\r
16 using HandBrake.Framework.Services.Interfaces;
\r
17 using HandBrake.ApplicationServices.Functions;
\r
18 using HandBrake.ApplicationServices.Parsing;
\r
19 using HandBrake.ApplicationServices.Services.Interfaces;
\r
24 public class ScanService : IScan
\r
26 /* Private Variables */
\r
29 /// The Error Service
\r
31 private readonly IErrorService errorService;
\r
36 private static readonly object locker = new object();
\r
39 /// The CLI data parser
\r
41 private Parser readData;
\r
46 private StringBuilder logBuffer;
\r
49 /// The line number thats been read to in the log file
\r
51 private int logFilePosition;
\r
54 /// The Process belonging to the CLI
\r
56 private Process hbProc;
\r
59 /// Initializes a new instance of the <see cref="ScanService"/> class.
\r
61 public ScanService()
\r
63 this.errorService = new ErrorService();
\r
66 /* Event Handlers */
\r
69 /// Scan has Started
\r
71 public event EventHandler ScanStared;
\r
74 /// Scan has completed
\r
76 public event EventHandler ScanCompleted;
\r
79 /// Scan process has changed to a new title
\r
81 public event EventHandler ScanStatusChanged;
\r
86 /// Gets a value indicating whether IsScanning.
\r
88 public bool IsScanning { get; private set; }
\r
91 /// Gets the Scan Status.
\r
93 public string ScanStatus { get; private set; }
\r
96 /// Gets the Souce Data.
\r
98 public DVD SouceData { get; private set; }
\r
101 /// Gets ActivityLog.
\r
103 public string ActivityLog
\r
108 return readData.Buffer.ToString();
\r
110 if (logBuffer == null)
\r
112 ResetLogReader(false);
\r
113 ReadLastScanFile();
\r
116 return logBuffer != null ? logBuffer.ToString() : string.Empty;
\r
120 /* Public Methods */
\r
123 /// Scan a Source Path.
\r
124 /// Title 0: scan all
\r
126 /// <param name="sourcePath">Path to the file to scan</param>
\r
127 /// <param name="title">int title number. 0 for scan all</param>
\r
128 public void Scan(string sourcePath, int title)
\r
130 Thread t = new Thread(unused => this.ScanSource(sourcePath, title));
\r
141 this.readData.OnScanProgress -= this.OnScanProgress;
\r
143 if (hbProc != null && !hbProc.HasExited)
\r
146 catch (Exception ex)
\r
148 errorService.ShowError("Unable to kill HandBrakeCLI.exe \n" +
\r
149 "You may need to manually kill HandBrakeCLI.exe using the Windows Task Manager if it does not close automatically" +
\r
150 " within the next few minutes. ", ex.ToString());
\r
154 /* Private Methods */
\r
157 /// Start a scan for a given source path and title
\r
159 /// <param name="sourcePath">Path to the source file</param>
\r
160 /// <param name="title">the title number to look at</param>
\r
161 private void ScanSource(object sourcePath, int title)
\r
166 if (this.ScanStared != null)
\r
167 this.ScanStared(this, new EventArgs());
\r
169 ResetLogReader(true);
\r
171 string handbrakeCLIPath = Path.Combine(Application.StartupPath, "HandBrakeCLI.exe");
\r
172 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
\r
173 "\\HandBrake\\logs";
\r
174 string dvdInfoPath = Path.Combine(logDir, string.Format("last_scan_log{0}.txt", Init.InstanceId == 0 ? string.Empty : Init.InstanceId.ToString()));
\r
176 // Make we don't pick up a stale last_encode_log.txt (and that we have rights to the file)
\r
177 if (File.Exists(dvdInfoPath))
\r
178 File.Delete(dvdInfoPath);
\r
180 string extraArguments = string.Empty;
\r
181 if (Init.DisableDvdNav)
\r
182 extraArguments = " --no-dvdnav";
\r
185 extraArguments += " --scan ";
\r
187 this.hbProc = new Process
\r
191 FileName = handbrakeCLIPath,
\r
193 String.Format(@" -i ""{0}"" -t{1} {2} -v ", sourcePath, title,
\r
195 RedirectStandardOutput = true,
\r
196 RedirectStandardError = true,
\r
197 UseShellExecute = false,
\r
198 CreateNoWindow = true
\r
203 this.hbProc.Start();
\r
205 this.readData = new Parser(this.hbProc.StandardError.BaseStream);
\r
206 this.readData.OnScanProgress += this.OnScanProgress;
\r
207 this.SouceData = DVD.Parse(this.readData);
\r
209 // Write the Buffer out to file.
\r
210 using (StreamWriter scanLog = new StreamWriter(dvdInfoPath))
\r
212 // Only write the log file to disk if it's less than 100MB.
\r
213 if (this.readData.Buffer.Length < 100000000)
\r
215 scanLog.WriteLine(Logging.CreateCliLogHeader(null));
\r
216 scanLog.Write(this.readData.Buffer);
\r
217 logBuffer.AppendLine(this.readData.Buffer.ToString());
\r
221 throw new Exception(
\r
222 "The Log file has not been written to disk as it has grown above the 100MB limit. This indicates there was a problem during the scan process.");
\r
226 IsScanning = false;
\r
228 if (this.ScanCompleted != null)
\r
229 this.ScanCompleted(this, new EventArgs());
\r
231 catch (Exception exc)
\r
235 errorService.ShowError("An error has occured during the scan process.", exc.ToString());
\r
237 if (this.ScanCompleted != null)
\r
238 this.ScanCompleted(this, new EventArgs());
\r
243 /// Read the log file
\r
245 private void ReadLastScanFile()
\r
249 // 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),
\r
250 // we'll need to make a copy of it.
\r
251 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
\r
252 "\\HandBrake\\logs";
\r
253 string logFile = Path.Combine(logDir, string.Format("last_scan_log{0}.txt", Init.InstanceId == 0 ? string.Empty : Init.InstanceId.ToString()));
\r
254 string logFile2 = Path.Combine(logDir, string.Format("tmp_appReadable_log{0}.txt", Init.InstanceId == 0 ? string.Empty : Init.InstanceId.ToString()));
\r
258 // Make sure the application readable log file does not already exist. FileCopy fill fail if it does.
\r
259 if (File.Exists(logFile2))
\r
260 File.Delete(logFile2);
\r
262 // Copy the log file.
\r
263 if (File.Exists(logFile))
\r
264 File.Copy(logFile, logFile2, true);
\r
267 ResetLogReader(true);
\r
271 // Start the Reader
\r
272 // Only use text which continues on from the last read line
\r
273 StreamReader sr = new StreamReader(logFile2);
\r
276 while ((line = sr.ReadLine()) != null)
\r
278 if (i > logFilePosition)
\r
280 logBuffer.AppendLine(line);
\r
288 catch (Exception exc)
\r
290 Console.WriteLine(exc.ToString());
\r
291 ResetLogReader(true);
\r
297 /// Reset the Log Reader
\r
299 /// <param name="addHeader">
\r
300 /// The add Header.
\r
302 private void ResetLogReader(bool addHeader)
\r
304 logFilePosition = 0;
\r
305 logBuffer = new StringBuilder();
\r
307 logBuffer.AppendLine(Logging.CreateCliLogHeader(null));
\r
311 /// Fire an event when the scan process progresses
\r
313 /// <param name="sender">the sender</param>
\r
314 /// <param name="currentTitle">the current title being scanned</param>
\r
315 /// <param name="titleCount">the total number of titles</param>
\r
316 private void OnScanProgress(object sender, int currentTitle, int titleCount)
\r
318 this.ScanStatus = string.Format("Processing Title: {0} of {1}", currentTitle, titleCount);
\r
319 if (this.ScanStatusChanged != null)
\r
320 this.ScanStatusChanged(this, new EventArgs());
\r