DirectoryWatchers.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. using MediaBrowser.Controller.Entities;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace MediaBrowser.Controller.IO
  9. {
  10. public class DirectoryWatchers
  11. {
  12. private readonly List<FileSystemWatcher> FileSystemWatchers = new List<FileSystemWatcher>();
  13. private Timer updateTimer;
  14. private List<string> affectedPaths = new List<string>();
  15. private const int TimerDelayInSeconds = 5;
  16. public void Start()
  17. {
  18. var pathsToWatch = new List<string>();
  19. var rootFolder = Kernel.Instance.RootFolder;
  20. pathsToWatch.Add(rootFolder.Path);
  21. foreach (Folder folder in rootFolder.Children.OfType<Folder>())
  22. {
  23. foreach (Folder subFolder in folder.Children.OfType<Folder>())
  24. {
  25. if (Path.IsPathRooted(subFolder.Path))
  26. {
  27. string parent = Path.GetDirectoryName(subFolder.Path);
  28. if (!pathsToWatch.Contains(parent))
  29. {
  30. pathsToWatch.Add(parent);
  31. }
  32. }
  33. }
  34. }
  35. foreach (string path in pathsToWatch)
  36. {
  37. var watcher = new FileSystemWatcher(path, "*") { };
  38. watcher.IncludeSubdirectories = true;
  39. watcher.Changed += watcher_Changed;
  40. // All the others seem to trigger change events on the parent, so let's keep it simple for now.
  41. //watcher.Created += watcher_Changed;
  42. //watcher.Deleted += watcher_Changed;
  43. //watcher.Renamed += watcher_Changed;
  44. watcher.EnableRaisingEvents = true;
  45. FileSystemWatchers.Add(watcher);
  46. }
  47. }
  48. void watcher_Changed(object sender, FileSystemEventArgs e)
  49. {
  50. if (!affectedPaths.Contains(e.FullPath))
  51. {
  52. affectedPaths.Add(e.FullPath);
  53. }
  54. if (updateTimer == null)
  55. {
  56. updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(TimerDelayInSeconds), TimeSpan.FromMilliseconds(-1));
  57. }
  58. else
  59. {
  60. updateTimer.Change(TimeSpan.FromSeconds(TimerDelayInSeconds), TimeSpan.FromMilliseconds(-1));
  61. }
  62. }
  63. private async void TimerStopped(object stateInfo)
  64. {
  65. updateTimer.Dispose();
  66. updateTimer = null;
  67. List<string> paths = affectedPaths;
  68. affectedPaths = new List<string>();
  69. await ProcessPathChanges(paths).ConfigureAwait(false);
  70. }
  71. private Task ProcessPathChanges(IEnumerable<string> paths)
  72. {
  73. var itemsToRefresh = new List<BaseItem>();
  74. foreach (BaseItem item in paths.Select(p => GetAffectedBaseItem(p)))
  75. {
  76. if (item != null && !itemsToRefresh.Contains(item))
  77. {
  78. itemsToRefresh.Add(item);
  79. }
  80. }
  81. if (itemsToRefresh.Any(i =>
  82. {
  83. var folder = i as Folder;
  84. return folder != null && folder.IsRoot;
  85. }))
  86. {
  87. return Kernel.Instance.ReloadRoot();
  88. }
  89. return Task.WhenAll(itemsToRefresh.Select(i => Kernel.Instance.ReloadItem(i)));
  90. }
  91. private BaseItem GetAffectedBaseItem(string path)
  92. {
  93. BaseItem item = null;
  94. while (item == null)
  95. {
  96. item = Kernel.Instance.RootFolder.FindByPath(path);
  97. path = Path.GetDirectoryName(path);
  98. }
  99. return item;
  100. }
  101. public void Stop()
  102. {
  103. foreach (FileSystemWatcher watcher in FileSystemWatchers)
  104. {
  105. watcher.Changed -= watcher_Changed;
  106. watcher.EnableRaisingEvents = false;
  107. watcher.Dispose();
  108. }
  109. if (updateTimer != null)
  110. {
  111. updateTimer.Dispose();
  112. updateTimer = null;
  113. }
  114. FileSystemWatchers.Clear();
  115. affectedPaths.Clear();
  116. }
  117. }
  118. }