소스 검색

begin file system rework

Luke Pulverenti 9 년 전
부모
커밋
8ad702060e
77개의 변경된 파일505개의 추가작업 그리고 282개의 파일을 삭제
  1. 2 2
      MediaBrowser.Api/Playback/Dash/MpegDashService.cs
  2. 2 2
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  3. 2 2
      MediaBrowser.Api/System/SystemService.cs
  4. 86 48
      MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
  5. 32 0
      MediaBrowser.Common/IO/FileSystemMetadata.cs
  6. 125 20
      MediaBrowser.Common/IO/IFileSystem.cs
  7. 1 0
      MediaBrowser.Common/MediaBrowser.Common.csproj
  8. 4 3
      MediaBrowser.Controller/Entities/AggregateFolder.cs
  9. 16 21
      MediaBrowser.Controller/Entities/BaseItem.cs
  10. 4 3
      MediaBrowser.Controller/Entities/CollectionFolder.cs
  11. 3 2
      MediaBrowser.Controller/Entities/Folder.cs
  12. 5 4
      MediaBrowser.Controller/Entities/IHasImages.cs
  13. 3 2
      MediaBrowser.Controller/Entities/Movies/Movie.cs
  14. 2 1
      MediaBrowser.Controller/Entities/Video.cs
  15. 3 3
      MediaBrowser.Controller/IO/FileData.cs
  16. 14 5
      MediaBrowser.Controller/Library/ILibraryManager.cs
  17. 8 7
      MediaBrowser.Controller/Library/ItemResolveArgs.cs
  18. 14 14
      MediaBrowser.Controller/Providers/DirectoryService.cs
  19. 7 6
      MediaBrowser.Controller/Providers/IDirectoryService.cs
  20. 2 1
      MediaBrowser.Controller/Providers/LocalImageInfo.cs
  21. 5 4
      MediaBrowser.Controller/Resolvers/IItemResolver.cs
  22. 1 1
      MediaBrowser.LocalMetadata/BaseXmlProvider.cs
  23. 2 2
      MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
  24. 13 13
      MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
  25. 5 2
      MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs
  26. 1 1
      MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs
  27. 2 2
      MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs
  28. 2 2
      MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs
  29. 1 1
      MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs
  30. 3 3
      MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs
  31. 5 10
      MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs
  32. 1 1
      MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs
  33. 1 1
      MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs
  34. 1 1
      MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs
  35. 1 1
      MediaBrowser.LocalMetadata/Providers/SeasonXmlProvider.cs
  36. 1 1
      MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs
  37. 1 1
      MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs
  38. 4 1
      MediaBrowser.Model/Devices/DeviceInfo.cs
  39. 1 1
      MediaBrowser.Providers/ImagesByName/ImageUtils.cs
  40. 1 1
      MediaBrowser.Providers/Manager/ImageSaver.cs
  41. 1 1
      MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs
  42. 1 1
      MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs
  43. 1 1
      MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
  44. 1 1
      MediaBrowser.Providers/Movies/MovieDbProvider.cs
  45. 1 1
      MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
  46. 1 1
      MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
  47. 1 1
      MediaBrowser.Providers/Music/FanArtArtistProvider.cs
  48. 1 1
      MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs
  49. 1 1
      MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
  50. 1 1
      MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs
  51. 1 1
      MediaBrowser.Providers/TV/FanartSeriesProvider.cs
  52. 1 1
      MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs
  53. 1 1
      MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs
  54. 5 5
      MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
  55. 1 1
      MediaBrowser.Providers/TV/TvdbPrescanTask.cs
  56. 1 1
      MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs
  57. 1 1
      MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
  58. 4 7
      MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
  59. 1 1
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  60. 8 9
      MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
  61. 3 2
      MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
  62. 50 16
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  63. 2 2
      MediaBrowser.Server.Implementations/Library/ResolverHelper.cs
  64. 1 1
      MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
  65. 10 9
      MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
  66. 1 1
      MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
  67. 1 1
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  68. 1 1
      MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
  69. 1 1
      MediaBrowser.Server.Startup.Common/ApplicationHost.cs
  70. 1 1
      MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
  71. 1 1
      MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
  72. 1 1
      MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs
  73. 1 1
      MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs
  74. 1 1
      MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
  75. 1 1
      MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
  76. 1 1
      MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
  77. 7 7
      MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs

+ 2 - 2
MediaBrowser.Api/Playback/Dash/MpegDashService.cs

@@ -322,7 +322,7 @@ namespace MediaBrowser.Api.Playback.Dash
             }
         }
 
-        private static List<FileInfo> GetLastTranscodingFiles(string playlist, string segmentExtension, IFileSystem fileSystem, int count)
+        private static List<FileSystemMetadata> GetLastTranscodingFiles(string playlist, string segmentExtension, IFileSystem fileSystem, int count)
         {
             var folder = Path.GetDirectoryName(playlist);
 
@@ -336,7 +336,7 @@ namespace MediaBrowser.Api.Playback.Dash
             }
             catch (DirectoryNotFoundException)
             {
-                return new List<FileInfo>();
+                return new List<FileSystemMetadata>();
             }
         }
 

+ 2 - 2
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -354,7 +354,7 @@ namespace MediaBrowser.Api.Playback.Hls
             }
         }
 
-        private void DeleteFile(FileInfo file, int retryCount)
+        private void DeleteFile(FileSystemMetadata file, int retryCount)
         {
             if (retryCount >= 5)
             {
@@ -378,7 +378,7 @@ namespace MediaBrowser.Api.Playback.Hls
             }
         }
 
-        private static FileInfo GetLastTranscodingFile(string playlist, string segmentExtension, IFileSystem fileSystem)
+        private static FileSystemMetadata GetLastTranscodingFile(string playlist, string segmentExtension, IFileSystem fileSystem)
         {
             var folder = Path.GetDirectoryName(playlist);
 

+ 2 - 2
MediaBrowser.Api/System/SystemService.cs

@@ -118,7 +118,7 @@ namespace MediaBrowser.Api.System
 
         public object Get(GetServerLogs request)
         {
-            List<FileInfo> files;
+            List<FileSystemMetadata> files;
 
             try
             {
@@ -128,7 +128,7 @@ namespace MediaBrowser.Api.System
             }
             catch (DirectoryNotFoundException)
             {
-                files = new List<FileInfo>();
+                files = new List<FileSystemMetadata>();
             }
 
             var result = files.Select(i => new LogFile

+ 86 - 48
MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs

@@ -27,7 +27,7 @@ namespace MediaBrowser.Common.Implementations.IO
             SetInvalidFileNameChars(usePresetInvalidFileNameChars);
         }
 
-        private void SetInvalidFileNameChars(bool usePresetInvalidFileNameChars)
+        protected void SetInvalidFileNameChars(bool usePresetInvalidFileNameChars)
         {
             // GetInvalidFileNameChars is less restrictive in Linux/Mac than Windows, this mimic Windows behavior for mono under Linux/Mac.
 
@@ -115,7 +115,7 @@ namespace MediaBrowser.Common.Implementations.IO
         /// </summary>
         /// <param name="path">The path.</param>
         /// <returns>FileSystemInfo.</returns>
-        public FileSystemInfo GetFileSystemInfo(string path)
+        public FileSystemMetadata GetFileSystemInfo(string path)
         {
             if (string.IsNullOrEmpty(path))
             {
@@ -129,10 +129,10 @@ namespace MediaBrowser.Common.Implementations.IO
 
                 if (fileInfo.Exists)
                 {
-                    return fileInfo;
+                    return GetFileSystemMetadata(fileInfo);
                 }
 
-                return new DirectoryInfo(path);
+                return GetFileSystemMetadata(new DirectoryInfo(path));
             }
             else
             {
@@ -140,13 +140,63 @@ namespace MediaBrowser.Common.Implementations.IO
 
                 if (fileInfo.Exists)
                 {
-                    return fileInfo;
+                    return GetFileSystemMetadata(fileInfo);
                 }
 
-                return new FileInfo(path);
+                return GetFileSystemMetadata(new FileInfo(path));
             }
         }
 
+        public FileSystemMetadata GetFileInfo(string path)
+        {
+            if (string.IsNullOrEmpty(path))
+            {
+                throw new ArgumentNullException("path");
+            }
+
+            var fileInfo = new FileInfo(path);
+
+            return GetFileSystemMetadata(fileInfo);
+        }
+
+        public FileSystemMetadata GetDirectoryInfo(string path)
+        {
+            if (string.IsNullOrEmpty(path))
+            {
+                throw new ArgumentNullException("path");
+            }
+
+            var fileInfo = new DirectoryInfo(path);
+
+            return GetFileSystemMetadata(fileInfo);
+        }
+
+        private FileSystemMetadata GetFileSystemMetadata(FileSystemInfo info)
+        {
+            var result = new FileSystemMetadata();
+
+            result.Attributes = info.Attributes;
+            result.Exists = info.Exists;
+            result.FullName = info.FullName;
+            result.Extension = info.Extension;
+            result.Name = info.Name;
+
+            if (result.Exists)
+            {
+                var fileInfo = info as FileInfo;
+                if (fileInfo != null)
+                {
+                    result.Length = fileInfo.Length;
+                    result.DirectoryName = fileInfo.DirectoryName;
+                }
+
+                result.CreationTimeUtc = GetCreationTimeUtc(info);
+                result.LastWriteTimeUtc = GetLastWriteTimeUtc(info);
+            }
+
+            return result;
+        }
+
         /// <summary>
         /// The space char
         /// </summary>
@@ -194,6 +244,26 @@ namespace MediaBrowser.Common.Implementations.IO
             }
         }
 
+        /// <summary>
+        /// Gets the creation time UTC.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns>DateTime.</returns>
+        public DateTime GetCreationTimeUtc(string path)
+        {
+            return GetCreationTimeUtc(GetFileSystemInfo(path));
+        }
+
+        public DateTime GetCreationTimeUtc(FileSystemMetadata info)
+        {
+            return info.CreationTimeUtc;
+        }
+
+        public DateTime GetLastWriteTimeUtc(FileSystemMetadata info)
+        {
+            return info.LastWriteTimeUtc;
+        }
+        
         /// <summary>
         /// Gets the creation time UTC.
         /// </summary>
@@ -346,41 +416,9 @@ namespace MediaBrowser.Common.Implementations.IO
             return path.TrimEnd(Path.DirectorySeparatorChar);
         }
 
-        public string SubstitutePath(string path, string from, string to)
+        public string GetFileNameWithoutExtension(FileSystemMetadata info)
         {
-            if (string.IsNullOrWhiteSpace(path))
-            {
-                throw new ArgumentNullException("path");
-            }
-            if (string.IsNullOrWhiteSpace(from))
-            {
-                throw new ArgumentNullException("from");
-            }
-            if (string.IsNullOrWhiteSpace(to))
-            {
-                throw new ArgumentNullException("to");
-            }
-
-            var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase);
-
-            if (!string.Equals(newPath, path))
-            {
-                if (to.IndexOf('/') != -1)
-                {
-                    newPath = newPath.Replace('\\', '/');
-                }
-                else
-                {
-                    newPath = newPath.Replace('/', '\\');
-                }
-            }
-
-            return newPath;
-        }
-
-        public string GetFileNameWithoutExtension(FileSystemInfo info)
-        {
-            if (info is DirectoryInfo)
+            if (info.IsDirectory)
             {
                 return info.Name;
             }
@@ -426,28 +464,28 @@ namespace MediaBrowser.Common.Implementations.IO
 		{
 			Directory.CreateDirectory(path);
 		}
-			
-		public IEnumerable<DirectoryInfo> GetDirectories(string path, bool recursive = false) 
+
+        public IEnumerable<FileSystemMetadata> GetDirectories(string path, bool recursive = false) 
 		{
 			var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
 
-			return new DirectoryInfo (path).EnumerateDirectories("*", searchOption);
+            return new DirectoryInfo(path).EnumerateDirectories("*", searchOption).Select(GetFileSystemMetadata);
 		}
 
-		public IEnumerable<FileInfo> GetFiles(string path, bool recursive = false) 
+        public IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false) 
 		{
 			var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
 
-			return new DirectoryInfo (path).EnumerateFiles("*", searchOption);
+			return new DirectoryInfo (path).EnumerateFiles("*", searchOption).Select(GetFileSystemMetadata);
 		}
 
-		public IEnumerable<FileSystemInfo> GetFileSystemEntries(string path, bool recursive = false) 
+        public IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false) 
 		{
 			var directoryInfo = new DirectoryInfo (path);
 			var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
 
-			return directoryInfo.EnumerateDirectories("*", searchOption)
-							.Concat<FileSystemInfo>(directoryInfo.EnumerateFiles("*", searchOption));
+            return directoryInfo.EnumerateDirectories("*", searchOption).Select(GetFileSystemMetadata)
+							.Concat(directoryInfo.EnumerateFiles("*", searchOption).Select(GetFileSystemMetadata));
 		}
 
         public Stream OpenRead(string path)

+ 32 - 0
MediaBrowser.Common/IO/FileSystemMetadata.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Common.IO
+{
+    public class FileSystemMetadata
+    {
+        public FileAttributes Attributes { get; set; }
+
+        public bool Exists { get; set; }
+        public string FullName { get; set; }
+        public string Name { get; set; }
+        public string Extension { get; set; }
+        public long Length { get; set; }
+        public string DirectoryName { get; set; }
+
+        public DateTime LastWriteTimeUtc { get; set; }
+        public DateTime CreationTimeUtc { get; set; }
+        
+        public bool IsDirectory
+        {
+            get
+            {
+                return (Attributes & FileAttributes.Directory) == FileAttributes.Directory;
+            }
+        }
+    }
+}

+ 125 - 20
MediaBrowser.Common/IO/IFileSystem.cs

@@ -36,8 +36,22 @@ namespace MediaBrowser.Common.IO
         /// </summary>
         /// <param name="path">The path.</param>
         /// <returns>FileSystemInfo.</returns>
-        FileSystemInfo GetFileSystemInfo(string path);
+        FileSystemMetadata GetFileSystemInfo(string path);
 
+        /// <summary>
+        /// Gets the file information.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns>FileSystemMetadata.</returns>
+        FileSystemMetadata GetFileInfo(string path);
+
+        /// <summary>
+        /// Gets the directory information.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns>FileSystemMetadata.</returns>
+        FileSystemMetadata GetDirectoryInfo(string path);
+        
         /// <summary>
         /// Gets the valid filename.
         /// </summary>
@@ -48,17 +62,24 @@ namespace MediaBrowser.Common.IO
         /// <summary>
         /// Gets the creation time UTC.
         /// </summary>
-        /// <param name="info">The info.</param>
+        /// <param name="info">The information.</param>
+        /// <returns>DateTime.</returns>
+        DateTime GetCreationTimeUtc(FileSystemMetadata info);
+        
+        /// <summary>
+        /// Gets the creation time UTC.
+        /// </summary>
+        /// <param name="path">The path.</param>
         /// <returns>DateTime.</returns>
-        DateTime GetCreationTimeUtc(FileSystemInfo info);
+        DateTime GetCreationTimeUtc(string path);
 
         /// <summary>
         /// Gets the last write time UTC.
         /// </summary>
         /// <param name="info">The information.</param>
         /// <returns>DateTime.</returns>
-        DateTime GetLastWriteTimeUtc(FileSystemInfo info);
-
+        DateTime GetLastWriteTimeUtc(FileSystemMetadata info);
+        
         /// <summary>
         /// Gets the last write time UTC.
         /// </summary>
@@ -77,6 +98,11 @@ namespace MediaBrowser.Common.IO
         /// <returns>FileStream.</returns>
         Stream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share, bool isAsync = false);
 
+        /// <summary>
+        /// Opens the read.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns>Stream.</returns>
 		Stream OpenRead(String path);
 
         /// <summary>
@@ -108,21 +134,12 @@ namespace MediaBrowser.Common.IO
         /// <returns>System.String.</returns>
         string NormalizePath(string path);
 
-        /// <summary>
-        /// Substitutes the path.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="from">From.</param>
-        /// <param name="to">To.</param>
-        /// <returns>System.String.</returns>
-        string SubstitutePath(string path, string from, string to);
-
         /// <summary>
         /// Gets the file name without extension.
         /// </summary>
         /// <param name="info">The information.</param>
         /// <returns>System.String.</returns>
-        string GetFileNameWithoutExtension(FileSystemInfo info);
+        string GetFileNameWithoutExtension(FileSystemMetadata info);
 
         /// <summary>
         /// Gets the file name without extension.
@@ -150,37 +167,125 @@ namespace MediaBrowser.Common.IO
         /// <param name="path">The path.</param>
         /// <param name="recursive">if set to <c>true</c> [recursive].</param>
         void DeleteDirectory(string path, bool recursive);
-        
-        IEnumerable<DirectoryInfo> GetDirectories(string path, bool recursive = false);
 
-		IEnumerable<FileInfo> GetFiles(string path, bool recursive = false);
+        /// <summary>
+        /// Gets the directories.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+        /// <returns>IEnumerable&lt;DirectoryInfo&gt;.</returns>
+        IEnumerable<FileSystemMetadata> GetDirectories(string path, bool recursive = false);
 
-		IEnumerable<FileSystemInfo> GetFileSystemEntries(string path, bool recursive = false);
+        /// <summary>
+        /// Gets the files.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+        /// <returns>IEnumerable&lt;FileInfo&gt;.</returns>
+        IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false);
+
+        /// <summary>
+        /// Gets the file system entries.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+        /// <returns>IEnumerable&lt;FileSystemMetadata&gt;.</returns>
+        IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false);
 
+        /// <summary>
+        /// Creates the directory.
+        /// </summary>
+        /// <param name="path">The path.</param>
 		void CreateDirectory(string path);
 
+        /// <summary>
+        /// Copies the file.
+        /// </summary>
+        /// <param name="source">The source.</param>
+        /// <param name="target">The target.</param>
+        /// <param name="overwrite">if set to <c>true</c> [overwrite].</param>
 		void CopyFile(string source, string target, bool overwrite);
 
+        /// <summary>
+        /// Moves the file.
+        /// </summary>
+        /// <param name="source">The source.</param>
+        /// <param name="target">The target.</param>
 		void MoveFile(string source, string target);
 
+        /// <summary>
+        /// Moves the directory.
+        /// </summary>
+        /// <param name="source">The source.</param>
+        /// <param name="target">The target.</param>
 		void MoveDirectory(string source, string target);
 
+        /// <summary>
+        /// Directories the exists.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
 		bool DirectoryExists(string path);
 
+        /// <summary>
+        /// Files the exists.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
 		bool FileExists(string path);
 
+        /// <summary>
+        /// Reads all text.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns>System.String.</returns>
 		string ReadAllText(string path);
 
+        /// <summary>
+        /// Writes all text.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="text">The text.</param>
         void WriteAllText(string path, string text);
-        
+
+        /// <summary>
+        /// Writes all text.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="text">The text.</param>
+        /// <param name="encoding">The encoding.</param>
         void WriteAllText(string path, string text, Encoding encoding);
 
+        /// <summary>
+        /// Reads all text.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="encoding">The encoding.</param>
+        /// <returns>System.String.</returns>
         string ReadAllText(string path, Encoding encoding);
 
+        /// <summary>
+        /// Gets the directory paths.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+        /// <returns>IEnumerable&lt;System.String&gt;.</returns>
         IEnumerable<string> GetDirectoryPaths(string path, bool recursive = false);
 
+        /// <summary>
+        /// Gets the file paths.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+        /// <returns>IEnumerable&lt;System.String&gt;.</returns>
         IEnumerable<string> GetFilePaths(string path, bool recursive = false);
 
+        /// <summary>
+        /// Gets the file system entry paths.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
+        /// <returns>IEnumerable&lt;System.String&gt;.</returns>
         IEnumerable<string> GetFileSystemEntryPaths(string path, bool recursive = false);
     }
 }

+ 1 - 0
MediaBrowser.Common/MediaBrowser.Common.csproj

@@ -60,6 +60,7 @@
     <Compile Include="Extensions\BaseExtensions.cs" />
     <Compile Include="Extensions\ResourceNotFoundException.cs" />
     <Compile Include="IDependencyContainer.cs" />
+    <Compile Include="IO\FileSystemMetadata.cs" />
     <Compile Include="IO\IFileSystem.cs" />
     <Compile Include="IO\ProgressStream.cs" />
     <Compile Include="IO\StreamDefaults.cs" />

+ 4 - 3
MediaBrowser.Controller/Entities/AggregateFolder.cs

@@ -6,6 +6,7 @@ using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Runtime.Serialization;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Providers;
 
 namespace MediaBrowser.Controller.Entities
@@ -62,7 +63,7 @@ namespace MediaBrowser.Controller.Entities
 
         public List<string> PhysicalLocationsList { get; set; }
 
-        protected override IEnumerable<FileSystemInfo> GetFileSystemChildren(IDirectoryService directoryService)
+        protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
         {
             return CreateResolveArgs(directoryService).FileSystemChildren;
         }
@@ -73,7 +74,7 @@ namespace MediaBrowser.Controller.Entities
 
             var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths , directoryService)
             {
-                FileInfo = new DirectoryInfo(path),
+                FileInfo = FileSystem.GetDirectoryInfo(path),
                 Path = path,
                 Parent = Parent
             };
@@ -94,7 +95,7 @@ namespace MediaBrowser.Controller.Entities
                 {
                     var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Keys);
 
-                    fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName);
+                    fileSystemDictionary = paths.Select(FileSystem.GetDirectoryInfo).ToDictionary(i => i.FullName);
                 }
 
                 args.FileSystemDictionary = fileSystemDictionary;

+ 16 - 21
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -676,7 +676,7 @@ namespace MediaBrowser.Controller.Entities
         /// Loads the theme songs.
         /// </summary>
         /// <returns>List{Audio.Audio}.</returns>
-        private IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
+        private IEnumerable<Audio.Audio> LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
         {
             var files = fileSystemChildren.OfType<DirectoryInfo>()
                 .Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
@@ -684,8 +684,8 @@ namespace MediaBrowser.Controller.Entities
                 .ToList();
 
             // Support plex/xbmc convention
-            files.AddRange(fileSystemChildren.OfType<FileInfo>()
-                .Where(i => string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase))
+            files.AddRange(fileSystemChildren
+                .Where(i => !i.IsDirectory && string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase))
                 );
 
             return LibraryManager.ResolvePaths(files, directoryService, null)
@@ -712,7 +712,7 @@ namespace MediaBrowser.Controller.Entities
         /// Loads the video backdrops.
         /// </summary>
         /// <returns>List{Video}.</returns>
-        private IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
+        private IEnumerable<Video> LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
         {
             var files = fileSystemChildren.OfType<DirectoryInfo>()
                 .Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
@@ -761,7 +761,7 @@ namespace MediaBrowser.Controller.Entities
                 {
                     var files = locationType != LocationType.Remote && locationType != LocationType.Virtual ?
                         GetFileSystemChildren(options.DirectoryService).ToList() :
-                        new List<FileSystemInfo>();
+                        new List<FileSystemMetadata>();
 
                     var ownedItemsChanged = await RefreshedOwnedItems(options, files, cancellationToken).ConfigureAwait(false);
 
@@ -808,7 +808,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="fileSystemChildren"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+        protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var themeSongsChanged = false;
 
@@ -839,14 +839,14 @@ namespace MediaBrowser.Controller.Entities
             return themeSongsChanged || themeVideosChanged || localTrailersChanged;
         }
 
-        protected virtual IEnumerable<FileSystemInfo> GetFileSystemChildren(IDirectoryService directoryService)
+        protected virtual IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
         {
             var path = ContainingFolderPath;
 
             return directoryService.GetFileSystemEntries(path);
         }
 
-        private async Task<bool> RefreshLocalTrailers(IHasTrailers item, MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+        private async Task<bool> RefreshLocalTrailers(IHasTrailers item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var newItems = LibraryManager.FindTrailers(this, fileSystemChildren, options.DirectoryService).ToList();
 
@@ -863,7 +863,7 @@ namespace MediaBrowser.Controller.Entities
             return itemsChanged;
         }
 
-        private async Task<bool> RefreshThemeVideos(IHasThemeMedia item, MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+        private async Task<bool> RefreshThemeVideos(IHasThemeMedia item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService).ToList();
 
@@ -894,7 +894,7 @@ namespace MediaBrowser.Controller.Entities
         /// <summary>
         /// Refreshes the theme songs.
         /// </summary>
-        private async Task<bool> RefreshThemeSongs(IHasThemeMedia item, MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+        private async Task<bool> RefreshThemeSongs(IHasThemeMedia item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService).ToList();
             var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList();
@@ -1395,7 +1395,7 @@ namespace MediaBrowser.Controller.Entities
             return GetImageInfo(type, imageIndex) != null;
         }
 
-        public void SetImagePath(ImageType type, int index, FileSystemInfo file)
+        public void SetImagePath(ImageType type, int index, FileSystemMetadata file)
         {
             if (type == ImageType.Chapter)
             {
@@ -1545,11 +1545,6 @@ namespace MediaBrowser.Controller.Entities
             return ImageInfos.Where(i => i.Type == imageType);
         }
 
-        public bool AddImages(ImageType imageType, IEnumerable<FileInfo> images)
-        {
-            return AddImages(imageType, images.Cast<FileSystemInfo>().ToList());
-        }
-
         /// <summary>
         /// Adds the images.
         /// </summary>
@@ -1557,7 +1552,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="images">The images.</param>
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
         /// <exception cref="System.ArgumentException">Cannot call AddImages with chapter images</exception>
-        public bool AddImages(ImageType imageType, List<FileSystemInfo> images)
+        public bool AddImages(ImageType imageType, List<FileSystemMetadata> images)
         {
             if (imageType == ImageType.Chapter)
             {
@@ -1567,7 +1562,7 @@ namespace MediaBrowser.Controller.Entities
             var existingImages = GetImages(imageType)
                 .ToList();
 
-            var newImageList = new List<FileSystemInfo>();
+            var newImageList = new List<FileSystemMetadata>();
             var imageAdded = false;
 
             foreach (var newImage in images)
@@ -1607,7 +1602,7 @@ namespace MediaBrowser.Controller.Entities
             return newImageList.Count > 0;
         }
 
-        private ItemImageInfo GetImageInfo(FileSystemInfo file, ImageType type)
+        private ItemImageInfo GetImageInfo(FileSystemMetadata file, ImageType type)
         {
             return new ItemImageInfo
             {
@@ -1730,7 +1725,7 @@ namespace MediaBrowser.Controller.Entities
             {
                 foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
                 {
-                    path = FileSystem.SubstitutePath(path, map.From, map.To);
+                    path = LibraryManager.SubstitutePath(path, map.From, map.To);
                 }
             }
 
@@ -1771,7 +1766,7 @@ namespace MediaBrowser.Controller.Entities
 
             if (video == null)
             {
-                video = LibraryManager.ResolvePath(new FileInfo(path)) as Video;
+                video = LibraryManager.ResolvePath(FileSystem.GetFileSystemInfo(path)) as Video;
 
                 newOptions.ForceSave = true;
             }

+ 4 - 3
MediaBrowser.Controller/Entities/CollectionFolder.cs

@@ -8,6 +8,7 @@ using System.Linq;
 using System.Runtime.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Controller.Entities
 {
@@ -80,7 +81,7 @@ namespace MediaBrowser.Controller.Entities
 
         public List<string> PhysicalLocationsList { get; set; }
 
-        protected override IEnumerable<FileSystemInfo> GetFileSystemChildren(IDirectoryService directoryService)
+        protected override IEnumerable<FileSystemMetadata> GetFileSystemChildren(IDirectoryService directoryService)
         {
             return CreateResolveArgs(directoryService).FileSystemChildren;
         }
@@ -107,7 +108,7 @@ namespace MediaBrowser.Controller.Entities
 
             var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
             {
-                FileInfo = new DirectoryInfo(path),
+                FileInfo = FileSystem.GetDirectoryInfo(path),
                 Path = path,
                 Parent = Parent,
                 CollectionType = CollectionType
@@ -129,7 +130,7 @@ namespace MediaBrowser.Controller.Entities
                 {
                     var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Keys);
 
-                    fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName);
+                    fileSystemDictionary = paths.Select(FileSystem.GetDirectoryInfo).ToDictionary(i => i.FullName);
                 }
 
                 args.FileSystemDictionary = fileSystemDictionary;

+ 3 - 2
MediaBrowser.Controller/Entities/Folder.cs

@@ -13,6 +13,7 @@ using System.Linq;
 using System.Runtime.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Controller.Entities
 {
@@ -1070,7 +1071,7 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+        protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var changesFound = false;
 
@@ -1091,7 +1092,7 @@ namespace MediaBrowser.Controller.Entities
         /// Refreshes the linked children.
         /// </summary>
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
-        private bool RefreshLinkedChildren(IEnumerable<FileSystemInfo> fileSystemChildren)
+        private bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
         {
             var currentManualLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Manual).ToList();
             var currentShortcutLinks = LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut).ToList();

+ 5 - 4
MediaBrowser.Controller/Entities/IHasImages.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Model.Entities;
 using System.Collections.Generic;
 using System.IO;
 using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Controller.Entities
 {
@@ -67,7 +68,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="type">The type.</param>
         /// <param name="index">The index.</param>
         /// <param name="file">The file.</param>
-        void SetImagePath(ImageType type, int index, FileSystemInfo file);
+        void SetImagePath(ImageType type, int index, FileSystemMetadata file);
 
         /// <summary>
         /// Determines whether the specified type has image.
@@ -134,7 +135,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="imageType">Type of the image.</param>
         /// <param name="images">The images.</param>
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
-        bool AddImages(ImageType imageType, List<FileSystemInfo> images);
+        bool AddImages(ImageType imageType, List<FileSystemMetadata> images);
 
         /// <summary>
         /// Determines whether [is save local metadata enabled].
@@ -215,7 +216,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="item">The item.</param>
         /// <param name="imageType">Type of the image.</param>
         /// <param name="file">The file.</param>
-        public static void SetImagePath(this IHasImages item, ImageType imageType, FileSystemInfo file)
+        public static void SetImagePath(this IHasImages item, ImageType imageType, FileSystemMetadata file)
         {
             item.SetImagePath(imageType, 0, file);
         }
@@ -228,7 +229,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="file">The file.</param>
         public static void SetImagePath(this IHasImages item, ImageType imageType, string file)
         {
-            item.SetImagePath(imageType, new FileInfo(file));
+            item.SetImagePath(imageType, BaseItem.FileSystem.GetFileInfo(file));
         }
     }
 }

+ 3 - 2
MediaBrowser.Controller/Entities/Movies/Movie.cs

@@ -8,6 +8,7 @@ using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Controller.Entities.Movies
 {
@@ -122,7 +123,7 @@ namespace MediaBrowser.Controller.Entities.Movies
             return key;
         }
 
-        protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+        protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
 
@@ -141,7 +142,7 @@ namespace MediaBrowser.Controller.Entities.Movies
             return hasChanges;
         }
 
-        private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+        private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var newItems = LibraryManager.FindExtras(this, fileSystemChildren, options.DirectoryService).ToList();
             var newItemIds = newItems.Select(i => i.Id).ToList();

+ 2 - 1
MediaBrowser.Controller/Entities/Video.cs

@@ -11,6 +11,7 @@ using System.Linq;
 using System.Runtime.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Controller.Entities
 {
@@ -343,7 +344,7 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
+        protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
             var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
 

+ 3 - 3
MediaBrowser.Controller/IO/FileData.cs

@@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.IO
         /// <param name="resolveShortcuts">if set to <c>true</c> [resolve shortcuts].</param>
         /// <returns>Dictionary{System.StringFileSystemInfo}.</returns>
         /// <exception cref="System.ArgumentNullException">path</exception>
-        public static Dictionary<string, FileSystemInfo> GetFilteredFileSystemEntries(IDirectoryService directoryService, 
+        public static Dictionary<string, FileSystemMetadata> GetFilteredFileSystemEntries(IDirectoryService directoryService, 
             string path, 
             IFileSystem fileSystem, 
             ILogger logger, 
@@ -49,7 +49,7 @@ namespace MediaBrowser.Controller.IO
 
             var entries = directoryService.GetFileSystemEntries(path);
 
-            var dict = new Dictionary<string, FileSystemInfo>(StringComparer.OrdinalIgnoreCase);
+            var dict = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
 
             foreach (var entry in entries)
             {
@@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.IO
                     }
 
                     // Don't check if it exists here because that could return false for network shares.
-                    var data = new DirectoryInfo(newPath);
+                    var data = fileSystem.GetDirectoryInfo(newPath);
 
                     // add to our physical locations
                     args.AddAdditionalLocation(newPath);

+ 14 - 5
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -11,6 +11,7 @@ using System.Collections.Generic;
 using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Controller.Library
 {
@@ -25,19 +26,18 @@ namespace MediaBrowser.Controller.Library
         /// <param name="fileInfo">The file information.</param>
         /// <param name="parent">The parent.</param>
         /// <returns>BaseItem.</returns>
-        BaseItem ResolvePath(FileSystemInfo fileInfo, 
+        BaseItem ResolvePath(FileSystemMetadata fileInfo, 
             Folder parent = null);
 
         /// <summary>
         /// Resolves a set of files into a list of BaseItem
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="files">The files.</param>
         /// <param name="directoryService">The directory service.</param>
         /// <param name="parent">The parent.</param>
         /// <param name="collectionType">Type of the collection.</param>
         /// <returns>List{``0}.</returns>
-        IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemInfo> files, 
+        IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, 
             IDirectoryService directoryService,
             Folder parent, string 
             collectionType = null);
@@ -434,7 +434,7 @@ namespace MediaBrowser.Controller.Library
         /// <param name="fileSystemChildren">The file system children.</param>
         /// <param name="directoryService">The directory service.</param>
         /// <returns>IEnumerable&lt;Trailer&gt;.</returns>
-        IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemInfo> fileSystemChildren,
+        IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren,
             IDirectoryService directoryService);
 
         /// <summary>
@@ -444,7 +444,7 @@ namespace MediaBrowser.Controller.Library
         /// <param name="fileSystemChildren">The file system children.</param>
         /// <param name="directoryService">The directory service.</param>
         /// <returns>IEnumerable&lt;Video&gt;.</returns>
-        IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren,
+        IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren,
             IDirectoryService directoryService);
 
         /// <summary>
@@ -509,5 +509,14 @@ namespace MediaBrowser.Controller.Library
         /// <param name="query">The query.</param>
         /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
         QueryResult<BaseItem> QueryItems(InternalItemsQuery query);
+
+        /// <summary>
+        /// Substitutes the path.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="from">From.</param>
+        /// <param name="to">To.</param>
+        /// <returns>System.String.</returns>
+        string SubstitutePath(string path, string from, string to);
     }
 }

+ 8 - 7
MediaBrowser.Controller/Library/ItemResolveArgs.cs

@@ -4,6 +4,7 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Controller.Library
 {
@@ -35,7 +36,7 @@ namespace MediaBrowser.Controller.Library
         /// Gets the file system children.
         /// </summary>
         /// <value>The file system children.</value>
-        public IEnumerable<FileSystemInfo> FileSystemChildren
+        public IEnumerable<FileSystemMetadata> FileSystemChildren
         {
             get
             {
@@ -43,7 +44,7 @@ namespace MediaBrowser.Controller.Library
 
                 if (dict == null)
                 {
-                    return new List<FileSystemInfo>();
+                    return new List<FileSystemMetadata>();
                 }
 
                 return dict.Values;
@@ -54,7 +55,7 @@ namespace MediaBrowser.Controller.Library
         /// Gets or sets the file system dictionary.
         /// </summary>
         /// <value>The file system dictionary.</value>
-        public Dictionary<string, FileSystemInfo> FileSystemDictionary { get; set; }
+        public Dictionary<string, FileSystemMetadata> FileSystemDictionary { get; set; }
 
         /// <summary>
         /// Gets or sets the parent.
@@ -66,7 +67,7 @@ namespace MediaBrowser.Controller.Library
         /// Gets or sets the file info.
         /// </summary>
         /// <value>The file info.</value>
-        public FileSystemInfo FileInfo { get; set; }
+        public FileSystemMetadata FileInfo { get; set; }
 
         /// <summary>
         /// Gets or sets the path.
@@ -201,7 +202,7 @@ namespace MediaBrowser.Controller.Library
         /// <param name="name">The name.</param>
         /// <returns>FileSystemInfo.</returns>
         /// <exception cref="System.ArgumentNullException"></exception>
-        public FileSystemInfo GetFileSystemEntryByName(string name)
+        public FileSystemMetadata GetFileSystemEntryByName(string name)
         {
             if (string.IsNullOrEmpty(name))
             {
@@ -217,7 +218,7 @@ namespace MediaBrowser.Controller.Library
         /// <param name="path">The path.</param>
         /// <returns>FileSystemInfo.</returns>
         /// <exception cref="System.ArgumentNullException"></exception>
-        public FileSystemInfo GetFileSystemEntryByPath(string path)
+        public FileSystemMetadata GetFileSystemEntryByPath(string path)
         {
             if (string.IsNullOrEmpty(path))
             {
@@ -226,7 +227,7 @@ namespace MediaBrowser.Controller.Library
 
             if (FileSystemDictionary != null)
             {
-                FileSystemInfo entry;
+                FileSystemMetadata entry;
 
                 if (FileSystemDictionary.TryGetValue(path, out entry))
                 {

+ 14 - 14
MediaBrowser.Controller/Providers/DirectoryService.cs

@@ -13,8 +13,8 @@ namespace MediaBrowser.Controller.Providers
         private readonly ILogger _logger;
 		private readonly IFileSystem _fileSystem;
 
-        private readonly ConcurrentDictionary<string, Dictionary<string,FileSystemInfo>> _cache =
-            new ConcurrentDictionary<string, Dictionary<string, FileSystemInfo>>(StringComparer.OrdinalIgnoreCase);
+        private readonly ConcurrentDictionary<string, Dictionary<string, FileSystemMetadata>> _cache =
+            new ConcurrentDictionary<string, Dictionary<string, FileSystemMetadata>>(StringComparer.OrdinalIgnoreCase);
 
 		public DirectoryService(ILogger logger, IFileSystem fileSystem)
         {
@@ -27,28 +27,28 @@ namespace MediaBrowser.Controller.Providers
         {
         }
 
-        public IEnumerable<FileSystemInfo> GetFileSystemEntries(string path)
+        public IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path)
         {
             return GetFileSystemEntries(path, false);
         }
 
-        public Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path)
+        public Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(string path)
         {
             return GetFileSystemDictionary(path, false);
         }
 
-        private Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path, bool clearCache)
+        private Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(string path, bool clearCache)
         {
             if (string.IsNullOrWhiteSpace(path))
             {
                 throw new ArgumentNullException("path");
             }
 
-            Dictionary<string, FileSystemInfo> entries;
+            Dictionary<string, FileSystemMetadata> entries;
 
             if (clearCache)
             {
-                Dictionary<string, FileSystemInfo> removed;
+                Dictionary<string, FileSystemMetadata> removed;
 
                 _cache.TryRemove(path, out removed);
             }
@@ -57,7 +57,7 @@ namespace MediaBrowser.Controller.Providers
             {
                 //_logger.Debug("Getting files for " + path);
 
-                entries = new Dictionary<string, FileSystemInfo>(StringComparer.OrdinalIgnoreCase);
+                entries = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
                 
                 try
                 {
@@ -82,34 +82,34 @@ namespace MediaBrowser.Controller.Providers
             return entries;
         }
 
-        private IEnumerable<FileSystemInfo> GetFileSystemEntries(string path, bool clearCache)
+        private IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool clearCache)
         {
             return GetFileSystemDictionary(path, clearCache).Values;
         }
 
-        public IEnumerable<FileSystemInfo> GetFiles(string path)
+        public IEnumerable<FileSystemMetadata> GetFiles(string path)
         {
             return GetFiles(path, false);
         }
 
-        public IEnumerable<FileSystemInfo> GetFiles(string path, bool clearCache)
+        public IEnumerable<FileSystemMetadata> GetFiles(string path, bool clearCache)
         {
             return GetFileSystemEntries(path, clearCache).Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory);
         }
 
-        public FileSystemInfo GetFile(string path)
+        public FileSystemMetadata GetFile(string path)
         {
             var directory = Path.GetDirectoryName(path);
 
             var dict = GetFileSystemDictionary(directory, false);
 
-            FileSystemInfo entry;
+            FileSystemMetadata entry;
             dict.TryGetValue(path, out entry);
 
             return entry;
         }
 
-        public IEnumerable<FileSystemInfo> GetDirectories(string path)
+        public IEnumerable<FileSystemMetadata> GetDirectories(string path)
         {
             return GetFileSystemEntries(path, false).Where(i => (i.Attributes & FileAttributes.Directory) == FileAttributes.Directory);
         }

+ 7 - 6
MediaBrowser.Controller/Providers/IDirectoryService.cs

@@ -1,15 +1,16 @@
 using System.Collections.Generic;
 using System.IO;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Controller.Providers
 {
     public interface IDirectoryService
     {
-        IEnumerable<FileSystemInfo> GetFileSystemEntries(string path);
-        IEnumerable<FileSystemInfo> GetFiles(string path);
-        IEnumerable<FileSystemInfo> GetDirectories(string path);
-        IEnumerable<FileSystemInfo> GetFiles(string path, bool clearCache);
-        FileSystemInfo GetFile(string path);
-        Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path);
+        IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path);
+        IEnumerable<FileSystemMetadata> GetFiles(string path);
+        IEnumerable<FileSystemMetadata> GetDirectories(string path);
+        IEnumerable<FileSystemMetadata> GetFiles(string path, bool clearCache);
+        FileSystemMetadata GetFile(string path);
+        Dictionary<string, FileSystemMetadata> GetFileSystemDictionary(string path);
     }
 }

+ 2 - 1
MediaBrowser.Controller/Providers/LocalImageInfo.cs

@@ -1,11 +1,12 @@
 using System.IO;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Controller.Providers
 {
     public class LocalImageInfo
     {
-        public FileSystemInfo FileInfo { get; set; }
+        public FileSystemMetadata FileInfo { get; set; }
         public ImageType Type { get; set; }
     }
 }

+ 5 - 4
MediaBrowser.Controller/Resolvers/IItemResolver.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using System.Collections.Generic;
 using System.IO;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Controller.Resolvers
 {
@@ -26,8 +27,8 @@ namespace MediaBrowser.Controller.Resolvers
 
     public interface IMultiItemResolver
     {
-        MultiItemResolverResult ResolveMultiple(Folder parent, 
-            List<FileSystemInfo> files, 
+        MultiItemResolverResult ResolveMultiple(Folder parent,
+            List<FileSystemMetadata> files, 
             string collectionType,
             IDirectoryService directoryService);
     }
@@ -35,12 +36,12 @@ namespace MediaBrowser.Controller.Resolvers
     public class MultiItemResolverResult
     {
         public List<BaseItem> Items { get; set; }
-        public List<FileSystemInfo> ExtraFiles { get; set; }
+        public List<FileSystemMetadata> ExtraFiles { get; set; }
 
         public MultiItemResolverResult()
         {
             Items = new List<BaseItem>();
-            ExtraFiles = new List<FileSystemInfo>();
+            ExtraFiles = new List<FileSystemMetadata>();
         }
     }
 }

+ 1 - 1
MediaBrowser.LocalMetadata/BaseXmlProvider.cs

@@ -54,7 +54,7 @@ namespace MediaBrowser.LocalMetadata
             FileSystem = fileSystem;
         }
 
-        protected abstract FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService);
+        protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
 
         public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
         {

+ 2 - 2
MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs

@@ -60,7 +60,7 @@ namespace MediaBrowser.LocalMetadata.Images
             return new List<LocalImageInfo>();
         }
 
-        private List<LocalImageInfo> GetFilesFromParentFolder(string filenameWithoutExtension, IEnumerable<FileSystemInfo> parentPathFiles)
+        private List<LocalImageInfo> GetFilesFromParentFolder(string filenameWithoutExtension, IEnumerable<FileSystemMetadata> parentPathFiles)
         {
             var thumbName = filenameWithoutExtension + "-thumb";
 
@@ -91,7 +91,7 @@ namespace MediaBrowser.LocalMetadata.Images
               })
               .Select(i => new LocalImageInfo
               {
-                  FileInfo = (FileInfo)i,
+                  FileInfo = i,
                   Type = ImageType.Primary
               })
               .ToList();

+ 13 - 13
MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs

@@ -62,11 +62,11 @@ namespace MediaBrowser.LocalMetadata.Images
             return false;
         }
 
-        private IEnumerable<FileSystemInfo> GetFiles(IHasImages item, bool includeDirectories, IDirectoryService directoryService)
+        private IEnumerable<FileSystemMetadata> GetFiles(IHasImages item, bool includeDirectories, IDirectoryService directoryService)
         {
             if (item.LocationType != LocationType.FileSystem)
             {
-                return new List<FileSystemInfo>();
+                return new List<FileSystemMetadata>();
             }
 
             var path = item.ContainingFolderPath;
@@ -127,7 +127,7 @@ namespace MediaBrowser.LocalMetadata.Images
             return list;
         }
 
-        private void PopulateImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemInfo> files, bool supportParentSeriesFiles, IDirectoryService directoryService)
+        private void PopulateImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemMetadata> files, bool supportParentSeriesFiles, IDirectoryService directoryService)
         {
             var imagePrefix = item.FileNameWithoutExtension + "-";
             var isInMixedFolder = item.IsInMixedFolder;
@@ -164,7 +164,7 @@ namespace MediaBrowser.LocalMetadata.Images
             }
         }
 
-        private void PopulatePrimaryImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemInfo> files, string imagePrefix, bool isInMixedFolder)
+        private void PopulatePrimaryImages(IHasImages item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
         {
             var names = new List<string>
             {
@@ -206,7 +206,7 @@ namespace MediaBrowser.LocalMetadata.Images
             }
         }
 
-        private void PopulateBackdrops(IHasImages item, List<LocalImageInfo> images, List<FileSystemInfo> files, string imagePrefix, bool isInMixedFolder, IDirectoryService directoryService)
+        private void PopulateBackdrops(IHasImages item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder, IDirectoryService directoryService)
         {
             PopulateBackdrops(images, files, imagePrefix, "backdrop", "backdrop", isInMixedFolder, ImageType.Backdrop);
 
@@ -261,12 +261,12 @@ namespace MediaBrowser.LocalMetadata.Images
             }));
         }
 
-        private void PopulateScreenshots(List<LocalImageInfo> images, List<FileSystemInfo> files, string imagePrefix, bool isInMixedFolder)
+        private void PopulateScreenshots(List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
         {
             PopulateBackdrops(images, files, imagePrefix, "screenshot", "screenshot", isInMixedFolder, ImageType.Screenshot);
         }
 
-        private void PopulateBackdrops(List<LocalImageInfo> images, List<FileSystemInfo> files, string imagePrefix, string firstFileName, string subsequentFileNamePrefix, bool isInMixedFolder, ImageType type)
+        private void PopulateBackdrops(List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, string firstFileName, string subsequentFileNamePrefix, bool isInMixedFolder, ImageType type)
         {
             AddImage(files, images, imagePrefix + firstFileName, type);
 
@@ -349,7 +349,7 @@ namespace MediaBrowser.LocalMetadata.Images
             }
         }
 
-        private bool AddImage(List<FileSystemInfo> files, List<LocalImageInfo> images, string name, string imagePrefix, bool isInMixedFolder, ImageType type)
+        private bool AddImage(List<FileSystemMetadata> files, List<LocalImageInfo> images, string name, string imagePrefix, bool isInMixedFolder, ImageType type)
         {
             var added = AddImage(files, images, imagePrefix + name, type);
 
@@ -364,9 +364,9 @@ namespace MediaBrowser.LocalMetadata.Images
             return added;
         }
 
-        private bool AddImage(IEnumerable<FileSystemInfo> files, List<LocalImageInfo> images, string name, ImageType type)
+        private bool AddImage(IEnumerable<FileSystemMetadata> files, List<LocalImageInfo> images, string name, ImageType type)
         {
-            var image = GetImage(files, name) as FileInfo;
+            var image = GetImage(files, name);
 
             if (image != null)
             {
@@ -382,7 +382,7 @@ namespace MediaBrowser.LocalMetadata.Images
             return false;
         }
 
-        private void AddCacheKeyImage(IEnumerable<FileSystemInfo> files, List<LocalImageInfo> images, ImageType type)
+        private void AddCacheKeyImage(IEnumerable<FileSystemMetadata> files, List<LocalImageInfo> images, ImageType type)
         {
             var candidates = files
                 .Where(i => _fileSystem.GetFileNameWithoutExtension(i).StartsWith(type.ToString() + "_key_", StringComparison.OrdinalIgnoreCase))
@@ -390,7 +390,7 @@ namespace MediaBrowser.LocalMetadata.Images
 
             var image = BaseItem.SupportedImageExtensions
                 .Select(i => candidates.FirstOrDefault(c => string.Equals(c.Extension, i, StringComparison.OrdinalIgnoreCase)))
-                .FirstOrDefault(i => i != null) as FileInfo;
+                .FirstOrDefault(i => i != null);
 
             if (image != null)
             {
@@ -402,7 +402,7 @@ namespace MediaBrowser.LocalMetadata.Images
             }
         }
 
-        private FileSystemInfo GetImage(IEnumerable<FileSystemInfo> files, string name)
+        private FileSystemMetadata GetImage(IEnumerable<FileSystemMetadata> files, string name)
         {
             return files.FirstOrDefault(i => ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) && string.Equals(name, _fileSystem.GetFileNameWithoutExtension(i), StringComparison.OrdinalIgnoreCase));
         }

+ 5 - 2
MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs

@@ -8,6 +8,7 @@ using System.Globalization;
 using System.IO;
 using System.Threading;
 using System.Xml;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.LocalMetadata.Parsers
 {
@@ -17,10 +18,12 @@ namespace MediaBrowser.LocalMetadata.Parsers
     public class EpisodeXmlParser : BaseItemXmlParser<Episode>
     {
         private List<LocalImageInfo> _imagesFound;
+        private readonly IFileSystem _fileSystem;
 
-        public EpisodeXmlParser(ILogger logger)
+        public EpisodeXmlParser(ILogger logger, IFileSystem fileSystem)
             : base(logger)
         {
+            _fileSystem = fileSystem;
         }
 
         private string _xmlPath;
@@ -80,7 +83,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
 
                             var parentFolder = Path.GetDirectoryName(_xmlPath);
                             filename = Path.Combine(parentFolder, filename);
-                            var file = new FileInfo(filename);
+                            var file = _fileSystem.GetFileInfo(filename);
 
                             if (file.Exists)
                             {

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs

@@ -26,7 +26,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             new BoxSetXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "collection.xml"));
         }

+ 2 - 2
MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs

@@ -25,12 +25,12 @@ namespace MediaBrowser.LocalMetadata.Providers
             var images = new List<LocalImageInfo>();
             var chapters = new List<ChapterInfo>();
 
-            new EpisodeXmlParser(_logger).Fetch(result, images, path, cancellationToken);
+            new EpisodeXmlParser(_logger, FileSystem).Fetch(result, images, path, cancellationToken);
 
             result.Images = images;
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             var metadataPath = Path.GetDirectoryName(info.Path);
             metadataPath = Path.Combine(metadataPath, "metadata");

+ 2 - 2
MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs

@@ -25,9 +25,9 @@ namespace MediaBrowser.LocalMetadata.Providers
             new BaseItemXmlParser<Folder>(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
-            return new FileInfo(Path.Combine(info.Path, "folder.xml"));
+            return directoryService.GetFile(Path.Combine(info.Path, "folder.xml"));
         }
     }
 }

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs

@@ -23,7 +23,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             new GameSystemXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "gamesystem.xml"));
         }

+ 3 - 3
MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs

@@ -23,12 +23,12 @@ namespace MediaBrowser.LocalMetadata.Providers
             new GameXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             var specificFile = Path.ChangeExtension(info.Path, ".xml");
-            var file = new FileInfo(specificFile);
+            var file = FileSystem.GetFileInfo(specificFile);
 
-            return info.IsInMixedFolder || file.Exists ? file : new FileInfo(Path.Combine(Path.GetDirectoryName(info.Path), "game.xml"));
+            return info.IsInMixedFolder || file.Exists ? file : FileSystem.GetFileInfo(Path.Combine(Path.GetDirectoryName(info.Path), "game.xml"));
         }
     }
 }

+ 5 - 10
MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs

@@ -23,27 +23,22 @@ namespace MediaBrowser.LocalMetadata.Providers
             new MovieXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return GetXmlFileInfo(info, FileSystem);
         }
 
-        public static FileInfo GetXmlFileInfo(ItemInfo info, IFileSystem fileSystem)
+        public static FileSystemMetadata GetXmlFileInfo(ItemInfo info, IFileSystem fileSystem)
         {
             var fileInfo = fileSystem.GetFileSystemInfo(info.Path);
 
-            var directoryInfo = fileInfo as DirectoryInfo;
-
-            if (directoryInfo == null)
-            {
-                directoryInfo = new DirectoryInfo(Path.GetDirectoryName(info.Path));
-            }
+            var directoryInfo = fileInfo.IsDirectory ? fileInfo : fileSystem.GetDirectoryInfo(Path.GetDirectoryName(info.Path));
 
             var directoryPath = directoryInfo.FullName;
 
             var specificFile = Path.Combine(directoryPath, fileSystem.GetFileNameWithoutExtension(info.Path) + ".xml");
 
-            var file = new FileInfo(specificFile);
+            var file = fileSystem.GetFileInfo(specificFile);
 
             // In a mixed folder, only {moviename}.xml is supported
             if (info.IsInMixedFolder)
@@ -52,7 +47,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             }
 
             // If in it's own folder, prefer movie.xml, but allow the specific file as well
-            var movieFile = new FileInfo(Path.Combine(directoryPath, "movie.xml"));
+            var movieFile = fileSystem.GetFileInfo(Path.Combine(directoryPath, "movie.xml"));
 
             return movieFile.Exists ? movieFile : file;
         }

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs

@@ -23,7 +23,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             new MusicVideoXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return MovieXmlProvider.GetXmlFileInfo(info, FileSystem);
         }

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs

@@ -22,7 +22,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             new BaseItemXmlParser<Person>(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "person.xml"));
         }

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs

@@ -23,7 +23,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             new PlaylistXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "playlist.xml"));
         }

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/SeasonXmlProvider.cs

@@ -26,7 +26,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             new SeasonXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "season.xml"));
         }

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs

@@ -26,7 +26,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             new SeriesXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "series.xml"));
         }

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs

@@ -23,7 +23,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             new VideoXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return MovieXmlProvider.GetXmlFileInfo(info, FileSystem);
         }

+ 4 - 1
MediaBrowser.Model/Devices/DeviceInfo.cs

@@ -27,7 +27,10 @@ namespace MediaBrowser.Model.Devices
         /// <value>The name.</value>
         public string Name
         {
-            get { return string.IsNullOrEmpty(CustomName) ? ReportedName : CustomName; }
+            get
+            {
+                return string.IsNullOrEmpty(CustomName) ? ReportedName : CustomName;
+            }
         }
 
         /// <summary>

+ 1 - 1
MediaBrowser.Providers/ImagesByName/ImageUtils.cs

@@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.ImagesByName
         /// <returns>Task.</returns>
         public static async Task EnsureList(string url, string file, IHttpClient httpClient, IFileSystem fileSystem, SemaphoreSlim semaphore, CancellationToken cancellationToken)
         {
-            var fileInfo = new FileInfo(file);
+            var fileInfo = fileSystem.GetFileInfo(file);
 
             if (!fileInfo.Exists || (DateTime.UtcNow - fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays > 1)
             {

+ 1 - 1
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -291,7 +291,7 @@ namespace MediaBrowser.Providers.Manager
         /// imageIndex</exception>
         private void SetImagePath(IHasImages item, ImageType type, int? imageIndex, string path)
         {
-            item.SetImagePath(type, imageIndex ?? 0, new FileInfo(path));
+            item.SetImagePath(type, imageIndex ?? 0, _fileSystem.GetFileInfo(path));
         }
 
         /// <summary>

+ 1 - 1
MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs

@@ -99,7 +99,7 @@ namespace MediaBrowser.Providers.MediaInfo
             }
         }
 
-        public static IEnumerable<FileSystemInfo> GetSubtitleFiles(Video video, IDirectoryService directoryService, IFileSystem fileSystem, bool clearCache)
+        public static IEnumerable<FileSystemMetadata> GetSubtitleFiles(Video video, IDirectoryService directoryService, IFileSystem fileSystem, bool clearCache)
         {
             var containingPath = video.ContainingFolderPath;
 

+ 1 - 1
MediaBrowser.Providers/Movies/FanArtMovieUpdatesPostScanTask.cs

@@ -70,7 +70,7 @@ namespace MediaBrowser.Providers.Movies
             
             var timestampFile = Path.Combine(path, "time.txt");
 
-            var timestampFileInfo = new FileInfo(timestampFile);
+            var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
 
             // Don't check for updates every single time
             if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3)

+ 1 - 1
MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs

@@ -234,7 +234,7 @@ namespace MediaBrowser.Providers.Movies
                 // Process images
                 var path = GetFanartJsonPath(id);
 
-                var fileInfo = new FileInfo(path);
+                var fileInfo = _fileSystem.GetFileInfo(path);
 
                 return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
             }

+ 1 - 1
MediaBrowser.Providers/Movies/MovieDbProvider.cs

@@ -381,7 +381,7 @@ namespace MediaBrowser.Providers.Movies
                 // Process images
                 var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage());
 
-                var fileInfo = new FileInfo(dataFilePath);
+                var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
 
                 return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
             }

+ 1 - 1
MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs

@@ -80,7 +80,7 @@ namespace MediaBrowser.Providers.Movies
 
             var timestampFile = Path.Combine(path, "time.txt");
 
-            var timestampFileInfo = new FileInfo(timestampFile);
+            var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
 
             // Don't check for updates every single time
             if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 7)

+ 1 - 1
MediaBrowser.Providers/Music/FanArtAlbumProvider.cs

@@ -375,7 +375,7 @@ namespace MediaBrowser.Providers.Music
                     // Process images
                     var artistXmlPath = FanartArtistProvider.GetArtistXmlPath(_config.CommonApplicationPaths, artistMusicBrainzId);
 
-                    var fileInfo = new FileInfo(artistXmlPath);
+                    var fileInfo = _fileSystem.GetFileInfo(artistXmlPath);
 
                     return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
                 }

+ 1 - 1
MediaBrowser.Providers/Music/FanArtArtistProvider.cs

@@ -387,7 +387,7 @@ namespace MediaBrowser.Providers.Music
                 // Process images
                 var artistXmlPath = GetArtistXmlPath(_config.CommonApplicationPaths, id);
 
-                var fileInfo = new FileInfo(artistXmlPath);
+                var fileInfo = _fileSystem.GetFileInfo(artistXmlPath);
 
                 return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
             }

+ 1 - 1
MediaBrowser.Providers/Music/FanArtUpdatesPostScanTask.cs

@@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.Music
 
             var timestampFile = Path.Combine(path, "time.txt");
 
-            var timestampFileInfo = new FileInfo(timestampFile);
+            var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
 
             // Don't check for updates every single time
             if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3)

+ 1 - 1
MediaBrowser.Providers/TV/FanArtSeasonProvider.cs

@@ -248,7 +248,7 @@ namespace MediaBrowser.Providers.TV
                 // Process images
                 var imagesFilePath = FanartSeriesProvider.Current.GetFanartJsonPath(tvdbId);
 
-                var fileInfo = new FileInfo(imagesFilePath);
+                var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
 
                 return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
             }

+ 1 - 1
MediaBrowser.Providers/TV/FanArtTvUpdatesPostScanTask.cs

@@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.TV
             
             var timestampFile = Path.Combine(path, "time.txt");
 
-            var timestampFileInfo = new FileInfo(timestampFile);
+            var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
 
             // Don't check for updates every single time
             if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3)

+ 1 - 1
MediaBrowser.Providers/TV/FanartSeriesProvider.cs

@@ -356,7 +356,7 @@ namespace MediaBrowser.Providers.TV
                 // Process images
                 var imagesFilePath = GetFanartJsonPath(tvdbId);
 
-                var fileInfo = new FileInfo(imagesFilePath);
+                var fileInfo = _fileSystem.GetFileInfo(imagesFilePath);
 
                 return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
             }

+ 1 - 1
MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs

@@ -412,7 +412,7 @@ namespace MediaBrowser.Providers.TV
                 // Process images
                 var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage());
 
-                var fileInfo = new FileInfo(dataFilePath);
+                var fileInfo = _fileSystem.GetFileInfo(dataFilePath);
 
                 return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
             }

+ 1 - 1
MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs

@@ -75,7 +75,7 @@ namespace MediaBrowser.Providers.TV
             return Task.FromResult<IEnumerable<RemoteImageInfo>>(new RemoteImageInfo[] { });
         }
 
-        private RemoteImageInfo GetImageInfo(FileInfo xmlFile, CancellationToken cancellationToken)
+        private RemoteImageInfo GetImageInfo(FileSystemMetadata xmlFile, CancellationToken cancellationToken)
         {
             var height = 225;
             var width = 400;

+ 5 - 5
MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs

@@ -173,9 +173,9 @@ namespace MediaBrowser.Providers.TV
         /// <param name="endingEpisodeNumber">The ending episode number.</param>
         /// <param name="seriesDataPath">The series data path.</param>
         /// <returns>List{FileInfo}.</returns>
-        internal List<FileInfo> GetEpisodeXmlFiles(int? seasonNumber, int? episodeNumber, int? endingEpisodeNumber, string seriesDataPath)
+        internal List<FileSystemMetadata> GetEpisodeXmlFiles(int? seasonNumber, int? episodeNumber, int? endingEpisodeNumber, string seriesDataPath)
         {
-            var files = new List<FileInfo>();
+            var files = new List<FileSystemMetadata>();
 
             if (episodeNumber == null)
             {
@@ -189,7 +189,7 @@ namespace MediaBrowser.Providers.TV
 
             var file = Path.Combine(seriesDataPath, string.Format("episode-{0}-{1}.xml", seasonNumber.Value, episodeNumber));
 
-            var fileInfo = new FileInfo(file);
+            var fileInfo = _fileSystem.GetFileInfo(file);
             var usingAbsoluteData = false;
 
             if (fileInfo.Exists)
@@ -199,7 +199,7 @@ namespace MediaBrowser.Providers.TV
             else
             {
                 file = Path.Combine(seriesDataPath, string.Format("episode-abs-{0}.xml", episodeNumber));
-                fileInfo = new FileInfo(file);
+                fileInfo = _fileSystem.GetFileInfo(file);
                 if (fileInfo.Exists)
                 {
                     files.Add(fileInfo);
@@ -221,7 +221,7 @@ namespace MediaBrowser.Providers.TV
                     file = Path.Combine(seriesDataPath, string.Format("episode-{0}-{1}.xml", seasonNumber.Value, episodeNumber));
                 }
 
-                fileInfo = new FileInfo(file);
+                fileInfo = _fileSystem.GetFileInfo(file);
                 if (fileInfo.Exists)
                 {
                     files.Add(fileInfo);

+ 1 - 1
MediaBrowser.Providers/TV/TvdbPrescanTask.cs

@@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.TV
 
             var timestampFile = Path.Combine(path, "time.txt");
 
-            var timestampFileInfo = new FileInfo(timestampFile);
+            var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);
 
             // Don't check for tvdb updates anymore frequently than 24 hours
             if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)

+ 1 - 1
MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs

@@ -380,7 +380,7 @@ namespace MediaBrowser.Providers.TV
                 // Process images
                 var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, tvdbId), "banners.xml");
 
-                var fileInfo = new FileInfo(imagesXmlPath);
+                var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);
 
                 return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
             }

+ 1 - 1
MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs

@@ -352,7 +352,7 @@ namespace MediaBrowser.Providers.TV
                 // Process images
                 var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, tvdbId), "banners.xml");
 
-                var fileInfo = new FileInfo(imagesXmlPath);
+                var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);
 
                 return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > (status.DateLastMetadataRefresh ?? DateTime.MinValue);
             }

+ 4 - 7
MediaBrowser.Server.Implementations/Channels/ChannelManager.cs

@@ -388,18 +388,15 @@ namespace MediaBrowser.Server.Implementations.Channels
 
             var path = Channel.GetInternalMetadataPath(_config.ApplicationPaths.InternalMetadataPath, id);
 
-            var fileInfo = new DirectoryInfo(path);
-
             var isNew = false;
 
-            if (!fileInfo.Exists)
+            if (!_fileSystem.DirectoryExists(path))
             {
                 _logger.Debug("Creating directory {0}", path);
 
                 _fileSystem.CreateDirectory(path);
-                fileInfo = new DirectoryInfo(path);
 
-                if (!fileInfo.Exists)
+                if (!_fileSystem.DirectoryExists(path))
                 {
                     throw new IOException("Path not created: " + path);
                 }
@@ -415,8 +412,8 @@ namespace MediaBrowser.Server.Implementations.Channels
                 {
                     Name = channelInfo.Name,
                     Id = id,
-                    DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo),
-                    DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo),
+                    DateCreated = _fileSystem.GetCreationTimeUtc(path),
+                    DateModified = _fileSystem.GetLastWriteTimeUtc(path),
                     Path = path,
                     ChannelId = channelInfo.Name.GetMD5().ToString("N")
                 };

+ 1 - 1
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -1577,7 +1577,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             {
                 foreach (var map in _config.Configuration.PathSubstitutions)
                 {
-                    path = _fileSystem.SubstitutePath(path, map.From, map.To);
+                    path = _libraryManager.SubstitutePath(path, map.From, map.To);
                 }
             }
 

+ 8 - 9
MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs

@@ -35,12 +35,13 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             _providerManager = providerManager;
         }
 
-        private bool FilterValidVideoFile(FileInfo fileInfo)
+        private bool EnableOrganization(FileSystemMetadata fileInfo, TvFileOrganizationOptions options)
         {
+            var minFileBytes = options.MinFileSizeMb * 1024 * 1024;
+
             try
             {
-                var fullName = fileInfo.FullName;
-                return _libraryManager.IsVideoFile(fileInfo.FullName);
+                return _libraryManager.IsVideoFile(fileInfo.FullName) && fileInfo.Length >= minFileBytes;
             }
             catch (Exception ex)
             {
@@ -50,15 +51,13 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             return false;
         }
 
-        public async Task Organize(AutoOrganizeOptions options, CancellationToken cancellationToken, IProgress<double> progress)
+        public async Task Organize(TvFileOrganizationOptions options, CancellationToken cancellationToken, IProgress<double> progress)
         {
-            var minFileBytes = options.MinFileSizeMb * 1024 * 1024;
-
             var watchLocations = options.WatchLocations.ToList();
 
             var eligibleFiles = watchLocations.SelectMany(GetFilesToOrganize)
                 .OrderBy(_fileSystem.GetCreationTimeUtc)
-                .Where(i => FilterValidVideoFile(i) && i.Length >= minFileBytes)
+                .Where(i => EnableOrganization(i, options))
                 .ToList();
 
             var processedFolders = new HashSet<string>();
@@ -128,7 +127,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
         /// </summary>
         /// <param name="path">The path.</param>
         /// <returns>IEnumerable{FileInfo}.</returns>
-        private IEnumerable<FileInfo> GetFilesToOrganize(string path)
+        private IEnumerable<FileSystemMetadata> GetFilesToOrganize(string path)
         {
             try
             {
@@ -139,7 +138,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             {
                 _logger.ErrorException("Error getting files from {0}", ex, path);
 
-                return new List<FileInfo>();
+                return new List<FileSystemMetadata>();
             }
         }
 

+ 3 - 2
MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs

@@ -114,12 +114,12 @@ namespace MediaBrowser.Server.Implementations.IO
         private IServerConfigurationManager ConfigurationManager { get; set; }
 
         private readonly IFileSystem _fileSystem;
-        private IServerApplicationHost _appHost;
+        private readonly IServerApplicationHost _appHost;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
         /// </summary>
-        public LibraryMonitor(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
+        public LibraryMonitor(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IServerApplicationHost appHost)
         {
             if (taskManager == null)
             {
@@ -131,6 +131,7 @@ namespace MediaBrowser.Server.Implementations.IO
             Logger = logManager.GetLogger(GetType().Name);
             ConfigurationManager = configurationManager;
             _fileSystem = fileSystem;
+            _appHost = appHost;
 
             SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
         }

+ 50 - 16
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -34,6 +34,7 @@ using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Extensions;
 using MoreLinq;
 using SortOrder = MediaBrowser.Model.Entities.SortOrder;
 
@@ -549,13 +550,13 @@ namespace MediaBrowser.Server.Implementations.Library
             return item;
         }
 
-        public BaseItem ResolvePath(FileSystemInfo fileInfo,
+        public BaseItem ResolvePath(FileSystemMetadata fileInfo,
             Folder parent = null)
         {
             return ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), parent);
         }
 
-        private BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null)
+        private BaseItem ResolvePath(FileSystemMetadata fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null)
         {
             if (fileInfo == null)
             {
@@ -599,7 +600,7 @@ namespace MediaBrowser.Server.Implementations.Library
                 {
                     var paths = NormalizeRootPathList(fileSystemDictionary.Keys);
 
-                    fileSystemDictionary = paths.Select(i => (FileSystemInfo)new DirectoryInfo(i)).ToDictionary(i => i.FullName);
+                    fileSystemDictionary = paths.Select(_fileSystem.GetDirectoryInfo).ToDictionary(i => i.FullName);
                 }
 
                 args.FileSystemDictionary = fileSystemDictionary;
@@ -642,7 +643,7 @@ namespace MediaBrowser.Server.Implementations.Library
             return !args.ContainsFileSystemEntryByName(".ignore");
         }
 
-        public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemInfo> files, IDirectoryService directoryService, Folder parent, string collectionType)
+        public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, string collectionType)
         {
             var fileList = files.ToList();
 
@@ -670,7 +671,7 @@ namespace MediaBrowser.Server.Implementations.Library
             return ResolveFileList(fileList, directoryService, parent, collectionType);
         }
 
-        private IEnumerable<BaseItem> ResolveFileList(IEnumerable<FileSystemInfo> fileList, IDirectoryService directoryService, Folder parent, string collectionType)
+        private IEnumerable<BaseItem> ResolveFileList(IEnumerable<FileSystemMetadata> fileList, IDirectoryService directoryService, Folder parent, string collectionType)
         {
             return fileList.Select(f =>
             {
@@ -697,7 +698,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
 			_fileSystem.CreateDirectory(rootFolderPath);
 
-            var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(new DirectoryInfo(rootFolderPath));
+            var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath));
 
             // Add in the plug-in folders
             foreach (var child in PluginFolderCreators)
@@ -752,7 +753,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
                         if (tmpItem == null)
                         {
-                            tmpItem = (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath));
+                            tmpItem = (UserRootFolder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath));
                         }
 
                         _userRootFolder = tmpItem;
@@ -1185,7 +1186,8 @@ namespace MediaBrowser.Server.Implementations.Library
 
         private string GetCollectionType(string path)
         {
-            return new DirectoryInfo(path).EnumerateFiles("*.collection", SearchOption.TopDirectoryOnly)
+            return _fileSystem.GetFiles(path, false)
+                .Where(i => string.Equals(i.Extension, ".collection", StringComparison.OrdinalIgnoreCase))
                 .Select(i => _fileSystem.GetFileNameWithoutExtension(i))
                 .FirstOrDefault();
         }
@@ -2050,11 +2052,11 @@ namespace MediaBrowser.Server.Implementations.Library
             };
         }
 
-        public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
+        public IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
         {
-            var files = fileSystemChildren.OfType<DirectoryInfo>()
+            var files = fileSystemChildren.Where(i => i.IsDirectory)
                 .Where(i => string.Equals(i.Name, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase))
-                .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly))
+                .SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
                 .ToList();
 
             var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
@@ -2070,7 +2072,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
             if (currentVideo != null)
             {
-                files.AddRange(currentVideo.Extras.Where(i => string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => new FileInfo(i.Path)));
+                files.AddRange(currentVideo.Extras.Where(i => string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path)));
             }
 
             return ResolvePaths(files, directoryService, null, null)
@@ -2093,11 +2095,11 @@ namespace MediaBrowser.Server.Implementations.Library
             }).OrderBy(i => i.Path).ToList();
         }
 
-        public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
+        public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
         {
-            var files = fileSystemChildren.OfType<DirectoryInfo>()
+            var files = fileSystemChildren.Where(i => i.IsDirectory)
                 .Where(i => string.Equals(i.Name, "extras", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "specials", StringComparison.OrdinalIgnoreCase))
-                .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly))
+                .SelectMany(i => _fileSystem.GetFiles(i.FullName, false))
                 .ToList();
 
             var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
@@ -2113,7 +2115,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
             if (currentVideo != null)
             {
-                files.AddRange(currentVideo.Extras.Where(i => !string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => new FileInfo(i.Path)));
+                files.AddRange(currentVideo.Extras.Where(i => !string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path)));
             }
 
             return ResolvePaths(files, directoryService, null, null)
@@ -2136,6 +2138,38 @@ namespace MediaBrowser.Server.Implementations.Library
                 }).OrderBy(i => i.Path).ToList();
         }
 
+        public string SubstitutePath(string path, string from, string to)
+        {
+            if (string.IsNullOrWhiteSpace(path))
+            {
+                throw new ArgumentNullException("path");
+            }
+            if (string.IsNullOrWhiteSpace(from))
+            {
+                throw new ArgumentNullException("from");
+            }
+            if (string.IsNullOrWhiteSpace(to))
+            {
+                throw new ArgumentNullException("to");
+            }
+
+            var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase);
+
+            if (!string.Equals(newPath, path))
+            {
+                if (to.IndexOf('/') != -1)
+                {
+                    newPath = newPath.Replace('\\', '/');
+                }
+                else
+                {
+                    newPath = newPath.Replace('/', '\\');
+                }
+            }
+
+            return newPath;
+        }
+
         private void SetExtraTypeFromFilename(Video item)
         {
             var resolver = new ExtraResolver(GetNamingOptions(), new PatternsLogger(), new RegexProvider());

+ 2 - 2
MediaBrowser.Server.Implementations/Library/ResolverHelper.cs

@@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.Library
         /// </summary>
         /// <param name="item">The item.</param>
         /// <param name="fileInfo">The file information.</param>
-        private static void EnsureName(BaseItem item, FileSystemInfo fileInfo)
+        private static void EnsureName(BaseItem item, FileSystemMetadata fileInfo)
         {
             // If the subclass didn't supply a name, add it here
             if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path))
@@ -179,7 +179,7 @@ namespace MediaBrowser.Server.Implementations.Library
             }
         }
 
-        private static void SetDateCreated(BaseItem item, IFileSystem fileSystem, FileSystemInfo info)
+        private static void SetDateCreated(BaseItem item, IFileSystem fileSystem, FileSystemMetadata info)
         {
             var config = BaseItem.ConfigurationManager.GetMetadataConfiguration();
 

+ 1 - 1
MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs

@@ -107,7 +107,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
         /// <param name="fileSystem">The file system.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <returns><c>true</c> if the specified list contains music; otherwise, <c>false</c>.</returns>
-        private bool ContainsMusic(IEnumerable<FileSystemInfo> list,
+        private bool ContainsMusic(IEnumerable<FileSystemMetadata> list,
             bool allowSubfolders,
             IDirectoryService directoryService,
             ILogger logger,

+ 10 - 9
MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs

@@ -13,6 +13,7 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using MediaBrowser.Common.IO;
 
 namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
 {
@@ -43,7 +44,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
         }
 
         public MultiItemResolverResult ResolveMultiple(Folder parent,
-            List<FileSystemInfo> files,
+            List<FileSystemMetadata> files,
             string collectionType,
             IDirectoryService directoryService)
         {
@@ -61,7 +62,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
         }
 
         private MultiItemResolverResult ResolveMultipleInternal(Folder parent,
-            List<FileSystemInfo> files,
+            List<FileSystemMetadata> files,
             string collectionType,
             IDirectoryService directoryService)
         {
@@ -109,12 +110,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
             return null;
         }
 
-        private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool suppportMultiEditions)
+        private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool suppportMultiEditions)
             where T : Video, new()
         {
-            var files = new List<FileSystemInfo>();
+            var files = new List<FileSystemMetadata>();
             var videos = new List<BaseItem>();
-            var leftOver = new List<FileSystemInfo>();
+            var leftOver = new List<FileSystemMetadata>();
 
             // Loop through each child file/folder and see if we find a video
             foreach (var child in fileSystemEntries)
@@ -343,10 +344,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
         /// <param name="directoryService">The directory service.</param>
         /// <param name="collectionType">Type of the collection.</param>
         /// <returns>Movie.</returns>
-        private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType)
+        private T FindMovie<T>(string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType)
             where T : Video, new()
         {
-            var multiDiscFolders = new List<FileSystemInfo>();
+            var multiDiscFolders = new List<FileSystemMetadata>();
 
             // Search for a folder rip
             foreach (var child in fileSystemEntries)
@@ -419,7 +420,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
         /// <param name="multiDiscFolders">The folders.</param>
         /// <param name="directoryService">The directory service.</param>
         /// <returns>``0.</returns>
-        private T GetMultiDiscMovie<T>(List<FileSystemInfo> multiDiscFolders, IDirectoryService directoryService)
+        private T GetMultiDiscMovie<T>(List<FileSystemMetadata> multiDiscFolders, IDirectoryService directoryService)
                where T : Video, new()
         {
             var videoTypes = new List<VideoType>();
@@ -492,7 +493,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
             };
         }
 
-        private bool IsInvalid(Folder parent, string collectionType, IEnumerable<FileSystemInfo> files)
+        private bool IsInvalid(Folder parent, string collectionType, IEnumerable<FileSystemMetadata> files)
         {
             if (parent != null)
             {

+ 1 - 1
MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs

@@ -99,7 +99,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
         }
 
         public static bool IsSeriesFolder(string path,
-            IEnumerable<FileSystemInfo> fileSystemChildren,
+            IEnumerable<FileSystemMetadata> fileSystemChildren,
             IDirectoryService directoryService,
             IFileSystem fileSystem,
             ILogger logger,

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -744,7 +744,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             if (!string.IsNullOrEmpty(info.Path))
             {
                 item.Path = info.Path;
-                var fileInfo = new FileInfo(info.Path);
+                var fileInfo = _fileSystem.GetFileInfo(info.Path);
 
                 recording.DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo);
                 recording.DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo);

+ 1 - 1
MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs

@@ -864,7 +864,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
         private async Task<MediaSourceInfo> GetEncodedMediaSource(string path, User user, bool isVideo)
         {
-            var item = _libraryManager.ResolvePath(new FileInfo(path));
+            var item = _libraryManager.ResolvePath(_fileSystem.GetFileSystemInfo(path));
 
             await item.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
 

+ 1 - 1
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -426,7 +426,7 @@ namespace MediaBrowser.Server.Startup.Common
             var musicManager = new MusicManager(LibraryManager);
             RegisterSingleInstance<IMusicManager>(new MusicManager(LibraryManager));
 
-            LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager);
+            LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, this);
             RegisterSingleInstance(LibraryMonitor);
 
             ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager);

+ 1 - 1
MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs

@@ -26,7 +26,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
             new BaseNfoParser<MusicAlbum>(_logger, _config).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "album.nfo"));
         }

+ 1 - 1
MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs

@@ -26,7 +26,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
             new BaseNfoParser<MusicArtist>(_logger, _config).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "artist.nfo"));
         }

+ 1 - 1
MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs

@@ -55,7 +55,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
             FileSystem = fileSystem;
         }
 
-        protected abstract FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService);
+        protected abstract FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService);
 
         public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
         {

+ 1 - 1
MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs

@@ -41,7 +41,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
             }
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return MovieNfoSaver.GetMovieSavePaths(info, FileSystem)
                 .Select(directoryService.GetFile)

+ 1 - 1
MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs

@@ -32,7 +32,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
             result.Images = images;
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             var path = Path.ChangeExtension(info.Path, ".nfo");
 

+ 1 - 1
MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs

@@ -26,7 +26,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
             new SeasonNfoParser(_logger, _config).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "season.nfo"));
         }

+ 1 - 1
MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs

@@ -26,7 +26,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
             new SeriesNfoParser(_logger, _config).Fetch(result, path, cancellationToken);
         }
 
-        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "tvshow.nfo"));
         }

+ 7 - 7
MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs

@@ -815,7 +815,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
 
             if (options.SaveImagePathsInNfo)
             {
-                AddImages(item, writer, fileSystem, config);
+                AddImages(item, writer, libraryManager, config);
             }
 
             AddUserData(item, writer, userManager, userDataRepo, options);
@@ -879,7 +879,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
                 StringComparison.OrdinalIgnoreCase);
         }
 
-        private static void AddImages(BaseItem item, XmlWriter writer, IFileSystem fileSystem, IServerConfigurationManager config)
+        private static void AddImages(BaseItem item, XmlWriter writer, ILibraryManager libraryManager, IServerConfigurationManager config)
         {
             writer.WriteStartElement("art");
 
@@ -887,12 +887,12 @@ namespace MediaBrowser.XbmcMetadata.Savers
 
             if (!string.IsNullOrEmpty(poster))
             {
-                writer.WriteElementString("poster", GetPathToSave(item.PrimaryImagePath, fileSystem, config));
+                writer.WriteElementString("poster", GetPathToSave(item.PrimaryImagePath, libraryManager, config));
             }
 
             foreach (var backdrop in item.GetImages(ImageType.Backdrop))
             {
-                writer.WriteElementString("fanart", GetPathToSave(backdrop.Path, fileSystem, config));
+                writer.WriteElementString("fanart", GetPathToSave(backdrop.Path, libraryManager, config));
             }
 
             writer.WriteEndElement();
@@ -984,7 +984,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
 
                     if (!string.IsNullOrEmpty(personEntity.PrimaryImagePath))
                     {
-                        writer.WriteElementString("thumb", GetPathToSave(personEntity.PrimaryImagePath, fileSystem, config));
+                        writer.WriteElementString("thumb", GetPathToSave(personEntity.PrimaryImagePath, libraryManager, config));
                     }
                 }
                 catch (Exception)
@@ -996,11 +996,11 @@ namespace MediaBrowser.XbmcMetadata.Savers
             }
         }
 
-        private static string GetPathToSave(string path, IFileSystem fileSystem, IServerConfigurationManager config)
+        private static string GetPathToSave(string path, ILibraryManager libraryManager, IServerConfigurationManager config)
         {
             foreach (var map in config.Configuration.PathSubstitutions)
             {
-                path = fileSystem.SubstitutePath(path, map.From, map.To);
+                path = libraryManager.SubstitutePath(path, map.From, map.To);
             }
 
             return path;