Browse Source

live tv stream adjustments, add additional dlna params

Luke Pulverenti 11 năm trước cách đây
mục cha
commit
c4f587dd94
36 tập tin đã thay đổi với 204 bổ sung171 xóa
  1. 1 1
      MediaBrowser.Api/GamesService.cs
  2. 1 1
      MediaBrowser.Api/Movies/MoviesService.cs
  3. 32 12
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  4. 1 1
      MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
  5. 1 1
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  6. 7 3
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  7. 1 1
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  8. 2 0
      MediaBrowser.Api/Playback/StreamRequest.cs
  9. 17 1
      MediaBrowser.Api/Playback/StreamState.cs
  10. 2 2
      MediaBrowser.Controller/Entities/BaseItem.cs
  11. 3 3
      MediaBrowser.Controller/Entities/IHasImages.cs
  12. 80 80
      MediaBrowser.Controller/Library/TVUtils.cs
  13. 12 0
      MediaBrowser.Controller/Net/IHttpResultFactory.cs
  14. 7 23
      MediaBrowser.Controller/Providers/DirectoryService.cs
  15. 1 1
      MediaBrowser.Controller/Providers/ILocalImageProvider.cs
  16. 1 1
      MediaBrowser.Providers/AdultVideos/AdultVideoXmlProvider.cs
  17. 1 1
      MediaBrowser.Providers/All/LocalImageProvider.cs
  18. 1 1
      MediaBrowser.Providers/BaseXmlProvider.cs
  19. 1 1
      MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs
  20. 1 1
      MediaBrowser.Providers/Folders/FolderXmlProvider.cs
  21. 1 1
      MediaBrowser.Providers/Games/GameSystemXmlProvider.cs
  22. 1 1
      MediaBrowser.Providers/Games/GameXmlProvider.cs
  23. 1 1
      MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs
  24. 1 1
      MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
  25. 1 1
      MediaBrowser.Providers/Movies/MovieXmlProvider.cs
  26. 1 1
      MediaBrowser.Providers/Movies/TrailerXmlProvider.cs
  27. 1 1
      MediaBrowser.Providers/Music/AlbumXmlProvider.cs
  28. 1 1
      MediaBrowser.Providers/Music/ArtistXmlProvider.cs
  29. 1 1
      MediaBrowser.Providers/Music/MusicVideoXmlProvider.cs
  30. 1 1
      MediaBrowser.Providers/People/PersonXmlProvider.cs
  31. 1 1
      MediaBrowser.Providers/TV/EpisodeXmlProvider.cs
  32. 1 1
      MediaBrowser.Providers/TV/SeasonXmlProvider.cs
  33. 1 1
      MediaBrowser.Providers/TV/SeriesXmlProvider.cs
  34. 5 7
      MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
  35. 13 1
      MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
  36. 0 15
      MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs

+ 1 - 1
MediaBrowser.Api/GamesService.cs

@@ -155,7 +155,7 @@ namespace MediaBrowser.Api
 
             var games = items.OfType<Game>().ToList();
 
-            summary.ClientInstalledGameCount = games.Count(i => !i.IsPlaceHolder);
+            summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder);
 
             summary.GameCount = games.Count;
 

+ 1 - 1
MediaBrowser.Api/Movies/MoviesService.cs

@@ -174,7 +174,7 @@ namespace MediaBrowser.Api.Movies
                 .OrderBy(i => Guid.NewGuid())
                 .ToList();
 
-            var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(10).OrderBy(i => Guid.NewGuid()), itemLimit, fields, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
+            var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(7).OrderBy(i => Guid.NewGuid()), itemLimit, fields, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
             var similarToLiked = GetSimilarTo(user, allMovies, likedMovies, itemLimit, fields, RecommendationType.SimilarToLikedItem).GetEnumerator();
 
             var hasDirectorFromRecentlyPlayed = GetWithDirector(user, allMovies, recentDirectors, itemLimit, fields, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();

+ 32 - 12
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -279,8 +279,19 @@ namespace MediaBrowser.Api.Playback
         /// </summary>
         /// <returns>System.Int32.</returns>
         /// <exception cref="System.Exception">Unrecognized MediaEncodingQuality value.</exception>
-        protected int GetNumberOfThreads(bool isWebm)
+        protected int GetNumberOfThreads(StreamState state, bool isWebm)
         {
+            // Use more when this is true. -re will keep cpu usage under control
+            if (state.ReadInputAtNativeFramerate)
+            {
+                if (isWebm)
+                {
+                    return Math.Max(Environment.ProcessorCount - 1, 1);
+                }
+
+                return 0;
+            }
+
             // Webm: http://www.webmproject.org/docs/encoder-parameters/
             // The decoder will usually automatically use an appropriate number of threads according to how many cores are available but it can only use multiple threads 
             // for the coefficient data if the encoder selected --token-parts > 0 at encode time.
@@ -1191,66 +1202,74 @@ namespace MediaBrowser.Api.Playback
                     request.DeviceId = val;
                 }
                 else if (i == 1)
+                {
+                    request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+                }
+                else if (i == 2)
                 {
                     if (videoRequest != null)
                     {
                         videoRequest.VideoCodec = (VideoCodecs)Enum.Parse(typeof(VideoCodecs), val, true);
                     }
                 }
-                else if (i == 2)
+                else if (i == 3)
                 {
                     request.AudioCodec = (AudioCodecs)Enum.Parse(typeof(AudioCodecs), val, true);
                 }
-                else if (i == 3)
+                else if (i == 4)
                 {
                     if (videoRequest != null)
                     {
                         videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
                     }
                 }
-                else if (i == 4)
+                else if (i == 5)
                 {
                     if (videoRequest != null)
                     {
                         videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
                     }
                 }
-                else if (i == 5)
+                else if (i == 6)
                 {
                     if (videoRequest != null)
                     {
                         videoRequest.VideoBitRate = int.Parse(val, UsCulture);
                     }
                 }
-                else if (i == 6)
+                else if (i == 7)
                 {
                     request.AudioBitRate = int.Parse(val, UsCulture);
                 }
-                else if (i == 7)
+                else if (i == 8)
                 {
                     request.AudioChannels = int.Parse(val, UsCulture);
                 }
-                else if (i == 8)
+                else if (i == 9)
                 {
                     if (videoRequest != null)
                     {
                         request.StartTimeTicks = long.Parse(val, UsCulture);
                     }
                 }
-                else if (i == 9)
+                else if (i == 10)
                 {
                     if (videoRequest != null)
                     {
                         videoRequest.Profile = val;
                     }
                 }
-                else if (i == 10)
+                else if (i == 11)
                 {
                     if (videoRequest != null)
                     {
                         videoRequest.Level = val;
                     }
                 }
+                else if (i == 12)
+                {
+                    request.ForcedMimeType = val;
+                }
             }
         }
 
@@ -1334,6 +1353,7 @@ namespace MediaBrowser.Api.Playback
                     await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
                 }
 
+                state.ReadInputAtNativeFramerate = recording.RecordingInfo.Status == RecordingStatus.InProgress;
                 state.AudioSync = "1000";
                 state.DeInterlace = true;
             }
@@ -1420,8 +1440,8 @@ namespace MediaBrowser.Api.Playback
 
             state.HasMediaStreams = mediaStreams.Count > 0;
 
-            state.SegmentLength = state.ReadInputAtNativeFramerate ? 3 : 10;
-            state.HlsListSize = state.ReadInputAtNativeFramerate ? 20 : 1440;
+            state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
+            state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
 
             return state;
         }

+ 1 - 1
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -278,7 +278,7 @@ namespace MediaBrowser.Api.Playback.Hls
 
             var itsOffset = itsOffsetMs == 0 ? string.Empty : string.Format("-itsoffset {0} ", TimeSpan.FromMilliseconds(itsOffsetMs).TotalSeconds);
 
-            var threads = GetNumberOfThreads(false);
+            var threads = GetNumberOfThreads(state, false);
 
             var inputModifier = GetInputModifier(state);
 

+ 1 - 1
MediaBrowser.Api/Playback/Progressive/AudioService.cs

@@ -102,7 +102,7 @@ namespace MediaBrowser.Api.Playback.Progressive
 
             const string vn = " -vn";
 
-            var threads = GetNumberOfThreads(false);
+            var threads = GetNumberOfThreads(state, false);
 
             var inputModifier = GetInputModifier(state);
 

+ 7 - 3
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -214,12 +214,16 @@ namespace MediaBrowser.Api.Playback.Progressive
 
             if (request.Static)
             {
-                return ResultFactory.GetStaticFileResult(Request, state.MediaPath, FileShare.Read, responseHeaders, isHeadRequest);
+                var contentType = state.GetMimeType(state.MediaPath);
+
+                return ResultFactory.GetStaticFileResult(Request, state.MediaPath, contentType, FileShare.Read, responseHeaders, isHeadRequest);
             }
 
             if (outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive))
             {
-                return ResultFactory.GetStaticFileResult(Request, outputPath, FileShare.Read, responseHeaders, isHeadRequest);
+                var contentType = state.GetMimeType(outputPath);
+
+                return ResultFactory.GetStaticFileResult(Request, outputPath, contentType, FileShare.Read, responseHeaders, isHeadRequest);
             }
 
             return GetStreamResult(state, responseHeaders, isHeadRequest).Result;
@@ -287,7 +291,7 @@ namespace MediaBrowser.Api.Playback.Progressive
 
             responseHeaders["Accept-Ranges"] = "none";
 
-            var contentType = MimeTypes.GetMimeType(outputPath);
+            var contentType = state.GetMimeType(outputPath);
 
             // Headers only
             if (isHeadRequest)

+ 1 - 1
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -102,7 +102,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 format = " -f mp4 -movflags frag_keyframe+empty_moov";
             }
 
-            var threads = GetNumberOfThreads(string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase));
+            var threads = GetNumberOfThreads(state, string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase));
 
             var inputModifier = GetInputModifier(state);
 

+ 2 - 0
MediaBrowser.Api/Playback/StreamRequest.cs

@@ -66,6 +66,8 @@ namespace MediaBrowser.Api.Playback
         public bool ThrowDebugError { get; set; }
 
         public string Params { get; set; }
+
+        public string ForcedMimeType { get; set; }
     }
 
     public class VideoStreamRequest : StreamRequest

+ 17 - 1
MediaBrowser.Api/Playback/StreamState.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using System.Collections.Generic;
 using System.IO;
@@ -72,5 +73,20 @@ namespace MediaBrowser.Api.Playback
         public string InputVideoCodec { get; set; }
 
         public string InputAudioCodec { get; set; }
+
+        public string GetMimeType(string outputPath)
+        {
+            if (!string.IsNullOrWhiteSpace(Request.ForcedMimeType))
+            {
+                if (VideoRequest == null)
+                {
+                    return "audio/" + Request.ForcedMimeType;
+                }
+
+                return "video/" + Request.ForcedMimeType;
+            }
+
+            return MimeTypes.GetMimeType(outputPath);
+        }
     }
 }

+ 2 - 2
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -1184,7 +1184,7 @@ namespace MediaBrowser.Controller.Entities
             return GetImageInfo(type, imageIndex) != null;
         }
 
-        public void SetImagePath(ImageType type, int index, FileInfo file)
+        public void SetImagePath(ImageType type, int index, FileSystemInfo file)
         {
             if (type == ImageType.Chapter)
             {
@@ -1339,7 +1339,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, IEnumerable<FileInfo> images)
+        public bool AddImages(ImageType imageType, IEnumerable<FileSystemInfo> images)
         {
             if (imageType == ImageType.Chapter)
             {

+ 3 - 3
MediaBrowser.Controller/Entities/IHasImages.cs

@@ -62,7 +62,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, FileInfo file);
+        void SetImagePath(ImageType type, int index, FileSystemInfo file);
 
         /// <summary>
         /// Determines whether the specified type has image.
@@ -129,7 +129,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, IEnumerable<FileInfo> images);
+        bool AddImages(ImageType imageType, IEnumerable<FileSystemInfo> images);
 
         /// <summary>
         /// Determines whether [is save local metadata enabled].
@@ -180,7 +180,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, FileInfo file)
+        public static void SetImagePath(this IHasImages item, ImageType imageType, FileSystemInfo file)
         {
             item.SetImagePath(imageType, 0, file);
         }

+ 80 - 80
MediaBrowser.Controller/Library/TVUtils.cs

@@ -27,94 +27,94 @@ namespace MediaBrowser.Controller.Library
         /// <summary>
         /// A season folder must contain one of these somewhere in the name
         /// </summary>
-        private static readonly string[] SeasonFolderNames = new[]
-                                                                 {
-                                                                     "season",
-                                                                     "sæson",
-                                                                     "temporada",
-                                                                     "saison",
-                                                                     "staffel",
-                                                                     "series",
-                                                                     "сезон"
-                                                                 };
+        private static readonly string[] SeasonFolderNames =
+        {
+            "season",
+            "sæson",
+            "temporada",
+            "saison",
+            "staffel",
+            "series",
+            "сезон"
+        };
 
         /// <summary>
         /// Used to detect paths that represent episodes, need to make sure they don't also
         /// match movie titles like "2001 A Space..."
         /// Currently we limit the numbers here to 2 digits to try and avoid this
         /// </summary>
-        private static readonly Regex[] EpisodeExpressions = new[]
-                                                                 {
-                                                                     new Regex(
-                                                                         @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)[sS](?<seasonnumber>\d{1,4})[x,X]?[eE](?<epnumber>\d{1,3})[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})[^\\\/]*$",
-                                                                         RegexOptions.Compiled)
-                                                                 };
-        private static readonly Regex[] MultipleEpisodeExpressions = new[]
-                                                                 {
-                                                                     new Regex(
-                                                                         @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[eExX](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})(-[xE]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled),
-                                                                     new Regex(
-                                                                         @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
-                                                                         RegexOptions.Compiled)
-                                                                 };
+        private static readonly Regex[] EpisodeExpressions =
+        {
+            new Regex(
+                @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)[sS](?<seasonnumber>\d{1,4})[x,X]?[eE](?<epnumber>\d{1,3})[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})[^\\\/]*$",
+                RegexOptions.Compiled)
+        };
+        private static readonly Regex[] MultipleEpisodeExpressions =
+        {
+            new Regex(
+                @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[eExX](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})(-[xE]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled),
+            new Regex(
+                @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
+                RegexOptions.Compiled)
+        };
 
         /// <summary>
         /// To avoid the following matching movies they are only valid when contained in a folder which has been matched as a being season
         /// </summary>
-        private static readonly Regex[] EpisodeExpressionsInASeasonFolder = new[]
-                                                                                {
-                                                                                    new Regex(
-                                                                                        @".*(\\|\/)(?<epnumber>\d{1,2})\s?-\s?[^\\\/]*$",
-                                                                                        RegexOptions.Compiled),
-                                                                                    // 01 - blah.avi, 01-blah.avi
-                                                                                    new Regex(
-                                                                                        @".*(\\|\/)(?<epnumber>\d{1,2})[^\d\\]*[^\\\/]*$",
-                                                                                        RegexOptions.Compiled),
-                                                                                    // 01.avi, 01.blah.avi "01 - 22 blah.avi" 
-                                                                                    new Regex(
-                                                                                        @".*(\\|\/)(?<seasonnumber>\d)(?<epnumber>\d{1,2})[^\d\\]+[^\\\/]*$",
-                                                                                        RegexOptions.Compiled),
-                                                                                    // 01.avi, 01.blah.avi
-                                                                                    new Regex(
-                                                                                        @".*(\\|\/)\D*\d+(?<epnumber>\d{2})",
-                                                                                        RegexOptions.Compiled)
-                                                                                    // hell0 - 101 -  hello.avi
-
-                                                                                };
+        private static readonly Regex[] EpisodeExpressionsInASeasonFolder =
+        {
+            new Regex(
+                @".*(\\|\/)(?<epnumber>\d{1,2})\s?-\s?[^\\\/]*$",
+                RegexOptions.Compiled),
+            // 01 - blah.avi, 01-blah.avi
+            new Regex(
+                @".*(\\|\/)(?<epnumber>\d{1,2})[^\d\\]*[^\\\/]*$",
+                RegexOptions.Compiled),
+            // 01.avi, 01.blah.avi "01 - 22 blah.avi" 
+            new Regex(
+                @".*(\\|\/)(?<seasonnumber>\d)(?<epnumber>\d{1,2})[^\d\\]+[^\\\/]*$",
+                RegexOptions.Compiled),
+            // 01.avi, 01.blah.avi
+            new Regex(
+                @".*(\\|\/)\D*\d+(?<epnumber>\d{2})",
+                RegexOptions.Compiled)
+            // hell0 - 101 -  hello.avi
+
+        };
 
         /// <summary>
         /// Gets the season number from path.
@@ -151,8 +151,8 @@ namespace MediaBrowser.Controller.Library
         /// <returns>System.Nullable{System.Int32}.</returns>
         private static int? GetSeasonNumberFromPathSubstring(string path)
         {
-            int numericStart = -1;
-            int length = 0;
+            var numericStart = -1;
+            var length = 0;
 
             // Find out where the numbers start, and then keep going until they end
             for (var i = 0; i < path.Length; i++)

+ 12 - 0
MediaBrowser.Controller/Net/IHttpResultFactory.cs

@@ -95,6 +95,18 @@ namespace MediaBrowser.Controller.Net
         /// <returns>System.Object.</returns>
         object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary<string, string> responseHeaders = null, bool isHeadRequest = false);
 
+        /// <summary>
+        /// Gets the static file result.
+        /// </summary>
+        /// <param name="requestContext">The request context.</param>
+        /// <param name="path">The path.</param>
+        /// <param name="contentType">Type of the content.</param>
+        /// <param name="fileShare">The file share.</param>
+        /// <param name="responseHeaders">The response headers.</param>
+        /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
+        /// <returns>System.Object.</returns>
+        object GetStaticFileResult(IRequest requestContext, string path, string contentType, FileShare fileShare = FileShare.Read, IDictionary<string, string> responseHeaders = null, bool isHeadRequest = false);
+        
         /// <summary>
         /// Gets the optimized serialized result using cache.
         /// </summary>

+ 7 - 23
MediaBrowser.Controller/Providers/DirectoryService.cs

@@ -1,6 +1,6 @@
-using System.Collections.Concurrent;
-using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Logging;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
@@ -10,10 +10,8 @@ namespace MediaBrowser.Controller.Providers
     public interface IDirectoryService
     {
         List<FileSystemInfo> GetFileSystemEntries(string path);
-        IEnumerable<FileInfo> GetFiles(string path);
-        IEnumerable<DirectoryInfo> GetDirectories(string path);
-        FileInfo GetFile(string path);
-        DirectoryInfo GetDirectory(string path);
+        IEnumerable<FileSystemInfo> GetFiles(string path);
+        FileSystemInfo GetFile(string path);
     }
 
     public class DirectoryService : IDirectoryService
@@ -50,31 +48,17 @@ namespace MediaBrowser.Controller.Providers
             return entries;
         }
 
-        public IEnumerable<FileInfo> GetFiles(string path)
+        public IEnumerable<FileSystemInfo> GetFiles(string path)
         {
-            return GetFileSystemEntries(path).OfType<FileInfo>();
+            return GetFileSystemEntries(path).Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory);
         }
 
-        public IEnumerable<DirectoryInfo> GetDirectories(string path)
-        {
-            return GetFileSystemEntries(path).OfType<DirectoryInfo>();
-        }
-
-        public FileInfo GetFile(string path)
+        public FileSystemInfo GetFile(string path)
         {
             var directory = Path.GetDirectoryName(path);
             var filename = Path.GetFileName(path);
 
             return GetFiles(directory).FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase));
         }
-
-
-        public DirectoryInfo GetDirectory(string path)
-        {
-            var directory = Path.GetDirectoryName(path);
-            var name = Path.GetFileName(path);
-
-            return GetDirectories(directory).FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
-        }
     }
 }

+ 1 - 1
MediaBrowser.Controller/Providers/ILocalImageProvider.cs

@@ -23,7 +23,7 @@ namespace MediaBrowser.Controller.Providers
 
     public class LocalImageInfo
     {
-        public FileInfo FileInfo { get; set; }
+        public FileSystemInfo FileInfo { get; set; }
         public ImageType Type { get; set; }
     }
 

+ 1 - 1
MediaBrowser.Providers/AdultVideos/AdultVideoXmlProvider.cs

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

+ 1 - 1
MediaBrowser.Providers/All/LocalImageProvider.cs

@@ -201,7 +201,7 @@ namespace MediaBrowser.Providers.All
             PopulateBackdrops(images, files, imagePrefix, "background", "background-", ImageType.Backdrop);
             PopulateBackdrops(images, files, imagePrefix, "art", "art-", ImageType.Backdrop);
 
-            var extraFanartFolder = files.OfType<DirectoryInfo>()
+            var extraFanartFolder = files
                 .FirstOrDefault(i => string.Equals(i.Name, "extrafanart", StringComparison.OrdinalIgnoreCase));
 
             if (extraFanartFolder != null)

+ 1 - 1
MediaBrowser.Providers/BaseXmlProvider.cs

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

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

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

+ 1 - 1
MediaBrowser.Providers/Folders/FolderXmlProvider.cs

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

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

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

+ 1 - 1
MediaBrowser.Providers/Games/GameXmlProvider.cs

@@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Games
             new GameXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
         }
 
-        protected override FileInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             var fileInfo = FileSystem.GetFileSystemInfo(info.Path);
 

+ 1 - 1
MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs

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

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

@@ -357,7 +357,7 @@ namespace MediaBrowser.Providers.MediaInfo
             }
         }
 
-        public IEnumerable<FileInfo> GetSubtitleFiles(Video video, IDirectoryService directoryService)
+        public IEnumerable<FileSystemInfo> GetSubtitleFiles(Video video, IDirectoryService directoryService)
         {
             var containingPath = video.ContainingFolderPath;
 

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

@@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Movies
             new MovieXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
         }
 
-        protected override FileInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return GetXmlFileInfo(info, FileSystem);
         }

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

@@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Movies
             new MovieXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
         }
 
-        protected override FileInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return MovieXmlProvider.GetXmlFileInfo(info, FileSystem);
         }

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

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

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

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

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

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

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

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

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

@@ -27,7 +27,7 @@ namespace MediaBrowser.Providers.TV
             result.Images = images;
         }
 
-        protected override FileInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             var metadataPath = Path.GetDirectoryName(info.Path);
             metadataPath = Path.Combine(metadataPath, "metadata");

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

@@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.TV
             new BaseItemXmlParser<Season>(_logger).Fetch(result.Item, path, cancellationToken);
         }
 
-        protected override FileInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
+        protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)
         {
             return directoryService.GetFile(Path.Combine(info.Path, "season.xml"));
         }

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

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

+ 5 - 7
MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs

@@ -173,25 +173,23 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
 
             if (!overwriteExisting)
             {
-                if (fileExists || otherDuplicatePaths.Count > 0)
+                if (options.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath))
                 {
+                    _logger.Info("File {0} already copied to new path {1}, stopping organization", sourcePath, newPath);
                     result.Status = FileSortingStatus.SkippedExisting;
                     result.StatusMessage = string.Empty;
-                    result.DuplicatePaths = otherDuplicatePaths;
                     return;
                 }
-
-                if (options.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath))
+                
+                if (fileExists || otherDuplicatePaths.Count > 0)
                 {
-                    _logger.Info("File {0} already copied to new path {1}, stopping organization", sourcePath, newPath);
                     result.Status = FileSortingStatus.SkippedExisting;
                     result.StatusMessage = string.Empty;
+                    result.DuplicatePaths = otherDuplicatePaths;
                     return;
                 }
             }
 
-   
-
             PerformFileSorting(options, result);
 
             if (overwriteExisting)

+ 13 - 1
MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs

@@ -306,6 +306,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer
                 throw new ArgumentNullException("path");
             }
 
+            return GetStaticFileResult(requestContext, path, MimeTypes.GetMimeType(path), fileShare, responseHeaders, isHeadRequest);
+        }
+
+        public object GetStaticFileResult(IRequest requestContext, string path, string contentType,
+            FileShare fileShare = FileShare.Read, IDictionary<string, string> responseHeaders = null,
+            bool isHeadRequest = false)
+        {
+            if (string.IsNullOrEmpty(path))
+            {
+                throw new ArgumentNullException("path");
+            }
+
             if (fileShare != FileShare.Read && fileShare != FileShare.ReadWrite)
             {
                 throw new ArgumentException("FileShare must be either Read or ReadWrite");
@@ -315,7 +327,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 
             var cacheKey = path + dateModified.Ticks;
 
-            return GetStaticResult(requestContext, cacheKey.GetMD5(), dateModified, null, MimeTypes.GetMimeType(path), () => Task.FromResult(GetFileStream(path, fileShare)), responseHeaders, isHeadRequest);
+            return GetStaticResult(requestContext, cacheKey.GetMD5(), dateModified, null, contentType, () => Task.FromResult(GetFileStream(path, fileShare)), responseHeaders, isHeadRequest);
         }
 
         /// <summary>

+ 0 - 15
MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs

@@ -56,21 +56,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
                 {
                     return null;
                 }
-
-                // If the parent is not a boxset, the only other allowed parent type is Folder		
-                if (!(args.Parent is BoxSet))
-                {
-                    if (args.Parent.GetType() != typeof(Folder))
-                    {
-                        return null;
-                    }
-                }
-            }
-
-            // Since the looping is expensive, this is an optimization to help us avoid it
-            if (args.Path.IndexOf("[tvdbid", StringComparison.OrdinalIgnoreCase) != -1)
-            {
-                return null;
             }
 
             var isDirectory = args.IsDirectory;