diff --git a/MediaBrowser.Api/ImageProcessor.cs b/MediaBrowser.Api/ImageProcessor.cs index c4a2fdb699..32c7e05a21 100644 --- a/MediaBrowser.Api/ImageProcessor.cs +++ b/MediaBrowser.Api/ImageProcessor.cs @@ -9,6 +9,14 @@ namespace MediaBrowser.Api { public static class ImageProcessor { + /// + /// Resizes an image from a source stream and saves the result to an output stream + /// + /// Use if a fixed width is required. Aspect ratio will be preserved. + /// Use if a fixed height is required. Aspect ratio will be preserved. + /// Use if a max width is required. Aspect ratio will be preserved. + /// Use if a max height is required. Aspect ratio will be preserved. + /// Quality level, from 0-100. Currently only applies to JPG. The default value should suffice. public static void ProcessImage(Stream sourceImageStream, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, int? quality) { Image originalImage = Image.FromStream(sourceImageStream); diff --git a/MediaBrowser.Common/Configuration/BaseApplicationPaths.cs b/MediaBrowser.Common/Configuration/BaseApplicationPaths.cs index ae45280136..d030da844c 100644 --- a/MediaBrowser.Common/Configuration/BaseApplicationPaths.cs +++ b/MediaBrowser.Common/Configuration/BaseApplicationPaths.cs @@ -1,14 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Configuration; using System.IO; -using System.Configuration; using System.Reflection; namespace MediaBrowser.Common.Configuration { + /// + /// Provides a base class to hold common application paths used by both the UI and Server. + /// This can be subclassed to add application-specific paths. + /// public abstract class BaseApplicationPaths { private string _programDataPath; diff --git a/MediaBrowser.Common/Events/GenericItemEventArgs.cs b/MediaBrowser.Common/Events/GenericItemEventArgs.cs deleted file mode 100644 index ae7b2f574a..0000000000 --- a/MediaBrowser.Common/Events/GenericItemEventArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace MediaBrowser.Common.Events -{ - public class GenericItemEventArgs : EventArgs - { - public TItemType Item { get; set; } - } -} diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index c38847b5c1..2d3d56da92 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -67,7 +67,6 @@ - diff --git a/MediaBrowser.Common/Serialization/JsvSerializer.cs b/MediaBrowser.Common/Serialization/JsvSerializer.cs index d2a12e0598..24c4b074eb 100644 --- a/MediaBrowser.Common/Serialization/JsvSerializer.cs +++ b/MediaBrowser.Common/Serialization/JsvSerializer.cs @@ -4,7 +4,7 @@ namespace MediaBrowser.Common.Serialization { /// /// This adds support for ServiceStack's proprietary JSV output format. - /// It's based on Json but the serializer performs faster and output runs about 10% smaller + /// It's a hybrid of Json and Csv but the serializer performs about 25% faster and output runs about 10% smaller /// http://www.servicestack.net/benchmarks/NorthwindDatabaseRowsSerialization.100000-times.2010-08-17.html /// public static class JsvSerializer diff --git a/MediaBrowser.Controller/Configuration/ServerApplicationPaths.cs b/MediaBrowser.Controller/Configuration/ServerApplicationPaths.cs index 50bc1d10ce..92283ab25f 100644 --- a/MediaBrowser.Controller/Configuration/ServerApplicationPaths.cs +++ b/MediaBrowser.Controller/Configuration/ServerApplicationPaths.cs @@ -3,6 +3,9 @@ using MediaBrowser.Common.Configuration; namespace MediaBrowser.Controller.Configuration { + /// + /// Extends BaseApplicationPaths to add paths that are only applicable on the server + /// public class ServerApplicationPaths : BaseApplicationPaths { private string _rootFolderPath; diff --git a/MediaBrowser.Controller/FFMpeg/ffmpeg.exe.REMOVED.git-id b/MediaBrowser.Controller/FFMpeg/ffmpeg.exe.REMOVED.git-id index 30743c0548..9258468531 100644 --- a/MediaBrowser.Controller/FFMpeg/ffmpeg.exe.REMOVED.git-id +++ b/MediaBrowser.Controller/FFMpeg/ffmpeg.exe.REMOVED.git-id @@ -1 +1 @@ -faf137524dd67edb423344830e1436dcdca83daf \ No newline at end of file +480bd76ce262d65df6b87802bd9bda18cf5b1c8f \ No newline at end of file diff --git a/MediaBrowser.Controller/FFMpeg/ffprobe.exe.REMOVED.git-id b/MediaBrowser.Controller/FFMpeg/ffprobe.exe.REMOVED.git-id index 4ad2356c9e..5ff237cfe6 100644 --- a/MediaBrowser.Controller/FFMpeg/ffprobe.exe.REMOVED.git-id +++ b/MediaBrowser.Controller/FFMpeg/ffprobe.exe.REMOVED.git-id @@ -1 +1 @@ -a304265e8410291c1f696e74a4f9b84970bb5753 \ No newline at end of file +1f5e9773868e0f41260f64e20090803400b9a36d \ No newline at end of file diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index fa650e53fe..b7e0258e0c 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -49,6 +49,11 @@ namespace MediaBrowser.Controller /// [ImportMany(typeof(IBaseItemResolver))] private IEnumerable EntityResolversEnumerable { get; set; } + + /// + /// Once MEF has loaded the resolvers, sort them by priority and store them in this array + /// Given the sheer number of times they'll be iterated over it'll be faster to loop through an array + /// internal IBaseItemResolver[] EntityResolvers { get; private set; } /// diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 41bd42040e..652a9d7365 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -76,7 +76,6 @@ - diff --git a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs index f0c95e4f78..d0bd20a47a 100644 --- a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs +++ b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs @@ -20,14 +20,17 @@ namespace MediaBrowser.Controller.Providers get { return MetadataProviderPriority.First; } } - public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) + public async override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) + { + await Task.Run(() => { Fetch(item, args); }).ConfigureAwait(false); + } + + private void Fetch(BaseEntity item, ItemResolveEventArgs args) { if (args.ContainsFile("folder.xml")) { - return Task.Run(() => { new FolderXmlParser().Fetch(item as Folder, Path.Combine(args.Path, "folder.xml")); }); + new BaseItemXmlParser().Fetch(item as Folder, Path.Combine(args.Path, "folder.xml")); } - - return Task.FromResult(null); } } } diff --git a/MediaBrowser.Controller/Xml/FolderXmlParser.cs b/MediaBrowser.Controller/Xml/FolderXmlParser.cs deleted file mode 100644 index 5ce3a10e5a..0000000000 --- a/MediaBrowser.Controller/Xml/FolderXmlParser.cs +++ /dev/null @@ -1,12 +0,0 @@ -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.Xml -{ - /// - /// Fetches metadata for a folder. - /// Since folder.xml contains no folder-specific values, no overrides are needed - /// - public class FolderXmlParser : BaseItemXmlParser - { - } -} diff --git a/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs b/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs index 2e9e7b0f5f..689e786d10 100644 --- a/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs +++ b/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs @@ -22,14 +22,17 @@ namespace MediaBrowser.Movies.Providers get { return MetadataProviderPriority.First; } } - public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) + public override async Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) + { + await Task.Run(() => { Fetch(item, args); }).ConfigureAwait(false); + } + + private void Fetch(BaseEntity item, ItemResolveEventArgs args) { if (args.ContainsFile("movie.xml")) { - return Task.Run(() => { new BaseItemXmlParser().Fetch(item as Movie, Path.Combine(args.Path, "movie.xml")); }); + new BaseItemXmlParser().Fetch(item as Movie, Path.Combine(args.Path, "movie.xml")); } - - return Task.FromResult(null); } } } diff --git a/MediaBrowser.Movies/Resolvers/BoxSetResolver.cs b/MediaBrowser.Movies/Resolvers/BoxSetResolver.cs index 79d30e8666..397bef2d68 100644 --- a/MediaBrowser.Movies/Resolvers/BoxSetResolver.cs +++ b/MediaBrowser.Movies/Resolvers/BoxSetResolver.cs @@ -12,6 +12,10 @@ namespace MediaBrowser.Movies.Resolvers { protected override BoxSet Resolve(ItemResolveEventArgs args) { + // It's a boxset if all of the following conditions are met: + // It's under a 'Movies' VF + // Is a Directory + // Contains [boxset] in the path if ((args.VirtualFolderCollectionType ?? string.Empty).Equals("Movies", StringComparison.OrdinalIgnoreCase) && args.IsDirectory) { if (Path.GetFileName(args.Path).IndexOf("[boxset]", StringComparison.OrdinalIgnoreCase) != -1) diff --git a/MediaBrowser.Movies/Resolvers/MovieResolver.cs b/MediaBrowser.Movies/Resolvers/MovieResolver.cs index 9d53f9b440..795a873e35 100644 --- a/MediaBrowser.Movies/Resolvers/MovieResolver.cs +++ b/MediaBrowser.Movies/Resolvers/MovieResolver.cs @@ -1,15 +1,9 @@ using System; using System.ComponentModel.Composition; -using System.IO; -using System.Linq; -using MediaBrowser.Controller; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Resolvers; -using MediaBrowser.Model.Entities; using MediaBrowser.Movies.Entities; -using System.Collections.Generic; -using System.Threading.Tasks; namespace MediaBrowser.Movies.Resolvers { @@ -18,27 +12,11 @@ namespace MediaBrowser.Movies.Resolvers { protected override Movie Resolve(ItemResolveEventArgs args) { + // Must be a directory and under a 'Movies' VF if ((args.VirtualFolderCollectionType ?? string.Empty).Equals("Movies", StringComparison.OrdinalIgnoreCase) && args.IsDirectory) { - if (args.ContainsFile("movie.xml") || Path.GetFileName(args.Path).IndexOf("[tmdbid=", StringComparison.OrdinalIgnoreCase) != -1) - { - return GetMovie(args) ?? new Movie(); - } - - // If it's not a boxset, the only other allowed parent type is Folder - if (!(args.Parent is BoxSet)) - { - if (args.Parent != null && args.Parent.GetType() != typeof(Folder)) - { - return null; - } - } - - // There's no metadata or [tmdb in the path, now we will have to work some magic to see if this is a Movie - if (args.Parent != null) - { - return GetMovie(args); - } + // Return a movie if the video resolver finds something in the folder + return GetMovie(args); } return null; @@ -46,6 +24,7 @@ namespace MediaBrowser.Movies.Resolvers private Movie GetMovie(ItemResolveEventArgs args) { + // Loop through each child file/folder and see if we find a video for (var i = 0; i < args.FileSystemChildren.Length; i++) { var child = args.FileSystemChildren[i]; diff --git a/MediaBrowser.TV/Plugin.cs b/MediaBrowser.TV/Plugin.cs index ab73f2c046..ccf39effc2 100644 --- a/MediaBrowser.TV/Plugin.cs +++ b/MediaBrowser.TV/Plugin.cs @@ -28,6 +28,7 @@ namespace MediaBrowser.TV void ItemController_PreBeginResolvePath(object sender, PreBeginResolveEventArgs e) { + // Don't try and resolve files with the metadata folder if (System.IO.Path.GetFileName(e.Path).Equals("metadata", StringComparison.OrdinalIgnoreCase) && e.IsDirectory) { if (e.Parent is Season || e.Parent is Series) diff --git a/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs b/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs index 300adb7e1b..a788b9211b 100644 --- a/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs +++ b/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs @@ -40,6 +40,7 @@ namespace MediaBrowser.TV.Providers private void SetPrimaryImagePath(Episode item, Season season, string metadataFolder, string episodeFileName) { + // Look for the image file in the metadata folder, and if found, set PrimaryImagePath string[] imageFiles = new string[] { Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".jpg")), Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".png")) @@ -49,7 +50,7 @@ namespace MediaBrowser.TV.Providers if (season == null) { - // Gotta do this the slow way + // Epsiode directly in Series folder. Gotta do this the slow way image = imageFiles.FirstOrDefault(f => File.Exists(f)); } else diff --git a/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs b/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs index 431e27308b..8e1f7b551d 100644 --- a/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs +++ b/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs @@ -22,21 +22,21 @@ namespace MediaBrowser.TV.Providers get { return MetadataProviderPriority.First; } } - public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) + public override async Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) { - return Fetch(item, args); + await Task.Run(() => { Fetch(item, args); }).ConfigureAwait(false); } - private Task Fetch(BaseEntity item, ItemResolveEventArgs args) + private void Fetch(BaseEntity item, ItemResolveEventArgs args) { string metadataFolder = Path.Combine(args.Parent.Path, "metadata"); string metadataFile = Path.Combine(metadataFolder, Path.ChangeExtension(Path.GetFileName(args.Path), ".xml")); - return FetchMetadata(item as Episode, args.Parent as Season, metadataFile); + FetchMetadata(item as Episode, args.Parent as Season, metadataFile); } - private async Task FetchMetadata(Episode item, Season season, string metadataFile) + private void FetchMetadata(Episode item, Season season, string metadataFile) { if (season == null) { @@ -55,7 +55,7 @@ namespace MediaBrowser.TV.Providers } } - await Task.Run(() => { new EpisodeXmlParser().Fetch(item, metadataFile); }).ConfigureAwait(false); + new EpisodeXmlParser().Fetch(item, metadataFile); } } } diff --git a/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs b/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs index abecc41f06..a1e6a04824 100644 --- a/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs +++ b/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs @@ -22,14 +22,17 @@ namespace MediaBrowser.TV.Providers get { return MetadataProviderPriority.First; } } - public override Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) + public override async Task FetchAsync(BaseEntity item, ItemResolveEventArgs args) + { + await Task.Run(() => { Fetch(item, args); }).ConfigureAwait(false); + } + + private void Fetch(BaseEntity item, ItemResolveEventArgs args) { if (args.ContainsFile("series.xml")) { - return Task.Run(() => { new SeriesXmlParser().Fetch(item as Series, Path.Combine(args.Path, "series.xml")); }); + new SeriesXmlParser().Fetch(item as Series, Path.Combine(args.Path, "series.xml")); } - - return Task.FromResult(null); } } } diff --git a/MediaBrowser.TV/Resolvers/EpisodeResolver.cs b/MediaBrowser.TV/Resolvers/EpisodeResolver.cs index b01a7be9ac..e6bc933421 100644 --- a/MediaBrowser.TV/Resolvers/EpisodeResolver.cs +++ b/MediaBrowser.TV/Resolvers/EpisodeResolver.cs @@ -10,6 +10,7 @@ namespace MediaBrowser.TV.Resolvers { protected override Episode Resolve(ItemResolveEventArgs args) { + // If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something if (args.Parent is Season || args.Parent is Series) { return base.Resolve(args); diff --git a/MediaBrowser.TV/Resolvers/SeasonResolver.cs b/MediaBrowser.TV/Resolvers/SeasonResolver.cs index 74424e8c2b..8770d08e79 100644 --- a/MediaBrowser.TV/Resolvers/SeasonResolver.cs +++ b/MediaBrowser.TV/Resolvers/SeasonResolver.cs @@ -15,6 +15,7 @@ namespace MediaBrowser.TV.Resolvers { Season season = new Season(); + // Gather these now so that the episode provider classes can utilize them instead of having to make their own file system calls if (args.ContainsFolder("metadata")) { season.MetadataFiles = Directory.GetFiles(Path.Combine(args.Path, "metadata"), "*", SearchOption.TopDirectoryOnly); diff --git a/MediaBrowser.TV/Resolvers/SeriesResolver.cs b/MediaBrowser.TV/Resolvers/SeriesResolver.cs index 8324cbfd9e..aa7c00306b 100644 --- a/MediaBrowser.TV/Resolvers/SeriesResolver.cs +++ b/MediaBrowser.TV/Resolvers/SeriesResolver.cs @@ -20,6 +20,10 @@ namespace MediaBrowser.TV.Resolvers return null; } + // It's a Series if any of the following conditions are met: + // series.xml exists + // [tvdbid= is present in the path + // TVUtils.IsSeriesFolder returns true if (args.ContainsFile("series.xml") || Path.GetFileName(args.Path).IndexOf("[tvdbid=", StringComparison.OrdinalIgnoreCase) != -1 || TVUtils.IsSeriesFolder(args.Path, args.FileSystemChildren)) { return new Series();