diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs index eabda673a..e371791f8 100644 --- a/MediaBrowser.Api/GamesService.cs +++ b/MediaBrowser.Api/GamesService.cs @@ -155,7 +155,7 @@ namespace MediaBrowser.Api var games = items.OfType().ToList(); - summary.ClientInstalledGameCount = games.Count(i => !i.IsPlaceHolder); + summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder); summary.GameCount = games.Count; diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 667a86fe6..3360d9736 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/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(); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 6743088c6..04e861d5b 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -279,8 +279,19 @@ namespace MediaBrowser.Api.Playback /// /// System.Int32. /// Unrecognized MediaEncodingQuality value. - 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; } diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index 5324d2c80..aec271ff2 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/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); diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index 909dd0f40..4d8d3a581 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/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); diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 023c59730..8ae61b521 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/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) diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index 6deea4ffc..43dc6f0d4 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/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); diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs index a73a8f0d9..6b0375e2d 100644 --- a/MediaBrowser.Api/Playback/StreamRequest.cs +++ b/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 diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 3874fa603..961ac0a2a 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/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); + } } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 0deebeb32..23f8ac31a 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/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 /// The images. /// true if XXXX, false otherwise. /// Cannot call AddImages with chapter images - public bool AddImages(ImageType imageType, IEnumerable images) + public bool AddImages(ImageType imageType, IEnumerable images) { if (imageType == ImageType.Chapter) { diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index 8e66605dd..bac226369 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -62,7 +62,7 @@ namespace MediaBrowser.Controller.Entities /// The type. /// The index. /// The file. - void SetImagePath(ImageType type, int index, FileInfo file); + void SetImagePath(ImageType type, int index, FileSystemInfo file); /// /// Determines whether the specified type has image. @@ -129,7 +129,7 @@ namespace MediaBrowser.Controller.Entities /// Type of the image. /// The images. /// true if XXXX, false otherwise. - bool AddImages(ImageType imageType, IEnumerable images); + bool AddImages(ImageType imageType, IEnumerable images); /// /// Determines whether [is save local metadata enabled]. @@ -180,7 +180,7 @@ namespace MediaBrowser.Controller.Entities /// The item. /// Type of the image. /// The file. - 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); } diff --git a/MediaBrowser.Controller/Library/TVUtils.cs b/MediaBrowser.Controller/Library/TVUtils.cs index c64e4fa0c..7841a32ae 100644 --- a/MediaBrowser.Controller/Library/TVUtils.cs +++ b/MediaBrowser.Controller/Library/TVUtils.cs @@ -27,94 +27,94 @@ namespace MediaBrowser.Controller.Library /// /// A season folder must contain one of these somewhere in the name /// - 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", + "сезон" + }; /// /// 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 /// - private static readonly Regex[] EpisodeExpressions = new[] - { - new Regex( - @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)[sS](?\d{1,4})[x,X]?[eE](?\d{1,3})[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?[^\\\/]*)[sS](?\d{1,4})[xX\.]?[eE](?\d{1,3})[^\\\/]*$", - RegexOptions.Compiled) - }; - private static readonly Regex[] MultipleEpisodeExpressions = new[] - { - new Regex( - @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})((-| - )\d{1,4}[eExX](?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})((-| - )\d{1,4}[xX][eE](?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})((-| - )?[xXeE](?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})(-[xE]?[eE]?(?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))((-| - )\d{1,4}[xXeE](?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))((-| - )\d{1,4}[xX][eE](?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))((-| - )?[xXeE](?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))(-[xX]?[eE]?(?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?[^\\\/]*)[sS](?\d{1,4})[xX\.]?[eE](?\d{1,3})((-| - )?[xXeE](?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?[^\\\/]*)[sS](?\d{1,4})[xX\.]?[eE](?\d{1,3})(-[xX]?[eE]?(?\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled) - }; + private static readonly Regex[] EpisodeExpressions = + { + new Regex( + @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)[sS](?\d{1,4})[x,X]?[eE](?\d{1,3})[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)(?[^\\\/]*)[sS](?\d{1,4})[xX\.]?[eE](?\d{1,3})[^\\\/]*$", + RegexOptions.Compiled) + }; + private static readonly Regex[] MultipleEpisodeExpressions = + { + new Regex( + @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})((-| - )\d{1,4}[eExX](?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})((-| - )\d{1,4}[xX][eE](?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})((-| - )?[xXeE](?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)[sS]?(?\d{1,4})[xX](?\d{1,3})(-[xE]?[eE]?(?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))((-| - )\d{1,4}[xXeE](?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))((-| - )\d{1,4}[xX][eE](?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))((-| - )?[xXeE](?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)(?((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?\d{1,4})[xX](?\d{1,3}))(-[xX]?[eE]?(?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)(?[^\\\/]*)[sS](?\d{1,4})[xX\.]?[eE](?\d{1,3})((-| - )?[xXeE](?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled), + new Regex( + @".*(\\|\/)(?[^\\\/]*)[sS](?\d{1,4})[xX\.]?[eE](?\d{1,3})(-[xX]?[eE]?(?\d{1,3}))+[^\\\/]*$", + RegexOptions.Compiled) + }; /// /// To avoid the following matching movies they are only valid when contained in a folder which has been matched as a being season /// - private static readonly Regex[] EpisodeExpressionsInASeasonFolder = new[] - { - new Regex( - @".*(\\|\/)(?\d{1,2})\s?-\s?[^\\\/]*$", - RegexOptions.Compiled), - // 01 - blah.avi, 01-blah.avi - new Regex( - @".*(\\|\/)(?\d{1,2})[^\d\\]*[^\\\/]*$", - RegexOptions.Compiled), - // 01.avi, 01.blah.avi "01 - 22 blah.avi" - new Regex( - @".*(\\|\/)(?\d)(?\d{1,2})[^\d\\]+[^\\\/]*$", - RegexOptions.Compiled), - // 01.avi, 01.blah.avi - new Regex( - @".*(\\|\/)\D*\d+(?\d{2})", - RegexOptions.Compiled) - // hell0 - 101 - hello.avi + private static readonly Regex[] EpisodeExpressionsInASeasonFolder = + { + new Regex( + @".*(\\|\/)(?\d{1,2})\s?-\s?[^\\\/]*$", + RegexOptions.Compiled), + // 01 - blah.avi, 01-blah.avi + new Regex( + @".*(\\|\/)(?\d{1,2})[^\d\\]*[^\\\/]*$", + RegexOptions.Compiled), + // 01.avi, 01.blah.avi "01 - 22 blah.avi" + new Regex( + @".*(\\|\/)(?\d)(?\d{1,2})[^\d\\]+[^\\\/]*$", + RegexOptions.Compiled), + // 01.avi, 01.blah.avi + new Regex( + @".*(\\|\/)\D*\d+(?\d{2})", + RegexOptions.Compiled) + // hell0 - 101 - hello.avi - }; + }; /// /// Gets the season number from path. @@ -151,8 +151,8 @@ namespace MediaBrowser.Controller.Library /// System.Nullable{System.Int32}. 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++) diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs index b7dff96cd..f7984c32c 100644 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs @@ -95,6 +95,18 @@ namespace MediaBrowser.Controller.Net /// System.Object. object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary responseHeaders = null, bool isHeadRequest = false); + /// + /// Gets the static file result. + /// + /// The request context. + /// The path. + /// Type of the content. + /// The file share. + /// The response headers. + /// if set to true [is head request]. + /// System.Object. + object GetStaticFileResult(IRequest requestContext, string path, string contentType, FileShare fileShare = FileShare.Read, IDictionary responseHeaders = null, bool isHeadRequest = false); + /// /// Gets the optimized serialized result using cache. /// diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index 751de9fb4..9d41b6d25 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/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 GetFileSystemEntries(string path); - IEnumerable GetFiles(string path); - IEnumerable GetDirectories(string path); - FileInfo GetFile(string path); - DirectoryInfo GetDirectory(string path); + IEnumerable GetFiles(string path); + FileSystemInfo GetFile(string path); } public class DirectoryService : IDirectoryService @@ -50,31 +48,17 @@ namespace MediaBrowser.Controller.Providers return entries; } - public IEnumerable GetFiles(string path) + public IEnumerable GetFiles(string path) { - return GetFileSystemEntries(path).OfType(); + return GetFileSystemEntries(path).Where(i => (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory); } - public IEnumerable GetDirectories(string path) - { - return GetFileSystemEntries(path).OfType(); - } - - 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)); - } } } diff --git a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs index ec24e1d60..68afb84b8 100644 --- a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs +++ b/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; } } diff --git a/MediaBrowser.Providers/AdultVideos/AdultVideoXmlProvider.cs b/MediaBrowser.Providers/AdultVideos/AdultVideoXmlProvider.cs index fcdaf29fd..efc8db9e7 100644 --- a/MediaBrowser.Providers/AdultVideos/AdultVideoXmlProvider.cs +++ b/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); } diff --git a/MediaBrowser.Providers/All/LocalImageProvider.cs b/MediaBrowser.Providers/All/LocalImageProvider.cs index f626c9534..6ef5f6bf3 100644 --- a/MediaBrowser.Providers/All/LocalImageProvider.cs +++ b/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() + var extraFanartFolder = files .FirstOrDefault(i => string.Equals(i.Name, "extrafanart", StringComparison.OrdinalIgnoreCase)); if (extraFanartFolder != null) diff --git a/MediaBrowser.Providers/BaseXmlProvider.cs b/MediaBrowser.Providers/BaseXmlProvider.cs index 908688086..a5a3ba146 100644 --- a/MediaBrowser.Providers/BaseXmlProvider.cs +++ b/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) { diff --git a/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs b/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs index 77ea52fa9..1d4d893ed 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs +++ b/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")); } diff --git a/MediaBrowser.Providers/Folders/FolderXmlProvider.cs b/MediaBrowser.Providers/Folders/FolderXmlProvider.cs index 978fb0f0c..144d1b752 100644 --- a/MediaBrowser.Providers/Folders/FolderXmlProvider.cs +++ b/MediaBrowser.Providers/Folders/FolderXmlProvider.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Folders new BaseItemXmlParser(_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")); } diff --git a/MediaBrowser.Providers/Games/GameSystemXmlProvider.cs b/MediaBrowser.Providers/Games/GameSystemXmlProvider.cs index 9efa93dfa..db9c8f063 100644 --- a/MediaBrowser.Providers/Games/GameSystemXmlProvider.cs +++ b/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")); } diff --git a/MediaBrowser.Providers/Games/GameXmlProvider.cs b/MediaBrowser.Providers/Games/GameXmlProvider.cs index c12feb85c..6609f9d5e 100644 --- a/MediaBrowser.Providers/Games/GameXmlProvider.cs +++ b/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); diff --git a/MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs b/MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs index 400ac825f..44a312e24 100644 --- a/MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs +++ b/MediaBrowser.Providers/LiveTv/ChannelXmlProvider.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.LiveTv new BaseItemXmlParser(_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")); } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index c2279fb50..d516a8221 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -357,7 +357,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - public IEnumerable GetSubtitleFiles(Video video, IDirectoryService directoryService) + public IEnumerable GetSubtitleFiles(Video video, IDirectoryService directoryService) { var containingPath = video.ContainingFolderPath; diff --git a/MediaBrowser.Providers/Movies/MovieXmlProvider.cs b/MediaBrowser.Providers/Movies/MovieXmlProvider.cs index bb7650255..63921fd6a 100644 --- a/MediaBrowser.Providers/Movies/MovieXmlProvider.cs +++ b/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); } diff --git a/MediaBrowser.Providers/Movies/TrailerXmlProvider.cs b/MediaBrowser.Providers/Movies/TrailerXmlProvider.cs index df90d32ca..7e53c9e7f 100644 --- a/MediaBrowser.Providers/Movies/TrailerXmlProvider.cs +++ b/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); } diff --git a/MediaBrowser.Providers/Music/AlbumXmlProvider.cs b/MediaBrowser.Providers/Music/AlbumXmlProvider.cs index 60bc18b2f..73b914090 100644 --- a/MediaBrowser.Providers/Music/AlbumXmlProvider.cs +++ b/MediaBrowser.Providers/Music/AlbumXmlProvider.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Music new BaseItemXmlParser(_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")); } diff --git a/MediaBrowser.Providers/Music/ArtistXmlProvider.cs b/MediaBrowser.Providers/Music/ArtistXmlProvider.cs index 89ba1c794..b221fde1e 100644 --- a/MediaBrowser.Providers/Music/ArtistXmlProvider.cs +++ b/MediaBrowser.Providers/Music/ArtistXmlProvider.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Music new BaseItemXmlParser(_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")); } diff --git a/MediaBrowser.Providers/Music/MusicVideoXmlProvider.cs b/MediaBrowser.Providers/Music/MusicVideoXmlProvider.cs index 4291f2369..93d9031c3 100644 --- a/MediaBrowser.Providers/Music/MusicVideoXmlProvider.cs +++ b/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); } diff --git a/MediaBrowser.Providers/People/PersonXmlProvider.cs b/MediaBrowser.Providers/People/PersonXmlProvider.cs index 4a145a1c0..b120c4830 100644 --- a/MediaBrowser.Providers/People/PersonXmlProvider.cs +++ b/MediaBrowser.Providers/People/PersonXmlProvider.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.People new BaseItemXmlParser(_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")); } diff --git a/MediaBrowser.Providers/TV/EpisodeXmlProvider.cs b/MediaBrowser.Providers/TV/EpisodeXmlProvider.cs index 2590fbce8..44755b18a 100644 --- a/MediaBrowser.Providers/TV/EpisodeXmlProvider.cs +++ b/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"); diff --git a/MediaBrowser.Providers/TV/SeasonXmlProvider.cs b/MediaBrowser.Providers/TV/SeasonXmlProvider.cs index e53a2deff..c2d3fe2d1 100644 --- a/MediaBrowser.Providers/TV/SeasonXmlProvider.cs +++ b/MediaBrowser.Providers/TV/SeasonXmlProvider.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.TV new BaseItemXmlParser(_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")); } diff --git a/MediaBrowser.Providers/TV/SeriesXmlProvider.cs b/MediaBrowser.Providers/TV/SeriesXmlProvider.cs index 53599ef55..f32afbd96 100644 --- a/MediaBrowser.Providers/TV/SeriesXmlProvider.cs +++ b/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")); } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index e5ffd639b..5d326f1ca 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -173,14 +173,6 @@ namespace MediaBrowser.Server.Implementations.FileOrganization if (!overwriteExisting) { - if (fileExists || otherDuplicatePaths.Count > 0) - { - result.Status = FileSortingStatus.SkippedExisting; - result.StatusMessage = string.Empty; - result.DuplicatePaths = otherDuplicatePaths; - return; - } - if (options.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath)) { _logger.Info("File {0} already copied to new path {1}, stopping organization", sourcePath, newPath); @@ -188,10 +180,16 @@ namespace MediaBrowser.Server.Implementations.FileOrganization result.StatusMessage = string.Empty; return; } + + if (fileExists || otherDuplicatePaths.Count > 0) + { + result.Status = FileSortingStatus.SkippedExisting; + result.StatusMessage = string.Empty; + result.DuplicatePaths = otherDuplicatePaths; + return; + } } - - PerformFileSorting(options, result); if (overwriteExisting) diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index 8455d9f58..925ef8050 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/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 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); } /// diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index a8a4e2237..16c0d1a27 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/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;