diff options
| author | Luke <luke.pulverenti@gmail.com> | 2014-12-14 00:38:07 -0500 |
|---|---|---|
| committer | Luke <luke.pulverenti@gmail.com> | 2014-12-14 00:38:07 -0500 |
| commit | 524293ea79ab61228f8326561be70bcca4d0ea8f (patch) | |
| tree | ccfe163c8edafc8dd14b0b63d48712a6d504de9d /MediaBrowser.Controller | |
| parent | 00da34b90a2f2fcee4d6aa584e25fccebb375b6d (diff) | |
| parent | 9df9723fa8554df0fd51d777d3f781b0136de926 (diff) | |
Merge pull request #954 from MediaBrowser/dev
3.0.5462.0
Diffstat (limited to 'MediaBrowser.Controller')
40 files changed, 633 insertions, 735 deletions
diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs index 74ae42095..4a2d39066 100644 --- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -15,11 +15,13 @@ namespace MediaBrowser.Controller.Collections public Dictionary<string, string> ProviderIds { get; set; } public List<Guid> ItemIdList { get; set; } + public List<Guid> UserIds { get; set; } public CollectionCreationOptions() { ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); ItemIdList = new List<Guid>(); + UserIds = new List<Guid>(); } } } diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index af184e6e9..efd24336a 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Devices; using MediaBrowser.Model.Events; +using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; using System; using System.Collections.Generic; @@ -58,8 +59,9 @@ namespace MediaBrowser.Controller.Devices /// <summary> /// Gets the devices. /// </summary> + /// <param name="query">The query.</param> /// <returns>IEnumerable<DeviceInfo>.</returns> - IEnumerable<DeviceInfo> GetDevices(); + QueryResult<DeviceInfo> GetDevices(DeviceQuery query); /// <summary> /// Deletes the device. diff --git a/MediaBrowser.Controller/Dlna/DlnaIconResponse.cs b/MediaBrowser.Controller/Dlna/DlnaIconResponse.cs deleted file mode 100644 index 04d8e88b9..000000000 --- a/MediaBrowser.Controller/Dlna/DlnaIconResponse.cs +++ /dev/null @@ -1,22 +0,0 @@ -using MediaBrowser.Controller.Drawing; -using System; -using System.IO; - -namespace MediaBrowser.Controller.Dlna -{ - public class DlnaIconResponse : IDisposable - { - public Stream Stream { get; set; } - - public ImageFormat Format { get; set; } - - public void Dispose() - { - if (Stream != null) - { - Stream.Dispose(); - Stream = null; - } - } - } -} diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index b7a06b368..34464f6a2 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Dlna; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Model.Dlna; using System.Collections.Generic; namespace MediaBrowser.Controller.Dlna @@ -69,6 +70,6 @@ namespace MediaBrowser.Controller.Dlna /// </summary> /// <param name="filename">The filename.</param> /// <returns>DlnaIconResponse.</returns> - DlnaIconResponse GetIcon(string filename); + ImageStream GetIcon(string filename); } } diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index 3bd333527..8ac7d56d2 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -94,6 +94,6 @@ namespace MediaBrowser.Controller.Drawing /// Gets the supported image output formats. /// </summary> /// <returns>ImageOutputFormat[].</returns> - ImageOutputFormat[] GetSupportedImageOutputFormats(); + ImageFormat[] GetSupportedImageOutputFormats(); } } diff --git a/MediaBrowser.Controller/Drawing/ImageExtensions.cs b/MediaBrowser.Controller/Drawing/ImageExtensions.cs deleted file mode 100644 index 2511659c3..000000000 --- a/MediaBrowser.Controller/Drawing/ImageExtensions.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; - -namespace MediaBrowser.Controller.Drawing -{ - /// <summary> - /// Class ImageExtensions - /// </summary> - public static class ImageExtensions - { - /// <summary> - /// Saves the image. - /// </summary> - /// <param name="outputFormat">The output format.</param> - /// <param name="image">The image.</param> - /// <param name="toStream">To stream.</param> - /// <param name="quality">The quality.</param> - public static void Save(this Image image, System.Drawing.Imaging.ImageFormat outputFormat, Stream toStream, int quality) - { - // Use special save methods for jpeg and png that will result in a much higher quality image - // All other formats use the generic Image.Save - if (System.Drawing.Imaging.ImageFormat.Jpeg.Equals(outputFormat)) - { - SaveAsJpeg(image, toStream, quality); - } - else if (System.Drawing.Imaging.ImageFormat.Png.Equals(outputFormat)) - { - image.Save(toStream, System.Drawing.Imaging.ImageFormat.Png); - } - else - { - image.Save(toStream, outputFormat); - } - } - - /// <summary> - /// Saves the JPEG. - /// </summary> - /// <param name="image">The image.</param> - /// <param name="target">The target.</param> - /// <param name="quality">The quality.</param> - public static void SaveAsJpeg(this Image image, Stream target, int quality) - { - using (var encoderParameters = new EncoderParameters(1)) - { - encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality); - image.Save(target, GetImageCodecInfo("image/jpeg"), encoderParameters); - } - } - - private static readonly ImageCodecInfo[] Encoders = ImageCodecInfo.GetImageEncoders(); - - /// <summary> - /// Gets the image codec info. - /// </summary> - /// <param name="mimeType">Type of the MIME.</param> - /// <returns>ImageCodecInfo.</returns> - private static ImageCodecInfo GetImageCodecInfo(string mimeType) - { - foreach (var encoder in Encoders) - { - if (string.Equals(encoder.MimeType, mimeType, StringComparison.OrdinalIgnoreCase)) - { - return encoder; - } - } - - return Encoders.Length == 0 ? null : Encoders[0]; - } - - /// <summary> - /// Crops an image by removing whitespace and transparency from the edges - /// </summary> - /// <param name="bmp">The BMP.</param> - /// <returns>Bitmap.</returns> - /// <exception cref="System.Exception"></exception> - public static Bitmap CropWhitespace(this Bitmap bmp) - { - var width = bmp.Width; - var height = bmp.Height; - - var topmost = 0; - for (int row = 0; row < height; ++row) - { - if (IsAllWhiteRow(bmp, row, width)) - topmost = row; - else break; - } - - int bottommost = 0; - for (int row = height - 1; row >= 0; --row) - { - if (IsAllWhiteRow(bmp, row, width)) - bottommost = row; - else break; - } - - int leftmost = 0, rightmost = 0; - for (int col = 0; col < width; ++col) - { - if (IsAllWhiteColumn(bmp, col, height)) - leftmost = col; - else - break; - } - - for (int col = width - 1; col >= 0; --col) - { - if (IsAllWhiteColumn(bmp, col, height)) - rightmost = col; - else - break; - } - - if (rightmost == 0) rightmost = width; // As reached left - if (bottommost == 0) bottommost = height; // As reached top. - - var croppedWidth = rightmost - leftmost; - var croppedHeight = bottommost - topmost; - - if (croppedWidth == 0) // No border on left or right - { - leftmost = 0; - croppedWidth = width; - } - - if (croppedHeight == 0) // No border on top or bottom - { - topmost = 0; - croppedHeight = height; - } - - // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here - var thumbnail = new Bitmap(croppedWidth, croppedHeight, PixelFormat.Format32bppPArgb); - - // Preserve the original resolution - TrySetResolution(thumbnail, bmp.HorizontalResolution, bmp.VerticalResolution); - - using (var thumbnailGraph = Graphics.FromImage(thumbnail)) - { - thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality; - thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality; - thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic; - thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality; - thumbnailGraph.CompositingMode = CompositingMode.SourceCopy; - - thumbnailGraph.DrawImage(bmp, - new RectangleF(0, 0, croppedWidth, croppedHeight), - new RectangleF(leftmost, topmost, croppedWidth, croppedHeight), - GraphicsUnit.Pixel); - } - return thumbnail; - } - - /// <summary> - /// Tries the set resolution. - /// </summary> - /// <param name="bmp">The BMP.</param> - /// <param name="x">The x.</param> - /// <param name="y">The y.</param> - private static void TrySetResolution(Bitmap bmp, float x, float y) - { - if (x > 0 && y > 0) - { - bmp.SetResolution(x, y); - } - } - - /// <summary> - /// Determines whether or not a row of pixels is all whitespace - /// </summary> - /// <param name="bmp">The BMP.</param> - /// <param name="row">The row.</param> - /// <param name="width">The width.</param> - /// <returns><c>true</c> if [is all white row] [the specified BMP]; otherwise, <c>false</c>.</returns> - private static bool IsAllWhiteRow(Bitmap bmp, int row, int width) - { - for (var i = 0; i < width; ++i) - { - if (!IsWhiteSpace(bmp.GetPixel(i, row))) - { - return false; - } - } - return true; - } - - /// <summary> - /// Determines whether or not a column of pixels is all whitespace - /// </summary> - /// <param name="bmp">The BMP.</param> - /// <param name="col">The col.</param> - /// <param name="height">The height.</param> - /// <returns><c>true</c> if [is all white column] [the specified BMP]; otherwise, <c>false</c>.</returns> - private static bool IsAllWhiteColumn(Bitmap bmp, int col, int height) - { - for (var i = 0; i < height; ++i) - { - if (!IsWhiteSpace(bmp.GetPixel(col, i))) - { - return false; - } - } - return true; - } - - /// <summary> - /// Determines if a color is whitespace - /// </summary> - /// <param name="color">The color.</param> - /// <returns><c>true</c> if [is white space] [the specified color]; otherwise, <c>false</c>.</returns> - private static bool IsWhiteSpace(Color color) - { - return (color.R == 255 && color.G == 255 && color.B == 255) || color.A == 0; - } - } -} diff --git a/MediaBrowser.Controller/Drawing/ImageFormat.cs b/MediaBrowser.Controller/Drawing/ImageFormat.cs deleted file mode 100644 index f78562556..000000000 --- a/MediaBrowser.Controller/Drawing/ImageFormat.cs +++ /dev/null @@ -1,11 +0,0 @@ - -namespace MediaBrowser.Controller.Drawing -{ - public enum ImageFormat - { - Jpg, - Png, - Gif, - Bmp - } -} diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index b99186f37..d8f5d52c3 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Drawing public List<IImageEnhancer> Enhancers { get; set; } - public ImageOutputFormat OutputFormat { get; set; } + public ImageFormat OutputFormat { get; set; } public bool AddPlayedIndicator { get; set; } diff --git a/MediaBrowser.Controller/Drawing/ImageStream.cs b/MediaBrowser.Controller/Drawing/ImageStream.cs new file mode 100644 index 000000000..353abaca3 --- /dev/null +++ b/MediaBrowser.Controller/Drawing/ImageStream.cs @@ -0,0 +1,28 @@ +using MediaBrowser.Model.Drawing; +using System; +using System.IO; + +namespace MediaBrowser.Controller.Drawing +{ + public class ImageStream : IDisposable + { + /// <summary> + /// Gets or sets the stream. + /// </summary> + /// <value>The stream.</value> + public Stream Stream { get; set; } + /// <summary> + /// Gets or sets the format. + /// </summary> + /// <value>The format.</value> + public ImageFormat Format { get; set; } + + public void Dispose() + { + if (Stream != null) + { + Stream.Dispose(); + } + } + } +} diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 61b2caec0..7c7ec56d5 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -22,7 +22,8 @@ namespace MediaBrowser.Controller.Dto /// </summary> /// <param name="dto">The dto.</param> /// <param name="item">The item.</param> - void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item); + /// <param name="fields">The fields.</param> + void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item, List<ItemFields> fields); /// <summary> /// Gets the base item dto. @@ -35,6 +36,16 @@ namespace MediaBrowser.Controller.Dto BaseItemDto GetBaseItemDto(BaseItem item, List<ItemFields> fields, User user = null, BaseItem owner = null); /// <summary> + /// Gets the base item dto. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="options">The options.</param> + /// <param name="user">The user.</param> + /// <param name="owner">The owner.</param> + /// <returns>BaseItemDto.</returns> + BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null); + + /// <summary> /// Gets the chapter information dto. /// </summary> /// <param name="item">The item.</param> @@ -51,12 +62,13 @@ namespace MediaBrowser.Controller.Dto /// <summary> /// Gets the item by name dto. /// </summary> + /// <typeparam name="T"></typeparam> /// <param name="item">The item.</param> - /// <param name="fields">The fields.</param> + /// <param name="options">The options.</param> /// <param name="taggedItems">The tagged items.</param> /// <param name="user">The user.</param> /// <returns>BaseItemDto.</returns> - BaseItemDto GetItemByNameDto<T>(T item, List<ItemFields> fields, List<BaseItem> taggedItems, User user = null) + BaseItemDto GetItemByNameDto<T>(T item, DtoOptions options, List<BaseItem> taggedItems, User user = null) where T : BaseItem, IItemByName; } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 990ea49f6..e01b8857f 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -53,16 +53,6 @@ namespace MediaBrowser.Controller.Entities public static string ThemeSongFilename = "theme"; public static string ThemeVideosFolderName = "backdrops"; - public static List<KeyValuePair<string, ExtraType>> ExtraSuffixes = new List<KeyValuePair<string, ExtraType>> - { - new KeyValuePair<string,ExtraType>("-trailer", ExtraType.Trailer), - new KeyValuePair<string,ExtraType>("-deleted", ExtraType.DeletedScene), - new KeyValuePair<string,ExtraType>("-behindthescenes", ExtraType.BehindTheScenes), - new KeyValuePair<string,ExtraType>("-interview", ExtraType.Interview), - new KeyValuePair<string,ExtraType>("-scene", ExtraType.Scene), - new KeyValuePair<string,ExtraType>("-sample", ExtraType.Sample) - }; - public List<ItemImageInfo> ImageInfos { get; set; } [IgnoreDataMember] @@ -222,6 +212,20 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public virtual string FileNameWithoutExtension + { + get + { + if (LocationType == LocationType.FileSystem) + { + return System.IO.Path.GetFileNameWithoutExtension(Path); + } + + return null; + } + } + /// <summary> /// This is just a helper for convenience /// </summary> @@ -361,6 +365,15 @@ namespace MediaBrowser.Controller.Entities } } + public bool ContainsPerson(string name) + { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentNullException("name"); + } + return People.Any(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)); + } + public string GetInternalMetadataPath() { return GetInternalMetadataPath(ConfigurationManager.ApplicationPaths.InternalMetadataPath); @@ -594,118 +607,6 @@ namespace MediaBrowser.Controller.Entities } /// <summary> - /// Loads local trailers from the file system - /// </summary> - /// <returns>List{Video}.</returns> - private IEnumerable<Trailer> LoadLocalTrailers(List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService) - { - var files = fileSystemChildren.OfType<DirectoryInfo>() - .Where(i => string.Equals(i.Name, TrailerFolderName, StringComparison.OrdinalIgnoreCase)) - .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) - .ToList(); - - var extraTypes = new List<ExtraType> { ExtraType.Trailer }; - var suffixes = ExtraSuffixes.Where(i => extraTypes.Contains(i.Value)) - .Select(i => i.Key) - .ToList(); - - files.AddRange(fileSystemChildren.OfType<FileInfo>() - .Where(i => - { - var nameEithoutExtension = FileSystem.GetFileNameWithoutExtension(i); - - if (!suffixes.Any(s => nameEithoutExtension.EndsWith(s, StringComparison.OrdinalIgnoreCase))) - { - return false; - } - - return !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase); - })); - - return LibraryManager.ResolvePaths<Trailer>(files, directoryService, null).Select(video => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(video.Id) as Trailer; - - if (dbItem != null) - { - video = dbItem; - } - - if (video != null) - { - video.ExtraType = ExtraType.Trailer; - } - - return video; - - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path).ToList(); - } - - protected IEnumerable<Video> LoadSpecialFeatures(List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService) - { - var files = fileSystemChildren.OfType<DirectoryInfo>() - .Where(i => string.Equals(i.Name, "extras", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "specials", StringComparison.OrdinalIgnoreCase)) - .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)) - .ToList(); - - var extraTypes = new List<ExtraType> { ExtraType.BehindTheScenes, ExtraType.DeletedScene, ExtraType.Interview, ExtraType.Sample, ExtraType.Scene, ExtraType.Clip }; - var suffixes = ExtraSuffixes.Where(i => extraTypes.Contains(i.Value)) - .Select(i => i.Key) - .ToList(); - - files.AddRange(fileSystemChildren.OfType<FileInfo>() - .Where(i => - { - var nameEithoutExtension = FileSystem.GetFileNameWithoutExtension(i); - - if (!suffixes.Any(s => nameEithoutExtension.EndsWith(s, StringComparison.OrdinalIgnoreCase))) - { - return false; - } - - return !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase); - })); - - return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(video => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(video.Id) as Video; - - if (dbItem != null) - { - video = dbItem; - } - - if (video != null) - { - SetExtraTypeFromFilename(video); - } - - return video; - - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path).ToList(); - } - - private void SetExtraTypeFromFilename(Video item) - { - var name = System.IO.Path.GetFileNameWithoutExtension(item.Path) ?? string.Empty; - - foreach (var suffix in ExtraSuffixes) - { - if (name.EndsWith(suffix.Key, StringComparison.OrdinalIgnoreCase)) - { - item.ExtraType = suffix.Value; - return; - } - } - - item.ExtraType = ExtraType.Clip; - } - - /// <summary> /// Loads the theme songs. /// </summary> /// <returns>List{Audio.Audio}.</returns> @@ -721,7 +622,9 @@ namespace MediaBrowser.Controller.Entities .Where(i => string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase)) ); - return LibraryManager.ResolvePaths<Audio.Audio>(files, directoryService, null).Select(audio => + return LibraryManager.ResolvePaths(files, directoryService, null) + .OfType<Audio.Audio>() + .Select(audio => { // Try to retrieve it from the db. If we don't find it, use the resolved version var dbItem = LibraryManager.GetItemById(audio.Id) as Audio.Audio; @@ -731,10 +634,7 @@ namespace MediaBrowser.Controller.Entities audio = dbItem; } - if (audio != null) - { - audio.ExtraType = ExtraType.ThemeSong; - } + audio.ExtraType = ExtraType.ThemeSong; return audio; @@ -752,7 +652,9 @@ namespace MediaBrowser.Controller.Entities .Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase)) .SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly)); - return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(item => + return LibraryManager.ResolvePaths(files, directoryService, null) + .OfType<Video>() + .Select(item => { // Try to retrieve it from the db. If we don't find it, use the resolved version var dbItem = LibraryManager.GetItemById(item.Id) as Video; @@ -762,10 +664,7 @@ namespace MediaBrowser.Controller.Entities item = dbItem; } - if (item != null) - { - item.ExtraType = ExtraType.ThemeVideo; - } + item.ExtraType = ExtraType.ThemeVideo; return item; @@ -870,7 +769,8 @@ namespace MediaBrowser.Controller.Entities private async Task<bool> RefreshLocalTrailers(IHasTrailers item, MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - var newItems = LoadLocalTrailers(fileSystemChildren, options.DirectoryService).ToList(); + var newItems = LibraryManager.FindTrailers(this, fileSystemChildren, options.DirectoryService).ToList(); + var newItemIds = newItems.Select(i => i.Id).ToList(); var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds); @@ -995,6 +895,28 @@ namespace MediaBrowser.Controller.Entities return Id.ToString(); } + internal virtual bool IsValidFromResolver(BaseItem newItem) + { + var current = this; + + var currentAsPlaceHolder = current as ISupportsPlaceHolders; + + if (currentAsPlaceHolder != null) + { + var newHasPlaceHolder = newItem as ISupportsPlaceHolders; + + if (newHasPlaceHolder != null) + { + if (currentAsPlaceHolder.IsPlaceHolder != newHasPlaceHolder.IsPlaceHolder) + { + return false; + } + } + } + + return current.IsInMixedFolder == newItem.IsInMixedFolder; + } + /// <summary> /// Gets the preferred metadata language. /// </summary> @@ -1390,7 +1312,7 @@ namespace MediaBrowser.Controller.Entities /// <param name="resetPosition">if set to <c>true</c> [reset position].</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException"></exception> - public virtual async Task MarkPlayed(User user, + public virtual async Task MarkPlayed(User user, DateTime? datePlayed, bool resetPosition) { @@ -1778,7 +1700,8 @@ namespace MediaBrowser.Controller.Entities Name = Name, ProviderIds = ProviderIds, IndexNumber = IndexNumber, - ParentIndexNumber = ParentIndexNumber + ParentIndexNumber = ParentIndexNumber, + Year = ProductionYear }; } @@ -1820,9 +1743,42 @@ namespace MediaBrowser.Controller.Entities if (pct > 0) { pct = userData.PlaybackPositionTicks / pct; - dto.PlayedPercentage = 100 * pct; + + if (pct > 0) + { + dto.PlayedPercentage = 100 * pct; + } } } } + + protected Task RefreshMetadataForOwnedVideo(MetadataRefreshOptions options, string path, CancellationToken cancellationToken) + { + var newOptions = new MetadataRefreshOptions(options.DirectoryService) + { + ImageRefreshMode = options.ImageRefreshMode, + MetadataRefreshMode = options.MetadataRefreshMode, + ReplaceAllMetadata = options.ReplaceAllMetadata + }; + + var id = LibraryManager.GetNewItemId(path, typeof(Video)); + + // Try to retrieve it from the db. If we don't find it, use the resolved version + var video = LibraryManager.GetItemById(id) as Video; + + if (video == null) + { + video = LibraryManager.ResolvePath(new FileInfo(path)) as Video; + + newOptions.ForceSave = true; + } + + if (video == null) + { + return Task.FromResult(true); + } + + return video.RefreshMetadata(newOptions, cancellationToken); + } } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 34f52aac5..87ad9c380 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Progress; +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; @@ -59,6 +58,20 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override string FileNameWithoutExtension + { + get + { + if (LocationType == LocationType.FileSystem) + { + return System.IO.Path.GetFileName(Path); + } + + return null; + } + } + /// <summary> /// Gets or sets a value indicating whether this instance is physical root. /// </summary> @@ -103,7 +116,7 @@ namespace MediaBrowser.Controller.Entities if (item.Id == Guid.Empty) { - item.Id = item.Path.GetMBId(item.GetType()); + item.Id = LibraryManager.GetNewItemId(item.Path, item.GetType()); } if (ActualChildren.Any(i => i.Id == item.Id)) @@ -364,47 +377,7 @@ namespace MediaBrowser.Controller.Entities private bool IsValidFromResolver(BaseItem current, BaseItem newItem) { - var currentAsVideo = current as Video; - - if (currentAsVideo != null) - { - var newAsVideo = newItem as Video; - - if (newAsVideo != null) - { - if (currentAsVideo.IsPlaceHolder != newAsVideo.IsPlaceHolder) - { - return false; - } - if (currentAsVideo.IsMultiPart != newAsVideo.IsMultiPart) - { - return false; - } - if (currentAsVideo.HasLocalAlternateVersions != newAsVideo.HasLocalAlternateVersions) - { - return false; - } - } - } - else - { - var currentAsPlaceHolder = current as ISupportsPlaceHolders; - - if (currentAsPlaceHolder != null) - { - var newHasPlaceHolder = newItem as ISupportsPlaceHolders; - - if (newHasPlaceHolder != null) - { - if (currentAsPlaceHolder.IsPlaceHolder != newHasPlaceHolder.IsPlaceHolder) - { - return false; - } - } - } - } - - return current.IsInMixedFolder == newItem.IsInMixedFolder; + return current.IsValidFromResolver(newItem); } /// <summary> @@ -737,7 +710,7 @@ namespace MediaBrowser.Controller.Entities { var collectionType = LibraryManager.FindCollectionType(this); - return LibraryManager.ResolvePaths<BaseItem>(GetFileSystemChildren(directoryService), directoryService, this, collectionType); + return LibraryManager.ResolvePaths(GetFileSystemChildren(directoryService), directoryService, this, collectionType); } /// <summary> @@ -782,6 +755,12 @@ namespace MediaBrowser.Controller.Entities private BaseItem RetrieveChild(BaseItem child) { + if (child.Id == Guid.Empty) + { + Logger.Error("Item found with empty Id: " + (child.Path ?? child.Name)); + return null; + } + var item = LibraryManager.GetMemoryItemById(child.Id); if (item != null) diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index 062bdfa88..e4d032359 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -28,12 +28,14 @@ namespace MediaBrowser.Controller.Entities SoundtrackIds = new List<Guid>(); RemoteTrailers = new List<MediaUrl>(); LocalTrailerIds = new List<Guid>(); + RemoteTrailerIds = new List<Guid>(); ThemeSongIds = new List<Guid>(); ThemeVideoIds = new List<Guid>(); Tags = new List<string>(); } public List<Guid> LocalTrailerIds { get; set; } + public List<Guid> RemoteTrailerIds { get; set; } /// <summary> /// Gets or sets the tags. @@ -119,5 +121,16 @@ namespace MediaBrowser.Controller.Entities return id; } + + /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + public List<Guid> GetTrailerIds() + { + var list = LocalTrailerIds.ToList(); + list.AddRange(RemoteTrailerIds); + return list; + } } } diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index 5c523d2e3..5aafc8eb3 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -22,6 +22,12 @@ namespace MediaBrowser.Controller.Entities string Path { get; set; } /// <summary> + /// Gets the file name without extension. + /// </summary> + /// <value>The file name without extension.</value> + string FileNameWithoutExtension { get; } + + /// <summary> /// Gets the identifier. /// </summary> /// <value>The identifier.</value> diff --git a/MediaBrowser.Controller/Entities/IHasTrailers.cs b/MediaBrowser.Controller/Entities/IHasTrailers.cs index 47779064b..bc1c7d875 100644 --- a/MediaBrowser.Controller/Entities/IHasTrailers.cs +++ b/MediaBrowser.Controller/Entities/IHasTrailers.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { - public interface IHasTrailers + public interface IHasTrailers : IHasProviderIds { /// <summary> /// Gets or sets the remote trailers. @@ -17,5 +17,12 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The local trailer ids.</value> List<Guid> LocalTrailerIds { get; set; } + List<Guid> RemoteTrailerIds { get; set; } + + /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + List<Guid> GetTrailerIds(); } } diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 705cf9057..9dc600675 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -15,15 +15,19 @@ namespace MediaBrowser.Controller.Entities.Movies /// <summary> /// Class BoxSet /// </summary> - public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer + public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer, IHasShares { + public List<Share> Shares { get; set; } + public BoxSet() { RemoteTrailers = new List<MediaUrl>(); LocalTrailerIds = new List<Guid>(); + RemoteTrailerIds = new List<Guid>(); DisplayOrder = ItemSortBy.PremiereDate; Keywords = new List<string>(); + Shares = new List<Share>(); } protected override bool FilterLinkedChildrenPerUser @@ -35,6 +39,7 @@ namespace MediaBrowser.Controller.Entities.Movies } public List<Guid> LocalTrailerIds { get; set; } + public List<Guid> RemoteTrailerIds { get; set; } /// <summary> /// Gets or sets the remote trailers. @@ -76,6 +81,17 @@ namespace MediaBrowser.Controller.Entities.Movies } } + /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + public List<Guid> GetTrailerIds() + { + var list = LocalTrailerIds.ToList(); + list.AddRange(RemoteTrailerIds); + return list; + } + public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren) { var children = base.GetChildren(user, includeLinkedChildren); @@ -147,5 +163,20 @@ namespace MediaBrowser.Controller.Entities.Movies progress.Report(100); } + + public override bool IsVisible(User user) + { + if (base.IsVisible(user)) + { + var userId = user.Id.ToString("N"); + + return Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)) || + + // Need to support this for boxsets created prior to the creation of Shares + Shares.Count == 0; + } + + return false; + } } } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 686abdaf5..e749d89e4 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -36,6 +36,7 @@ namespace MediaBrowser.Controller.Entities.Movies SoundtrackIds = new List<Guid>(); RemoteTrailers = new List<MediaUrl>(); LocalTrailerIds = new List<Guid>(); + RemoteTrailerIds = new List<Guid>(); ThemeSongIds = new List<Guid>(); ThemeVideoIds = new List<Guid>(); BoxSetIdList = new List<Guid>(); @@ -49,6 +50,7 @@ namespace MediaBrowser.Controller.Entities.Movies public float? Metascore { get; set; } public List<Guid> LocalTrailerIds { get; set; } + public List<Guid> RemoteTrailerIds { get; set; } public List<string> Keywords { get; set; } public List<MediaUrl> RemoteTrailers { get; set; } @@ -90,6 +92,17 @@ namespace MediaBrowser.Controller.Entities.Movies public string TmdbCollectionName { get; set; } /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + public List<Guid> GetTrailerIds() + { + var list = LocalTrailerIds.ToList(); + list.AddRange(RemoteTrailerIds); + return list; + } + + /// <summary> /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> @@ -119,7 +132,7 @@ namespace MediaBrowser.Controller.Entities.Movies private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { - var newItems = LoadSpecialFeatures(fileSystemChildren, options.DirectoryService).ToList(); + var newItems = LibraryManager.FindExtras(this, fileSystemChildren, options.DirectoryService).ToList(); var newItemIds = newItems.Select(i => i.Id).ToList(); var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds); @@ -158,6 +171,22 @@ namespace MediaBrowser.Controller.Entities.Movies ProductionYear = yearInName; hasChanges = true; } + else + { + // Try to get the year from the folder name + if (!IsInMixedFolder) + { + info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); + + yearInName = info.Year; + + if (yearInName.HasValue) + { + ProductionYear = yearInName; + hasChanges = true; + } + } + } } return hasChanges; diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 015e4b4ae..d7cd62aa6 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -89,5 +89,41 @@ namespace MediaBrowser.Controller.Entities { return GetItemLookupInfo<MusicVideoInfo>(); } + + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + if (!ProductionYear.HasValue) + { + var info = LibraryManager.ParseName(Name); + + var yearInName = info.Year; + + if (yearInName.HasValue) + { + ProductionYear = yearInName; + hasChanges = true; + } + else + { + // Try to get the year from the folder name + if (!IsInMixedFolder) + { + info = LibraryManager.ParseName(System.IO.Path.GetFileName(ContainingFolderPath)); + + yearInName = info.Year; + + if (yearInName.HasValue) + { + ProductionYear = yearInName; + hasChanges = true; + } + } + } + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/Share.cs b/MediaBrowser.Controller/Entities/Share.cs new file mode 100644 index 000000000..e194f6238 --- /dev/null +++ b/MediaBrowser.Controller/Entities/Share.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Entities +{ + public interface IHasShares + { + List<Share> Shares { get; set; } + } + + public class Share + { + public string UserId { get; set; } + public bool CanEdit { get; set; } + } +} diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 3d1051b18..4c0d1fdfb 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -36,6 +36,7 @@ namespace MediaBrowser.Controller.Entities.TV SoundtrackIds = new List<Guid>(); RemoteTrailers = new List<MediaUrl>(); LocalTrailerIds = new List<Guid>(); + RemoteTrailerIds = new List<Guid>(); DisplaySpecialsWithSeasons = true; } @@ -57,7 +58,8 @@ namespace MediaBrowser.Controller.Entities.TV public bool DisplaySpecialsWithSeasons { get; set; } public List<Guid> LocalTrailerIds { get; set; } - + public List<Guid> RemoteTrailerIds { get; set; } + public List<MediaUrl> RemoteTrailers { get; set; } /// <summary> @@ -109,6 +111,17 @@ namespace MediaBrowser.Controller.Entities.TV return this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom) ?? base.GetUserDataKey(); } + /// <summary> + /// Gets the trailer ids. + /// </summary> + /// <returns>List<Guid>.</returns> + public List<Guid> GetTrailerIds() + { + var list = LocalTrailerIds.ToList(); + list.AddRange(RemoteTrailerIds); + return list; + } + // Studio, Genre and Rating will all be the same so makes no sense to index by these protected override IEnumerable<string> GetIndexByOptions() { diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index bbbf2358f..bb165d790 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -12,7 +12,8 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Class Trailer /// </summary> - public class Trailer : Video, IHasCriticRating, IHasSoundtracks, IHasProductionLocations, IHasBudget, IHasTrailers, IHasKeywords, IHasTaglines, IHasMetascore, IHasLookupInfo<TrailerInfo> + [Obsolete] + public class Trailer : Video, IHasCriticRating, IHasSoundtracks, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTaglines, IHasMetascore, IHasLookupInfo<TrailerInfo> { public List<Guid> SoundtrackIds { get; set; } @@ -23,15 +24,12 @@ namespace MediaBrowser.Controller.Entities RemoteTrailers = new List<MediaUrl>(); Taglines = new List<string>(); SoundtrackIds = new List<Guid>(); - LocalTrailerIds = new List<Guid>(); Keywords = new List<string>(); ProductionLocations = new List<string>(); } public float? Metascore { get; set; } - public List<Guid> LocalTrailerIds { get; set; } - public List<MediaUrl> RemoteTrailers { get; set; } public List<string> Keywords { get; set; } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 0bbd2eeca..3fa0a0435 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Connect; using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Users; using System; using System.IO; using System.Linq; @@ -287,7 +288,7 @@ namespace MediaBrowser.Controller.Entities var localTime = date.ToLocalTime(); - return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek) && + return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek) && IsWithinTime(schedule, localTime); } diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 7674dc1d3..926ffa19c 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -63,8 +63,7 @@ namespace MediaBrowser.Controller.Entities { CollectionType.Books, CollectionType.HomeVideos, - CollectionType.Photos, - CollectionType.Trailers + CollectionType.Photos }; var collectionFolder = folder as ICollectionFolder; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index aff4af468..166d56c51 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -1428,7 +1428,7 @@ namespace MediaBrowser.Controller.Entities var hasTrailers = item as IHasTrailers; if (hasTrailers != null) { - trailerCount = hasTrailers.LocalTrailerIds.Count; + trailerCount = hasTrailers.GetTrailerIds().Count; } var ok = val ? trailerCount > 0 : trailerCount == 0; diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 1c59b8bfb..6b098cbd8 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -1,12 +1,10 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -19,24 +17,23 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Class Video /// </summary> - public class Video : BaseItem, - IHasAspectRatio, - IHasTags, + public class Video : BaseItem, + IHasAspectRatio, + IHasTags, ISupportsPlaceHolders, IHasMediaSources, IHasShortOverview, IHasPreferredMetadataLanguage, IThemeMedia { - public bool IsMultiPart { get; set; } - public bool HasLocalAlternateVersions { get; set; } public Guid? PrimaryVersionId { get; set; } - public List<Guid> AdditionalPartIds { get; set; } - public List<Guid> LocalAlternateVersionIds { get; set; } + public List<string> AdditionalParts { get; set; } + public List<string> LocalAlternateVersions { get; set; } + public List<LinkedChild> LinkedAlternateVersions { get; set; } public bool IsThemeMedia { get; set; } - + public string FormatName { get; set; } public long? Size { get; set; } public string Container { get; set; } @@ -56,12 +53,12 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The timestamp.</value> public TransportStreamTimestamp? Timestamp { get; set; } - + public Video() { PlayableStreamFileNames = new List<string>(); - AdditionalPartIds = new List<Guid>(); - LocalAlternateVersionIds = new List<Guid>(); + AdditionalParts = new List<string>(); + LocalAlternateVersions = new List<string>(); Tags = new List<string>(); SubtitleFiles = new List<string>(); LinkedAlternateVersions = new List<LinkedChild>(); @@ -78,11 +75,31 @@ namespace MediaBrowser.Controller.Entities { get { - return LinkedAlternateVersions.Count + LocalAlternateVersionIds.Count + 1; + return LinkedAlternateVersions.Count + LocalAlternateVersions.Count + 1; } } - public List<LinkedChild> LinkedAlternateVersions { get; set; } + [IgnoreDataMember] + public bool IsStacked + { + get { return AdditionalParts.Count > 0; } + } + + [IgnoreDataMember] + public bool HasLocalAlternateVersions + { + get { return LocalAlternateVersions.Count > 0; } + } + + public IEnumerable<Guid> GetAdditionalPartIds() + { + return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video))); + } + + public IEnumerable<Guid> GetLocalAlternateVersionIds() + { + return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video))); + } /// <summary> /// Gets the linked children. @@ -90,7 +107,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>IEnumerable{BaseItem}.</returns> public IEnumerable<Video> GetAlternateVersions() { - var filesWithinSameDirectory = LocalAlternateVersionIds + var filesWithinSameDirectory = GetLocalAlternateVersionIds() .Select(i => LibraryManager.GetItemById(i)) .Where(i => i != null) .OfType<Video>(); @@ -116,7 +133,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>IEnumerable{Video}.</returns> public IEnumerable<Video> GetAdditionalParts() { - return AdditionalPartIds + return GetAdditionalPartIds() .Select(i => LibraryManager.GetItemById(i)) .Where(i => i != null) .OfType<Video>() @@ -200,7 +217,7 @@ namespace MediaBrowser.Controller.Entities { get { - if (IsMultiPart) + if (IsStacked) { return System.IO.Path.GetDirectoryName(Path); } @@ -218,6 +235,46 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public override string FileNameWithoutExtension + { + get + { + if (LocationType == LocationType.FileSystem) + { + if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd || VideoType == VideoType.HdDvd) + { + return System.IO.Path.GetFileName(Path); + } + + return System.IO.Path.GetFileNameWithoutExtension(Path); + } + + return null; + } + } + + internal override bool IsValidFromResolver(BaseItem newItem) + { + var current = this; + + var newAsVideo = newItem as Video; + + if (newAsVideo != null) + { + if (!current.AdditionalParts.SequenceEqual(newAsVideo.AdditionalParts, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + if (!current.LocalAlternateVersions.SequenceEqual(newAsVideo.LocalAlternateVersions, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + } + + return base.IsValidFromResolver(newItem); + } + public string MainFeaturePlaylistName { get; set; } /// <summary> @@ -263,37 +320,34 @@ namespace MediaBrowser.Controller.Entities { var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + if (IsStacked) + { + var tasks = AdditionalParts + .Select(i => RefreshMetadataForOwnedVideo(options, i, cancellationToken)); + + await Task.WhenAll(tasks).ConfigureAwait(false); + } + // Must have a parent to have additional parts or alternate versions // In other words, it must be part of the Parent/Child tree // The additional parts won't have additional parts themselves if (LocationType == LocationType.FileSystem && Parent != null) { - if (IsMultiPart) - { - var additionalPartsChanged = await RefreshAdditionalParts(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); - - if (additionalPartsChanged) - { - hasChanges = true; - } - } - else + if (!IsStacked) { RefreshLinkedAlternateVersions(); - var additionalPartsChanged = await RefreshAlternateVersionsWithinSameDirectory(options, fileSystemChildren, cancellationToken).ConfigureAwait(false); + var tasks = LocalAlternateVersions + .Select(i => RefreshMetadataForOwnedVideo(options, i, cancellationToken)); - if (additionalPartsChanged) - { - hasChanges = true; - } + await Task.WhenAll(tasks).ConfigureAwait(false); } } return hasChanges; } - private bool RefreshLinkedAlternateVersions() + private void RefreshLinkedAlternateVersions() { foreach (var child in LinkedAlternateVersions) { @@ -303,111 +357,13 @@ namespace MediaBrowser.Controller.Entities child.ItemId = null; } } - - return false; - } - - /// <summary> - /// Refreshes the additional parts. - /// </summary> - /// <param name="options">The options.</param> - /// <param name="fileSystemChildren">The file system children.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{System.Boolean}.</returns> - private async Task<bool> RefreshAdditionalParts(MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) - { - var newItems = LoadAdditionalParts(fileSystemChildren, options.DirectoryService).ToList(); - - var newItemIds = newItems.Select(i => i.Id).ToList(); - - var itemsChanged = !AdditionalPartIds.SequenceEqual(newItemIds); - - var tasks = newItems.Select(i => i.RefreshMetadata(options, cancellationToken)); - - await Task.WhenAll(tasks).ConfigureAwait(false); - - AdditionalPartIds = newItemIds; - - return itemsChanged; - } - - /// <summary> - /// Loads the additional parts. - /// </summary> - /// <returns>IEnumerable{Video}.</returns> - private IEnumerable<Video> LoadAdditionalParts(IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService) - { - var files = LibraryManager.GetAdditionalParts(Path, VideoType, fileSystemChildren); - - return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(video => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(video.Id) as Video; - - if (dbItem != null) - { - video = dbItem; - } - - return video; - - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path).ToList(); - } - - private async Task<bool> RefreshAlternateVersionsWithinSameDirectory(MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) - { - var newItems = HasLocalAlternateVersions ? - LoadAlternateVersionsWithinSameDirectory(fileSystemChildren, options.DirectoryService).ToList() : - new List<Video>(); - - var newItemIds = newItems.Select(i => i.Id).ToList(); - - var itemsChanged = !LocalAlternateVersionIds.SequenceEqual(newItemIds); - - var tasks = newItems.Select(i => RefreshAlternateVersion(options, i, cancellationToken)); - - await Task.WhenAll(tasks).ConfigureAwait(false); - - LocalAlternateVersionIds = newItemIds; - - return itemsChanged; - } - - private Task RefreshAlternateVersion(MetadataRefreshOptions options, Video video, CancellationToken cancellationToken) - { - var currentImagePath = video.GetImagePath(ImageType.Primary); - var ownerImagePath = this.GetImagePath(ImageType.Primary); - - var newOptions = new MetadataRefreshOptions(options.DirectoryService) - { - ImageRefreshMode = options.ImageRefreshMode, - MetadataRefreshMode = options.MetadataRefreshMode, - ReplaceAllMetadata = options.ReplaceAllMetadata - }; - - if (!string.Equals(currentImagePath, ownerImagePath, StringComparison.OrdinalIgnoreCase)) - { - newOptions.ForceSave = true; - - if (string.IsNullOrWhiteSpace(ownerImagePath)) - { - video.ImageInfos.Clear(); - } - else - { - video.SetImagePath(ImageType.Primary, ownerImagePath); - } - } - - return video.RefreshMetadata(newOptions, cancellationToken); } public override async Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken) { await base.UpdateToRepository(updateReason, cancellationToken).ConfigureAwait(false); - foreach (var item in LocalAlternateVersionIds.Select(i => LibraryManager.GetItemById(i))) + foreach (var item in GetLocalAlternateVersionIds().Select(i => LibraryManager.GetItemById(i))) { item.ImageInfos = ImageInfos; item.Overview = Overview; @@ -422,56 +378,6 @@ namespace MediaBrowser.Controller.Entities } } - /// <summary> - /// Loads the additional parts. - /// </summary> - /// <returns>IEnumerable{Video}.</returns> - private IEnumerable<Video> LoadAlternateVersionsWithinSameDirectory(IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService) - { - IEnumerable<FileSystemInfo> files; - - // Only support this for video files. For folder rips, they'll have to use the linking feature - if (VideoType == VideoType.VideoFile || VideoType == VideoType.Iso) - { - var path = Path; - - var filenamePrefix = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(path)); - - files = fileSystemChildren.Where(i => - { - if ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory) - { - return false; - } - - return !string.Equals(i.FullName, path, StringComparison.OrdinalIgnoreCase) && - LibraryManager.IsVideoFile(i.FullName) && - i.Name.StartsWith(filenamePrefix + " - ", StringComparison.OrdinalIgnoreCase); - }); - } - else - { - files = new List<FileSystemInfo>(); - } - - return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(video => - { - // Try to retrieve it from the db. If we don't find it, use the resolved version - var dbItem = LibraryManager.GetItemById(video.Id) as Video; - - if (dbItem != null) - { - video = dbItem; - } - - video.PrimaryVersionId = Id; - - return video; - - // Sort them so that the list can be easily compared for changes - }).OrderBy(i => i.Path).ToList(); - } - public override IEnumerable<string> GetDeletePaths() { if (!IsInMixedFolder) @@ -539,7 +445,7 @@ namespace MediaBrowser.Controller.Entities var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(); var locationType = i.LocationType; - + var info = new MediaSourceInfo { Id = i.Id.ToString("N"), diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 3367f98e4..33dea4dca 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -24,7 +24,9 @@ namespace MediaBrowser.Controller.Library /// <param name="parent">The parent.</param> /// <param name="collectionType">Type of the collection.</param> /// <returns>BaseItem.</returns> - BaseItem ResolvePath(FileSystemInfo fileInfo, Folder parent = null, string collectionType = null); + BaseItem ResolvePath(FileSystemInfo fileInfo, + Folder parent = null, + string collectionType = null); /// <summary> /// Resolves a set of files into a list of BaseItem @@ -35,8 +37,10 @@ namespace MediaBrowser.Controller.Library /// <param name="parent">The parent.</param> /// <param name="collectionType">Type of the collection.</param> /// <returns>List{``0}.</returns> - List<T> ResolvePaths<T>(IEnumerable<FileSystemInfo> files, IDirectoryService directoryService, Folder parent, string collectionType = null) - where T : BaseItem; + IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemInfo> files, + IDirectoryService directoryService, + Folder parent, string + collectionType = null); /// <summary> /// Gets the root folder. @@ -230,46 +234,6 @@ namespace MediaBrowser.Controller.Library BaseItem RetrieveItem(Guid id); /// <summary> - /// Validates the artists. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress); - - /// <summary> - /// Validates the music genres. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - Task ValidateMusicGenres(CancellationToken cancellationToken, IProgress<double> progress); - - /// <summary> - /// Validates the game genres. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - Task ValidateGameGenres(CancellationToken cancellationToken, IProgress<double> progress); - - /// <summary> - /// Validates the genres. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - Task ValidateGenres(CancellationToken cancellationToken, IProgress<double> progress); - - /// <summary> - /// Validates the studios. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> - Task ValidateStudios(CancellationToken cancellationToken, IProgress<double> progress); - - /// <summary> /// Occurs when [item added]. /// </summary> event EventHandler<ItemChangeEventArgs> ItemAdded; @@ -405,14 +369,31 @@ namespace MediaBrowser.Controller.Library ItemLookupInfo ParseName(string name); /// <summary> - /// Gets the additional parts. + /// Gets the new item identifier. /// </summary> - /// <param name="file">The file.</param> + /// <param name="key">The key.</param> /// <param name="type">The type.</param> - /// <param name="files">The files.</param> - /// <returns>IEnumerable<System.String>.</returns> - IEnumerable<FileSystemInfo> GetAdditionalParts(string file, - VideoType type, - IEnumerable<FileSystemInfo> files); + /// <returns>Guid.</returns> + Guid GetNewItemId(string key, Type type); + + /// <summary> + /// Finds the trailers. + /// </summary> + /// <param name="owner">The owner.</param> + /// <param name="fileSystemChildren">The file system children.</param> + /// <param name="directoryService">The directory service.</param> + /// <returns>IEnumerable<Trailer>.</returns> + IEnumerable<Video> FindTrailers(BaseItem owner, List<FileSystemInfo> fileSystemChildren, + IDirectoryService directoryService); + + /// <summary> + /// Finds the extras. + /// </summary> + /// <param name="owner">The owner.</param> + /// <param name="fileSystemChildren">The file system children.</param> + /// <param name="directoryService">The directory service.</param> + /// <returns>IEnumerable<Video>.</returns> + IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren, + IDirectoryService directoryService); } }
\ No newline at end of file diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs index 192ce2e83..f66f18401 100644 --- a/MediaBrowser.Controller/Library/IMusicManager.cs +++ b/MediaBrowser.Controller/Library/IMusicManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Playlists; using System.Collections.Generic; namespace MediaBrowser.Controller.Library @@ -28,6 +29,13 @@ namespace MediaBrowser.Controller.Library /// <returns>IEnumerable{Audio}.</returns> IEnumerable<Audio> GetInstantMixFromAlbum(MusicAlbum item, User user); /// <summary> + /// Gets the instant mix from playlist. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="user">The user.</param> + /// <returns>IEnumerable<Audio>.</returns> + IEnumerable<Audio> GetInstantMixFromPlaylist(Playlist item, User user); + /// <summary> /// Gets the instant mix from genre. /// </summary> /// <param name="genres">The genres.</param> diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index bd44f786f..debdafe4d 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -164,5 +164,19 @@ namespace MediaBrowser.Controller.Library /// <param name="pin">The pin.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> Task<PinRedeemResult> RedeemPasswordResetPin(string pin); + + /// <summary> + /// Gets the user policy. + /// </summary> + /// <param name="userId">The user identifier.</param> + /// <returns>UserPolicy.</returns> + UserPolicy GetUserPolicy(string userId); + + /// <summary> + /// Updates the user policy. + /// </summary> + /// <param name="userId">The user identifier.</param> + /// <param name="userPolicy">The user policy.</param> + Task UpdateUserPolicy(string userId, UserPolicy userPolicy); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs index eda69b164..993db0004 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Drawing; namespace MediaBrowser.Controller.LiveTv { @@ -109,7 +110,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="channelId">The channel identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{Stream}.</returns> - Task<StreamResponseInfo> GetChannelImageAsync(string channelId, CancellationToken cancellationToken); + Task<ImageStream> GetChannelImageAsync(string channelId, CancellationToken cancellationToken); /// <summary> /// Gets the recording image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to RecordingInfo @@ -117,7 +118,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="recordingId">The recording identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{ImageResponseInfo}.</returns> - Task<StreamResponseInfo> GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken); + Task<ImageStream> GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken); /// <summary> /// Gets the program image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to ProgramInfo @@ -126,7 +127,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="channelId">The channel identifier.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{ImageResponseInfo}.</returns> - Task<StreamResponseInfo> GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken); + Task<ImageStream> GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken); /// <summary> /// Gets the recordings asynchronous. diff --git a/MediaBrowser.Controller/LiveTv/StreamResponseInfo.cs b/MediaBrowser.Controller/LiveTv/StreamResponseInfo.cs deleted file mode 100644 index b133874d0..000000000 --- a/MediaBrowser.Controller/LiveTv/StreamResponseInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using MediaBrowser.Controller.Drawing; -using System.IO; - -namespace MediaBrowser.Controller.LiveTv -{ - public class StreamResponseInfo - { - /// <summary> - /// Gets or sets the stream. - /// </summary> - /// <value>The stream.</value> - public Stream Stream { get; set; } - - /// <summary> - /// Gets or sets the type of the MIME. - /// </summary> - /// <value>The type of the MIME.</value> - public ImageFormat Format { get; set; } - } -} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 1c8a588f6..c198a58d4 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -55,7 +55,6 @@ <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Data" /> - <Reference Include="System.Drawing" /> <Reference Include="System.Net" /> <Reference Include="System.Runtime.Serialization" /> <Reference Include="Microsoft.CSharp" /> @@ -106,7 +105,6 @@ <Compile Include="Devices\IDeviceRepository.cs" /> <Compile Include="Dlna\ControlRequest.cs" /> <Compile Include="Dlna\ControlResponse.cs" /> - <Compile Include="Dlna\DlnaIconResponse.cs" /> <Compile Include="Dlna\EventSubscriptionResponse.cs" /> <Compile Include="Dlna\IConnectionManager.cs" /> <Compile Include="Dlna\IContentDirectory.cs" /> @@ -114,9 +112,9 @@ <Compile Include="Dlna\IEventManager.cs" /> <Compile Include="Dlna\IUpnpService.cs" /> <Compile Include="Drawing\IImageProcessor.cs" /> - <Compile Include="Drawing\ImageFormat.cs" /> <Compile Include="Drawing\ImageProcessingOptions.cs" /> <Compile Include="Drawing\ImageProcessorExtensions.cs" /> + <Compile Include="Drawing\ImageStream.cs" /> <Compile Include="Dto\IDtoService.cs" /> <Compile Include="Entities\AdultVideo.cs" /> <Compile Include="Entities\Audio\IHasAlbumArtist.cs" /> @@ -164,6 +162,7 @@ <Compile Include="Entities\IHasAwards.cs" /> <Compile Include="Entities\Photo.cs" /> <Compile Include="Entities\PhotoAlbum.cs" /> + <Compile Include="Entities\Share.cs" /> <Compile Include="Entities\UserView.cs" /> <Compile Include="Entities\UserViewBuilder.cs" /> <Compile Include="FileOrganization\IFileOrganizationService.cs" /> @@ -192,7 +191,6 @@ <Compile Include="LiveTv\LiveTvException.cs" /> <Compile Include="LiveTv\LiveTvServiceStatusInfo.cs" /> <Compile Include="LiveTv\LiveTvTunerInfo.cs" /> - <Compile Include="LiveTv\StreamResponseInfo.cs" /> <Compile Include="LiveTv\LiveTvProgram.cs" /> <Compile Include="LiveTv\LiveTvVideoRecording.cs" /> <Compile Include="LiveTv\ProgramInfo.cs" /> @@ -270,7 +268,6 @@ <Compile Include="Providers\MetadataStatus.cs" /> <Compile Include="Providers\ISeriesOrderManager.cs" /> <Compile Include="Session\ISessionManager.cs" /> - <Compile Include="Drawing\ImageExtensions.cs" /> <Compile Include="Entities\AggregateFolder.cs" /> <Compile Include="Entities\Audio\Audio.cs" /> <Compile Include="Entities\Audio\MusicAlbum.cs" /> diff --git a/MediaBrowser.Controller/Persistence/IUserRepository.cs b/MediaBrowser.Controller/Persistence/IUserRepository.cs index 0241b8c03..80961a369 100644 --- a/MediaBrowser.Controller/Persistence/IUserRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserRepository.cs @@ -11,12 +11,6 @@ namespace MediaBrowser.Controller.Persistence public interface IUserRepository : IRepository { /// <summary> - /// Opens the connection to the repository - /// </summary> - /// <returns>Task.</returns> - Task Initialize(); - - /// <summary> /// Deletes the user. /// </summary> /// <param name="user">The user.</param> diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 75e1bbde7..e48cddaaa 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -11,10 +11,17 @@ using System.Runtime.Serialization; namespace MediaBrowser.Controller.Playlists { - public class Playlist : Folder + public class Playlist : Folder, IHasShares { public string OwnerUserId { get; set; } + public List<Share> Shares { get; set; } + + public Playlist() + { + Shares = new List<Share>(); + } + [IgnoreDataMember] protected override bool FilterLinkedChildrenPerUser { @@ -166,7 +173,15 @@ namespace MediaBrowser.Controller.Playlists public override bool IsVisible(User user) { - return base.IsVisible(user) && string.Equals(user.Id.ToString("N"), OwnerUserId); + if (base.IsVisible(user)) + { + var userId = user.Id.ToString("N"); + + return Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)) || + string.Equals(OwnerUserId, userId, StringComparison.OrdinalIgnoreCase); + } + + return false; } } } diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 0a1c0938a..a37f7eb8a 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -819,6 +819,19 @@ namespace MediaBrowser.Controller.Providers break; } + case "Shares": + { + using (var subtree = reader.ReadSubtree()) + { + var hasShares = item as IHasShares; + if (hasShares != null) + { + FetchFromSharesNode(subtree, hasShares); + } + } + break; + } + case "Format3D": { var video = item as Video; @@ -853,6 +866,71 @@ namespace MediaBrowser.Controller.Providers } } + private void FetchFromSharesNode(XmlReader reader, IHasShares item) + { + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Share": + { + using (var subtree = reader.ReadSubtree()) + { + var share = GetShareFromNode(subtree); + if (share != null) + { + item.Shares.Add(share); + } + } + break; + } + + default: + reader.Skip(); + break; + } + } + } + } + + private Share GetShareFromNode(XmlReader reader) + { + var share = new Share(); + + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "UserId": + { + share.UserId = reader.ReadElementContentAsString(); + break; + } + + case "CanEdit": + { + share.CanEdit = string.Equals(reader.ReadElementContentAsString(), true.ToString(), StringComparison.OrdinalIgnoreCase); + break; + } + + default: + reader.Skip(); + break; + } + } + } + + return share; + } + private void FetchFromCountriesNode(XmlReader reader, T item) { reader.MoveToContent(); @@ -1340,6 +1418,12 @@ namespace MediaBrowser.Controller.Providers } } + // This is valid + if (!string.IsNullOrWhiteSpace(linkedItem.Path)) + { + return linkedItem; + } + return string.IsNullOrWhiteSpace(linkedItem.ItemName) || string.IsNullOrWhiteSpace(linkedItem.ItemType) ? null : linkedItem; } diff --git a/MediaBrowser.Controller/Providers/IImageEnhancer.cs b/MediaBrowser.Controller/Providers/IImageEnhancer.cs index ae605ec0d..56f8d02be 100644 --- a/MediaBrowser.Controller/Providers/IImageEnhancer.cs +++ b/MediaBrowser.Controller/Providers/IImageEnhancer.cs @@ -1,7 +1,7 @@ -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; -using System.Drawing; using System.Threading.Tasks; namespace MediaBrowser.Controller.Providers @@ -49,6 +49,6 @@ namespace MediaBrowser.Controller.Providers /// <param name="imageIndex">Index of the image.</param> /// <returns>Task{Image}.</returns> /// <exception cref="System.ArgumentNullException"></exception> - Task<Image> EnhanceImageAsync(IHasImages item, Image originalImage, ImageType imageType, int imageIndex); + Task<ImageStream> EnhanceImageAsync(IHasImages item, ImageStream originalImage, ImageType imageType, int imageIndex); } }
\ No newline at end of file diff --git a/MediaBrowser.Controller/Providers/IImageSaver.cs b/MediaBrowser.Controller/Providers/IImageSaver.cs index 5516c08f6..a983de63e 100644 --- a/MediaBrowser.Controller/Providers/IImageSaver.cs +++ b/MediaBrowser.Controller/Providers/IImageSaver.cs @@ -1,5 +1,5 @@ -using MediaBrowser.Controller.Drawing; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs index 68afb84b8..d1345d7a6 100644 --- a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs +++ b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs @@ -1,5 +1,5 @@ -using MediaBrowser.Controller.Drawing; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Resolvers/IItemResolver.cs b/MediaBrowser.Controller/Resolvers/IItemResolver.cs index 780d5d013..fec6be55c 100644 --- a/MediaBrowser.Controller/Resolvers/IItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/IItemResolver.cs @@ -1,5 +1,8 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using System.Collections.Generic; +using System.IO; namespace MediaBrowser.Controller.Resolvers { @@ -20,4 +23,24 @@ namespace MediaBrowser.Controller.Resolvers /// <value>The priority.</value> ResolverPriority Priority { get; } } + + public interface IMultiItemResolver + { + MultiItemResolverResult ResolveMultiple(Folder parent, + List<FileSystemInfo> files, + string collectionType, + IDirectoryService directoryService); + } + + public class MultiItemResolverResult + { + public List<BaseItem> Items { get; set; } + public List<FileSystemInfo> ExtraFiles { get; set; } + + public MultiItemResolverResult() + { + Items = new List<BaseItem>(); + ExtraFiles = new List<FileSystemInfo>(); + } + } } diff --git a/MediaBrowser.Controller/Sync/ISyncManager.cs b/MediaBrowser.Controller/Sync/ISyncManager.cs index 1e744a087..31c3c0c6d 100644 --- a/MediaBrowser.Controller/Sync/ISyncManager.cs +++ b/MediaBrowser.Controller/Sync/ISyncManager.cs @@ -1,6 +1,5 @@ -using System.IO; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Devices; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Sync; using System.Collections.Generic; @@ -29,7 +28,7 @@ namespace MediaBrowser.Controller.Sync /// <param name="id">The identifier.</param> /// <returns>SyncJob.</returns> SyncJob GetJob(string id); - + /// <summary> /// Cancels the job. /// </summary> @@ -53,5 +52,12 @@ namespace MediaBrowser.Controller.Sync /// <param name="item">The item.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> bool SupportsSync(BaseItem item); + + /// <summary> + /// Gets the device profile. + /// </summary> + /// <param name="targetId">The target identifier.</param> + /// <returns>DeviceProfile.</returns> + DeviceProfile GetDeviceProfile(string targetId); } } diff --git a/MediaBrowser.Controller/Sync/ISyncRepository.cs b/MediaBrowser.Controller/Sync/ISyncRepository.cs index 9cce69bdc..f1bcd7f07 100644 --- a/MediaBrowser.Controller/Sync/ISyncRepository.cs +++ b/MediaBrowser.Controller/Sync/ISyncRepository.cs @@ -28,6 +28,13 @@ namespace MediaBrowser.Controller.Sync Task Update(SyncJob job); /// <summary> + /// Deletes the job. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Task.</returns> + Task DeleteJob(string id); + + /// <summary> /// Gets the jobs. /// </summary> /// <param name="query">The query.</param> @@ -54,5 +61,12 @@ namespace MediaBrowser.Controller.Sync /// <param name="jobItem">The job item.</param> /// <returns>Task.</returns> Task Update(SyncJobItem jobItem); + + /// <summary> + /// Gets the job items. + /// </summary> + /// <param name="query">The query.</param> + /// <returns>IEnumerable<SyncJobItem>.</returns> + QueryResult<SyncJobItem> GetJobItems(SyncJobItemQuery query); } } |
