/// <summary> /// Consumes the file system changes blocking collection. /// </summary> private static void ProcessChangesQueue() { var prod = _producer; try { foreach (var evt in prod.GetConsumingEnumerable()) { try { switch (evt.Item1) { case WatcherChangeTypes.Created: { var success = false; if (File.Exists(evt.Item2[0])) { success = CheckFile(evt.Item2[0]); if (success) { Log.Debug("Added file " + Path.GetFileName(evt.Item2[0]) + " to the library."); } } else if (Directory.Exists(evt.Item2[0])) { Log.Debug("Scanning new directory " + Path.GetFileName(evt.Item2[0]) + " for episodes..."); if (_producer.Count < 10) { Log.Trace("Queue.Count < 10, waiting 5s before initiating directory scan..."); Thread.Sleep(5000); } var fs = new FileSearch(new[] {evt.Item2[0]}, CheckFile); fs.FileSearchDone += (sender, args) => { if (args.Data == null || args.Data.Count == 0) { Log.Debug("No episodes found in " + evt.Item2[0] + "."); } else { success = true; foreach (var file in args.Data) { Log.Debug("Added file " + Path.GetFileName(file) + " to the library."); } } }; fs.BeginSearch(); fs.Cancellation.CancelAfter(TimeSpan.FromMinutes(5)); try { if (!fs.SearchTask.Wait(TimeSpan.FromMinutes(5.5))) { fs.SearchTask.Dispose(); } } catch (AggregateException ex) { if (ex.InnerException is OperationCanceledException) { Log.Error("Directory scan timed out after 5 minutes of file searching."); } else { Log.Warn("Aggregate exceptions upon FileSearch._task completion.", ex); } } } else { Log.Warn(evt.Item2[0] + " has been deleted since the creation event was fired."); } if (success && !Indexing) { DataChanged(); } } break; case WatcherChangeTypes.Deleted: { var success = false; foreach (var ep in Files) { if (ep.Value.Contains(evt.Item2[0])) { ep.Value.Remove(evt.Item2[0]); success = true; Log.Debug("Removed file " + Path.GetFileName(evt.Item2[0]) + " from the library."); break; } } if (!success) { foreach (var ep in Files) { var lst = ep.Value.ToList(); foreach (var file in lst) { if (file.StartsWith(evt.Item2[0] + Path.DirectorySeparatorChar)) { ep.Value.Remove(file); success = true; Log.Debug("Removed file " + Path.GetFileName(file) + " from the library."); } } } } if (success && !Indexing) { DataChanged(); } } break; } } catch (Exception ex) { Log.Warn("Error while processing change " + evt.Item1 + " for " + evt.Item2.FirstOrDefault() + ".", ex); } } } catch (Exception ex) { Log.Debug("Exception upon producer/consumer collection enumeration.", ex); } finally { if (prod != null) { prod.Dispose(); } } }
/// <summary> /// Searches for downloaded files for the unwatched episodes. /// </summary> /// <param name="episodes">The episodes.</param> /// <returns> /// A list of found files mapped to their episode objects. /// </returns> public static Dictionary<Episode, List<string>> SearchForFiles(List<Episode> episodes) { var files = new Dictionary<Episode, List<string>>(); var busy = true; foreach (var episode in episodes) { files[episode] = new List<string>(); } var fs = new FileSearch(Settings.Get<List<string>>("Download Paths"), episodes); fs.MultiFileSearchDone += (s, e) => { for (var i = 0; i < e.Data.Length; i++) { files[episodes[i]].AddRange(e.Data[i]); } busy = false; }; fs.BeginSearch(); while (busy) { Thread.Sleep(TimeSpan.FromSeconds(1)); } return files; }
/// <summary> /// Searches for matching files in the download paths. /// </summary> public static void SearchForFiles() { if (!Signature.IsActivated) { return; } if (Indexing) { Log.Warn("A library update operation is currently running, cannot start a new one."); return; } Log.Info("Starting library update..."); if (_fsw != null && _fsw.Length != 0) { for (var i = 0; i < _fsw.Length; i++) { try { if (_fsw[i] != null) { _fsw[i].EnableRaisingEvents = false; _fsw[i].Dispose(); } } catch { } } } if (_producer != null) { _producer.CompleteAdding(); _producer.Dispose(); _producer = null; } var st = DateTime.Now; var fs = new FileSearch(Settings.Get<List<string>>("Download Paths"), CheckFile); Indexing = true; _tmp = new Dictionary<int, HashSet<string>>(); fs.BeginSearch(); fs.Cancellation.CancelAfter(TimeSpan.FromMinutes(5)); try { if (!fs.SearchTask.Wait(TimeSpan.FromMinutes(5.5))) { fs.SearchTask.Dispose(); } } catch (AggregateException ex) { if (ex.InnerException is OperationCanceledException) { Log.Error("Library update timed out after 5 minutes of file searching. Please optimize your download paths, and, if possible, please refrain from using network-attached paths."); } else { Log.Warn("Aggregate exceptions upon FileSearch._task completion.", ex); } } Files = _tmp; Indexing = false; Log.Info("Library update finished in " + (DateTime.Now - st).TotalSeconds + "s."); StartWatching(); DataChanged(false); }
/// <summary> /// Adds a new path to the library. /// </summary> /// <param name="path">The path.</param> public static void AddPath(string path) { var i = _fsw.Length; Array.Resize(ref _fsw, _fsw.Length + 1); _fsw[i] = new FileSystemWatcher(path); _fsw[i].Created += (s, a) => CheckFile(a.FullPath); _fsw[i].Renamed += (s, a) => { foreach (var ep in Files) { if (ep.Value.Contains(a.OldFullPath)) { ep.Value.Remove(a.OldFullPath); CheckFile(a.FullPath); return; } } }; _fsw[i].Deleted += (s, a) => { foreach (var ep in Files) { if (ep.Value.Contains(a.FullPath)) { ep.Value.Remove(a.FullPath); return; } } }; _fsw[i].Error += (s, a) => StartWatching(); _fsw[i].EnableRaisingEvents = true; var fs = new FileSearch(new[] { path }, CheckFile); Indexing = true; fs.BeginSearch(); fs.SearchThread.Join(TimeSpan.FromMinutes(5)); if (fs.SearchThread.IsAlive) { fs.SearchThread.Abort(); } Indexing = false; SaveList(); }
/// <summary> /// Searches for matching files in the download paths. /// </summary> public static void SearchForFiles() { var fs = new FileSearch(Settings.Get<List<string>>("Download Paths"), CheckFile); Indexing = true; fs.BeginSearch(); fs.SearchThread.Join(TimeSpan.FromMinutes(5)); if (fs.SearchThread.IsAlive) { // searching for more than 5 minutes, kill it fs.SearchThread.Abort(); } Indexing = false; SaveList(); if (MainWindow.Active != null && MainWindow.Active.activeGuidesPage != null && MainWindow.Active.activeGuidesPage._activeShowID != 0) { MainWindow.Active.Run(MainWindow.Active.activeGuidesPage.Refresh); } }
/// <summary> /// Searches for matching files in the download paths. /// </summary> public static void SearchForFiles() { if (!Signature.IsActivated) { return; } if (Indexing) { Log.Warn("A library update operation is currently running, cannot start a new one."); return; } Log.Info("Starting library update..."); if (_fsw != null && _fsw.Count != 0) { foreach (var fsw in _fsw) { try { if (fsw != null) { fsw.EnableRaisingEvents = false; fsw.Dispose(); } } catch { } } } if (_producer != null) { _producer.CompleteAdding(); _producer.Dispose(); _producer = null; } var st = DateTime.Now; var fs = new FileSearch(Settings.Get <List <string> >("Download Paths"), CheckFile); Indexing = true; _tmp = new Dictionary <int, HashSet <string> >(); fs.BeginSearch(); fs.Cancellation.CancelAfter(TimeSpan.FromMinutes(5)); try { if (!fs.SearchTask.Wait(TimeSpan.FromMinutes(5.5))) { fs.SearchTask.Dispose(); } } catch (AggregateException ex) { if (ex.InnerException is OperationCanceledException) { Log.Error("Library update timed out after 5 minutes of file searching. Please optimize your download paths, and, if possible, please refrain from using network-attached paths."); } else { Log.Warn("Aggregate exceptions upon FileSearch._task completion.", ex); } } Files = _tmp; Indexing = false; Log.Info("Library update finished in " + (DateTime.Now - st).TotalSeconds + "s."); StartWatching(); DataChanged(false); }
/// <summary> /// Consumes the file system changes blocking collection. /// </summary> private static void ProcessChangesQueue() { var prod = _producer; try { foreach (var evt in prod.GetConsumingEnumerable()) { try { switch (evt.Item1) { case WatcherChangeTypes.Created: { var success = false; if (File.Exists(evt.Item2[0])) { success = CheckFile(evt.Item2[0]); if (success) { Log.Debug("Added file " + Path.GetFileName(evt.Item2[0]) + " to the library."); } } else if (Directory.Exists(evt.Item2[0])) { AddPath(evt.Item2[0]); Log.Debug("Scanning new directory " + Path.GetFileName(evt.Item2[0]) + " for episodes..."); var fs = new FileSearch(new[] { evt.Item2[0] }, CheckFile); fs.FileSearchDone += (sender, args) => { if (args.Data == null || args.Data.Count == 0) { Log.Debug("No episodes found in " + evt.Item2[0] + "."); } else { success = true; foreach (var file in args.Data) { Log.Debug("Added file " + Path.GetFileName(file) + " to the library."); } } }; fs.BeginSearch(); fs.Cancellation.CancelAfter(TimeSpan.FromMinutes(5)); try { if (!fs.SearchTask.Wait(TimeSpan.FromMinutes(5.5))) { fs.SearchTask.Dispose(); } } catch (AggregateException ex) { if (ex.InnerException is OperationCanceledException) { Log.Error("Directory scan timed out after 5 minutes of file searching."); } else { Log.Warn("Aggregate exceptions upon FileSearch._task completion.", ex); } } } else { Log.Warn(evt.Item2[0] + " has been deleted since the creation event was fired."); } if (success && !Indexing) { DataChanged(); } } break; case WatcherChangeTypes.Deleted: { var success = false; foreach (var ep in Files) { if (ep.Value.Contains(evt.Item2[0])) { ep.Value.Remove(evt.Item2[0]); success = true; Log.Debug("Removed file " + Path.GetFileName(evt.Item2[0]) + " from the library."); break; } } if (!success) { foreach (var ep in Files) { var lst = ep.Value.ToList(); foreach (var file in lst) { if (file.StartsWith(evt.Item2[0] + Path.DirectorySeparatorChar)) { ep.Value.Remove(file); success = true; Log.Debug("Removed file " + Path.GetFileName(file) + " from the library."); } } } } if (success && !Indexing) { DataChanged(); } } break; } } catch (Exception ex) { Log.Warn("Error while processing change " + evt.Item1 + " for " + evt.Item2.FirstOrDefault() + ".", ex); } } } catch (Exception ex) { Log.Debug("Exception upon producer/consumer collection enumeration.", ex); } finally { if (prod != null) { prod.Dispose(); } } }