diff options
| author | Luke <luke.pulverenti@gmail.com> | 2015-02-09 16:58:30 -0500 |
|---|---|---|
| committer | Luke <luke.pulverenti@gmail.com> | 2015-02-09 16:58:30 -0500 |
| commit | 4cc3b2f0ccd7c092a4acf72db4903415e175037a (patch) | |
| tree | f9f90f8665b726253b8b357674f2f141aa43abc9 /MediaBrowser.Controller | |
| parent | e7037a9b80843c127712f11430239f8fa3cb4aed (diff) | |
| parent | 3d7089a7dbabb652730c892206ca050f52f832b1 (diff) | |
Merge pull request #1005 from MediaBrowser/dev
3.0.5518.0
Diffstat (limited to 'MediaBrowser.Controller')
78 files changed, 1315 insertions, 1106 deletions
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 5a9fc3322..b6514ca0a 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -14,9 +15,19 @@ namespace MediaBrowser.Controller.Channels public override bool IsVisible(User user) { - if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) + if (user.Policy.BlockedChannels != null) { - return false; + if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) + { + return false; + } + } + else + { + if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) + { + return false; + } } return base.IsVisible(user); @@ -50,7 +61,22 @@ namespace MediaBrowser.Controller.Channels protected override string GetInternalMetadataPath(string basePath) { - return System.IO.Path.Combine(basePath, "channels", Id.ToString("N"), "metadata"); + return GetInternalMetadataPath(basePath, Id); + } + + public static string GetInternalMetadataPath(string basePath, Guid id) + { + return System.IO.Path.Combine(basePath, "channels", id.ToString("N"), "metadata"); + } + + public override bool CanDelete() + { + return false; + } + + protected override bool IsAllowTagFilterEnforced() + { + return false; } } } diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs index 896d598bb..91b2407be 100644 --- a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs @@ -3,10 +3,10 @@ using MediaBrowser.Model.Channels; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System.Collections.Generic; using System.Linq; using System.Threading; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Channels return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent); } - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return ExternalId; } @@ -89,5 +89,10 @@ namespace MediaBrowser.Controller.Channels return list; } + + public override bool CanDelete() + { + return false; + } } } diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs index 8482e38df..7ba73d126 100644 --- a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs @@ -1,11 +1,10 @@ -using System; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Channels; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Users; +using System; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -40,7 +39,7 @@ namespace MediaBrowser.Controller.Channels return false; } - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return ExternalId; } @@ -76,5 +75,10 @@ namespace MediaBrowser.Controller.Channels { return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N")); } + + public override bool CanDelete() + { + return false; + } } } diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs index f0eafcbdf..d7d4483cd 100644 --- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs @@ -4,11 +4,11 @@ using MediaBrowser.Model.Channels; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -28,8 +28,8 @@ namespace MediaBrowser.Controller.Channels public string OriginalImageUrl { get; set; } public List<ChannelMediaInfo> ChannelMediaSources { get; set; } - - public override string GetUserDataKey() + + protected override string CreateUserDataKey() { if (ContentType == ChannelMediaContentType.MovieExtra) { @@ -119,5 +119,10 @@ namespace MediaBrowser.Controller.Channels { return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N")); } + + public override bool CanDelete() + { + return false; + } } } diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index 9130f68d4..89e505579 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -60,5 +60,12 @@ namespace MediaBrowser.Controller.Collections /// <param name="userId">The user identifier.</param> /// <returns>Folder.</returns> Folder GetCollectionsFolder(string userId); + + /// <summary> + /// Gets the collections. + /// </summary> + /// <param name="user">The user.</param> + /// <returns>IEnumerable<BoxSet>.</returns> + IEnumerable<BoxSet> GetCollections(User user); } } diff --git a/MediaBrowser.Controller/Devices/CameraImageUploadInfo.cs b/MediaBrowser.Controller/Devices/CameraImageUploadInfo.cs new file mode 100644 index 000000000..b3f3bb902 --- /dev/null +++ b/MediaBrowser.Controller/Devices/CameraImageUploadInfo.cs @@ -0,0 +1,10 @@ +using MediaBrowser.Model.Devices; + +namespace MediaBrowser.Controller.Devices +{ + public class CameraImageUploadInfo + { + public LocalFileInfo FileInfo { get; set; } + public DeviceInfo Device { get; set; } + } +} diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index f5010bb45..78eebd994 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -3,7 +3,6 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; using System; -using System.Collections.Generic; using System.IO; using System.Threading.Tasks; @@ -15,6 +14,10 @@ namespace MediaBrowser.Controller.Devices /// Occurs when [device options updated]. /// </summary> event EventHandler<GenericEventArgs<DeviceInfo>> DeviceOptionsUpdated; + /// <summary> + /// Occurs when [camera image uploaded]. + /// </summary> + event EventHandler<GenericEventArgs<CameraImageUploadInfo>> CameraImageUploaded; /// <summary> /// Registers the device. diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index 34464f6a2..2f64cd194 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -62,8 +62,9 @@ namespace MediaBrowser.Controller.Dlna /// </summary> /// <param name="headers">The headers.</param> /// <param name="serverUuId">The server uu identifier.</param> + /// <param name="serverAddress">The server address.</param> /// <returns>System.String.</returns> - string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId); + string GetServerDescriptionXml(IDictionary<string, string> headers, string serverUuId, string serverAddress); /// <summary> /// Gets the icon. diff --git a/MediaBrowser.Controller/Dlna/IMediaReceiverRegistrar.cs b/MediaBrowser.Controller/Dlna/IMediaReceiverRegistrar.cs new file mode 100644 index 000000000..6b76783a5 --- /dev/null +++ b/MediaBrowser.Controller/Dlna/IMediaReceiverRegistrar.cs @@ -0,0 +1,7 @@ + +namespace MediaBrowser.Controller.Dlna +{ + public interface IMediaReceiverRegistrar : IEventManager, IUpnpService + { + } +} diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs index eeb4fc114..a8d1b1862 100644 --- a/MediaBrowser.Controller/Dto/DtoOptions.cs +++ b/MediaBrowser.Controller/Dto/DtoOptions.cs @@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Dto public List<ImageType> ImageTypes { get; set; } public int ImageTypeLimit { get; set; } public bool EnableImages { get; set; } + public string DeviceId { get; set; } public DtoOptions() { diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 7c7ec56d5..ea311d993 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -44,6 +44,17 @@ namespace MediaBrowser.Controller.Dto /// <param name="owner">The owner.</param> /// <returns>BaseItemDto.</returns> BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null); + + /// <summary> + /// Gets the base item dtos. + /// </summary> + /// <param name="items">The items.</param> + /// <param name="options">The options.</param> + /// <param name="user">The user.</param> + /// <param name="owner">The owner.</param> + /// <returns>IEnumerable<BaseItemDto>.</returns> + IEnumerable<BaseItemDto> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null, + BaseItem owner = null); /// <summary> /// Gets the chapter information dto. diff --git a/MediaBrowser.Controller/Entities/AdultVideo.cs b/MediaBrowser.Controller/Entities/AdultVideo.cs deleted file mode 100644 index 6c3f7851e..000000000 --- a/MediaBrowser.Controller/Entities/AdultVideo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace MediaBrowser.Controller.Entities -{ - [Obsolete] - public class AdultVideo : Video, IHasProductionLocations, IHasTaglines - { - public List<string> ProductionLocations { get; set; } - - public List<string> Taglines { get; set; } - - public AdultVideo() - { - Taglines = new List<string>(); - ProductionLocations = new List<string>(); - } - } -} diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 362096b5e..66a0d551b 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -32,6 +32,11 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// The _virtual children /// </summary> @@ -66,7 +71,7 @@ namespace MediaBrowser.Controller.Entities { var path = ContainingFolderPath; - var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager, directoryService) + var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths , directoryService) { FileInfo = new DirectoryInfo(path), Path = path, diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index c5ed09016..902447999 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -4,11 +4,11 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -81,6 +81,15 @@ namespace MediaBrowser.Controller.Entities.Audio } [IgnoreDataMember] + protected override bool SupportsOwnedItems + { + get + { + return false; + } + } + + [IgnoreDataMember] public override Folder LatestItemsIndexContainer { get @@ -104,6 +113,13 @@ namespace MediaBrowser.Controller.Entities.Audio } } + public override bool CanDownload() + { + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + /// <summary> /// Gets or sets the artist. /// </summary> @@ -169,7 +185,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var parent = FindParent<MusicAlbum>(); @@ -186,7 +202,7 @@ namespace MediaBrowser.Controller.Entities.Audio } } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) @@ -223,7 +239,7 @@ namespace MediaBrowser.Controller.Entities.Audio { Id = i.Id.ToString("N"), Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File, - MediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(), + MediaStreams = MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(), Name = i.Name, Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path, RunTimeTicks = i.RunTimeTicks, diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 90edfcce7..e3f523b5a 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -1,11 +1,11 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -52,14 +52,14 @@ namespace MediaBrowser.Controller.Entities.Audio } } - public List<string> AlbumArtists { get; set; } - [IgnoreDataMember] public string AlbumArtist { get { return AlbumArtists.FirstOrDefault(); } } + public List<string> AlbumArtists { get; set; } + /// <summary> /// Gets the tracks. /// </summary> @@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Entities.Audio { get { - return RecursiveChildren.OfType<Audio>(); + return GetRecursiveChildren(i => i is Audio).Cast<Audio>(); } } @@ -136,7 +136,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var id = this.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup); @@ -152,7 +152,7 @@ namespace MediaBrowser.Controller.Entities.Audio return "MusicAlbum-Musicbrainz-" + id; } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) @@ -173,17 +173,12 @@ namespace MediaBrowser.Controller.Entities.Audio id.ArtistProviderIds = artist.ProviderIds; } - id.SongInfos = RecursiveChildren.OfType<Audio>() + id.SongInfos = GetRecursiveChildren(i => i is Audio) + .Cast<Audio>() .Select(i => i.GetLookupInfo()) .ToList(); return id; } } - - [Obsolete] - public class MusicAlbumDisc : Folder - { - - } } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index a60258d1a..e65d3c0e7 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -1,14 +1,13 @@ -using System.Runtime.Serialization; -using MediaBrowser.Common.Progress; -using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -19,7 +18,8 @@ namespace MediaBrowser.Controller.Entities.Audio { public bool IsAccessedByName { get; set; } public List<string> ProductionLocations { get; set; } - + + [IgnoreDataMember] public override bool IsFolder { get @@ -34,6 +34,11 @@ namespace MediaBrowser.Controller.Entities.Audio get { return true; } } + public override bool CanDelete() + { + return !IsAccessedByName; + } + protected override IEnumerable<BaseItem> ActualChildren { get @@ -68,7 +73,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return GetUserDataKey(this); } @@ -78,6 +83,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -90,6 +96,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -122,89 +129,53 @@ namespace MediaBrowser.Controller.Entities.Audio public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) { - var items = RecursiveChildren.ToList(); + var items = GetRecursiveChildren().ToList(); var songs = items.OfType<Audio>().ToList(); var others = items.Except(songs).ToList(); var totalItems = songs.Count + others.Count; - var percentages = new Dictionary<Guid, double>(totalItems); - - var tasks = new List<Task>(); + var numComplete = 0; // Refresh songs foreach (var item in songs) { - if (tasks.Count >= 2) - { - await Task.WhenAll(tasks).ConfigureAwait(false); - tasks.Clear(); - } - cancellationToken.ThrowIfCancellationRequested(); - var innerProgress = new ActionableProgress<double>(); - // Avoid implicitly captured closure - var currentChild = item; - innerProgress.RegisterAction(p => - { - lock (percentages) - { - percentages[currentChild.Id] = p / 100; - - var percent = percentages.Values.Sum(); - percent /= totalItems; - percent *= 100; - progress.Report(percent); - } - }); - - var taskChild = item; - tasks.Add(Task.Run(async () => await RefreshItem(taskChild, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken)); - } + await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - await Task.WhenAll(tasks).ConfigureAwait(false); - tasks.Clear(); + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); + } // Refresh current item await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - + // Refresh all non-songs foreach (var item in others) { cancellationToken.ThrowIfCancellationRequested(); - // Avoid implicitly captured closure - var currentChild = item; - await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - lock (percentages) - { - percentages[currentChild.Id] = 1; - var percent = percentages.Values.Sum(); - percent /= totalItems; - percent *= 100; - progress.Report(percent); - } + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); } progress.Report(100); } - private async Task RefreshItem(BaseItem item, MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) - { - await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - - progress.Report(100); - } - public ArtistInfo GetLookupInfo() { var info = GetItemLookupInfo<ArtistInfo>(); - info.SongInfos = RecursiveChildren.OfType<Audio>() + info.SongInfos = GetRecursiveChildren(i => i is Audio) + .Cast<Audio>() .Select(i => i.GetLookupInfo()) .ToList(); @@ -213,9 +184,16 @@ namespace MediaBrowser.Controller.Entities.Audio public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.OfType<IHasArtist>() - .Where(i => i.HasArtist(Name)) - .Cast<BaseItem>(); + return inputItems.Where(GetItemFilter()); + } + + public Func<BaseItem, bool> GetItemFilter() + { + return i => + { + var hasArtist = i as IHasArtist; + return hasArtist != null && hasArtist.HasArtist(Name); + }; } } } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index 928eb6463..ed0956073 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "MusicGenre-" + Name; } @@ -30,6 +30,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -38,10 +39,16 @@ namespace MediaBrowser.Controller.Entities.Audio } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -52,7 +59,12 @@ namespace MediaBrowser.Controller.Entities.Audio public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => (i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase)); + return inputItems.Where(GetItemFilter()); + } + + public Func<BaseItem, bool> GetItemFilter() + { + return i => (i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase); } } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index ee562d8b4..3ab02ea21 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -239,6 +239,38 @@ namespace MediaBrowser.Controller.Entities get { return this.GetImagePath(ImageType.Primary); } } + public virtual bool CanDelete() + { + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + + public virtual bool IsAuthorizedToDelete(User user) + { + return user.Policy.EnableContentDeletion; + } + + public bool CanDelete(User user) + { + return CanDelete() && IsAuthorizedToDelete(user); + } + + public virtual bool CanDownload() + { + return false; + } + + public virtual bool IsAuthorizedToDownload(User user) + { + return user.Policy.EnableContentDownloading; + } + + public bool CanDownload(User user) + { + return CanDownload() && IsAuthorizedToDownload(user); + } + /// <summary> /// Gets or sets the date created. /// </summary> @@ -268,6 +300,7 @@ namespace MediaBrowser.Controller.Entities public static IChannelManager ChannelManager { get; set; } public static ICollectionManager CollectionManager { get; set; } public static IImageProcessor ImageProcessor { get; set; } + public static IMediaSourceManager MediaSourceManager { get; set; } /// <summary> /// Returns a <see cref="System.String" /> that represents this instance. @@ -359,7 +392,7 @@ namespace MediaBrowser.Controller.Entities { get { - if (!string.IsNullOrEmpty(ForcedSortName)) + if (!string.IsNullOrWhiteSpace(ForcedSortName)) { return ForcedSortName; } @@ -379,21 +412,19 @@ namespace MediaBrowser.Controller.Entities public string GetInternalMetadataPath() { - return GetInternalMetadataPath(ConfigurationManager.ApplicationPaths.InternalMetadataPath); + var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath; + + return GetInternalMetadataPath(basePath); } protected virtual string GetInternalMetadataPath(string basePath) { var idString = Id.ToString("N"); - return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString); - } - - public static string GetInternalMetadataPathForId(Guid id) - { - var idString = id.ToString("N"); - - var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath; + if (ConfigurationManager.Configuration.EnableLibraryMetadataSubFolder) + { + basePath = System.IO.Path.Combine(basePath, "library"); + } return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString); } @@ -692,7 +723,7 @@ namespace MediaBrowser.Controller.Entities var requiresSave = false; - if (IsFolder || Parent != null) + if (SupportsOwnedItems) { try { @@ -724,6 +755,12 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + protected virtual bool SupportsOwnedItems + { + get { return IsFolder || Parent != null; } + } + /// <summary> /// Refreshes owned items such as trailers, theme videos, special features, etc. /// Returns true or false indicating if changes were found. @@ -889,11 +926,24 @@ namespace MediaBrowser.Controller.Entities get { return null; } } + private string _userDataKey; /// <summary> /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public virtual string GetUserDataKey() + public string GetUserDataKey() + { + if (string.IsNullOrWhiteSpace(_userDataKey)) + { + var key = CreateUserDataKey(); + _userDataKey = key; + return key; + } + + return _userDataKey; + } + + protected virtual string CreateUserDataKey() { return Id.ToString(); } @@ -905,6 +955,12 @@ namespace MediaBrowser.Controller.Entities return current.IsInMixedFolder == newItem.IsInMixedFolder; } + public void AfterMetadataRefresh() + { + _sortName = null; + _userDataKey = null; + } + /// <summary> /// Gets the preferred metadata language. /// </summary> @@ -1024,7 +1080,8 @@ namespace MediaBrowser.Controller.Entities if (hasTags != null) { - if (user.Policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) + var policy = user.Policy; + if (policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) { return false; } @@ -1033,6 +1090,11 @@ namespace MediaBrowser.Controller.Entities return true; } + protected virtual bool IsAllowTagFilterEnforced() + { + return true; + } + /// <summary> /// Gets the block unrated value. /// </summary> @@ -1060,6 +1122,23 @@ namespace MediaBrowser.Controller.Entities return IsParentalAllowed(user); } + public virtual bool IsVisibleStandalone(User user) + { + if (!IsVisible(user)) + { + return false; + } + + if (Parents.Any(i => !i.IsVisible(user))) + { + return false; + } + + // TODO: Need some work here, e.g. is in user library, for channels, can user access channel, etc. + + return true; + } + /// <summary> /// Gets a value indicating whether this instance is folder. /// </summary> @@ -1146,7 +1225,7 @@ namespace MediaBrowser.Controller.Entities if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType)) { - return LibraryManager.RootFolder.RecursiveChildren.FirstOrDefault(i => + return LibraryManager.RootFolder.GetRecursiveChildren(i => { if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)) { @@ -1164,7 +1243,8 @@ namespace MediaBrowser.Controller.Entities } return false; - }); + + }).FirstOrDefault(); } return null; @@ -1458,7 +1538,7 @@ namespace MediaBrowser.Controller.Entities currentFile.Attributes &= ~FileAttributes.Hidden; } - currentFile.Delete(); + FileSystem.DeleteFile(currentFile.FullName); } return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); @@ -1703,6 +1783,9 @@ namespace MediaBrowser.Controller.Entities /// </summary> public virtual bool BeforeMetadataRefresh() { + _userDataKey = null; + _sortName = null; + var hasChanges = false; if (string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Path)) diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index b30bd81b9..785c441d3 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -11,5 +11,10 @@ namespace MediaBrowser.Controller.Entities { get { return null; } } + + public override bool CanDelete() + { + return false; + } } } diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index 381b2101d..e59db67a6 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -2,6 +2,7 @@ using MediaBrowser.Model.Configuration; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities @@ -37,6 +38,13 @@ namespace MediaBrowser.Controller.Entities Tags = new List<string>(); } + public override bool CanDownload() + { + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Book); diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index f47a439a7..a39357f2b 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -35,6 +35,11 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + public string CollectionType { get; set; } /// <summary> @@ -86,7 +91,7 @@ namespace MediaBrowser.Controller.Entities { var path = ContainingFolderPath; - var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager, directoryService) + var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService) { FileInfo = new DirectoryInfo(path), Path = path, @@ -121,12 +126,6 @@ namespace MediaBrowser.Controller.Entities return args; } - // Cache this since it will be used a lot - /// <summary> - /// The null task result - /// </summary> - private static readonly Task NullTaskResult = Task.FromResult<object>(null); - /// <summary> /// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes /// ***Currently does not contain logic to maintain items that are unavailable in the file system*** @@ -138,7 +137,7 @@ namespace MediaBrowser.Controller.Entities /// <param name="refreshOptions">The refresh options.</param> /// <param name="directoryService">The directory service.</param> /// <returns>Task.</returns> - protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { var list = PhysicalLocationsList.ToList(); @@ -146,8 +145,10 @@ namespace MediaBrowser.Controller.Entities if (!list.SequenceEqual(PhysicalLocationsList)) { - await UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + return UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken); } + + return Task.FromResult(true); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 2761aa5d7..0d9bb03ac 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -6,7 +6,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; -using MoreLinq; using System; using System.Collections; using System.Collections.Generic; @@ -15,13 +14,14 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { /// <summary> /// Class Folder /// </summary> - public class Folder : BaseItem, IHasThemeMedia, IHasTags + public class Folder : BaseItem, IHasThemeMedia, IHasTags, IHasPreferredMetadataLanguage { public static IUserManager UserManager { get; set; } public static IUserViewManager UserViewManager { get; set; } @@ -30,6 +30,14 @@ namespace MediaBrowser.Controller.Entities public List<Guid> ThemeVideoIds { get; set; } public List<string> Tags { get; set; } + public string PreferredMetadataLanguage { get; set; } + + /// <summary> + /// Gets or sets the preferred metadata country code. + /// </summary> + /// <value>The preferred metadata country code.</value> + public string PreferredMetadataCountryCode { get; set; } + public Folder() { LinkedChildren = new List<LinkedChild>(); @@ -72,6 +80,19 @@ namespace MediaBrowser.Controller.Entities } } + protected override bool IsAllowTagFilterEnforced() + { + if (this is ICollectionFolder) + { + return false; + } + if (this is UserView) + { + return false; + } + return true; + } + /// <summary> /// Gets or sets a value indicating whether this instance is physical root. /// </summary> @@ -98,6 +119,7 @@ namespace MediaBrowser.Controller.Entities public virtual List<LinkedChild> LinkedChildren { get; set; } + [IgnoreDataMember] protected virtual bool SupportsShortcutChildren { get { return true; } @@ -237,14 +259,13 @@ namespace MediaBrowser.Controller.Entities protected virtual IEnumerable<string> GetIndexByOptions() { return new List<string> { - {LocalizedStrings.Instance.GetString("NoneDispPref")}, - {LocalizedStrings.Instance.GetString("PerformerDispPref")}, - {LocalizedStrings.Instance.GetString("GenreDispPref")}, - {LocalizedStrings.Instance.GetString("DirectorDispPref")}, - {LocalizedStrings.Instance.GetString("YearDispPref")}, - {LocalizedStrings.Instance.GetString("StudioDispPref")} + {"None"}, + {"Performer"}, + {"Genre"}, + {"Director"}, + {"Year"}, + {"Studio"} }; - } /// <summary> @@ -275,7 +296,17 @@ namespace MediaBrowser.Controller.Entities { get { - return _children ?? (_children = LoadChildrenInternal()); + if (_children == null) + { + lock (_childrenSyncLock) + { + if (_children == null) + { + _children = LoadChildrenInternal(); + } + } + } + return _children; } } @@ -301,14 +332,24 @@ namespace MediaBrowser.Controller.Entities public override bool IsVisible(User user) { - if (this is ICollectionFolder) + if (this is ICollectionFolder && !(this is BasePluginFolder)) { - if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) || + if (user.Policy.BlockedMediaFolders != null) + { + if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) || - // Backwards compatibility - user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) + // Backwards compatibility + user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + } + else { - return false; + if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) + { + return false; + } } } @@ -345,12 +386,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>Task.</returns> public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true) { - return ValidateChildrenWithCancellationSupport(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService); - } - - private Task ValidateChildrenWithCancellationSupport(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) - { - return ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService); + return ValidateChildrenInternal(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService); } private Dictionary<Guid, BaseItem> GetActualChildrenDictionary() @@ -540,50 +576,49 @@ namespace MediaBrowser.Controller.Entities var children = ActualChildren.ToList(); var percentages = new Dictionary<Guid, double>(children.Count); - - var tasks = new List<Task>(); + var numComplete = 0; + var count = children.Count; foreach (var child in children) { - if (tasks.Count >= 2) - { - await Task.WhenAll(tasks).ConfigureAwait(false); - tasks.Clear(); - } - cancellationToken.ThrowIfCancellationRequested(); - var innerProgress = new ActionableProgress<double>(); - // Avoid implicitly captured closure - var currentChild = child; - innerProgress.RegisterAction(p => + if (child.IsFolder) { - lock (percentages) + var innerProgress = new ActionableProgress<double>(); + + // Avoid implicitly captured closure + var currentChild = child; + innerProgress.RegisterAction(p => { - percentages[currentChild.Id] = p / 100; + lock (percentages) + { + percentages[currentChild.Id] = p / 100; - var percent = percentages.Values.Sum(); - percent /= children.Count; - percent *= 100; - progress.Report(percent); - } - }); + var innerPercent = percentages.Values.Sum(); + innerPercent /= count; + innerPercent *= 100; + progress.Report(innerPercent); + } + }); - if (child.IsFolder) - { await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken) .ConfigureAwait(false); } else { - // Avoid implicitly captured closure - var taskChild = child; - - tasks.Add(Task.Run(async () => await RefreshChildMetadata(taskChild, refreshOptions, false, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken)); + await RefreshChildMetadata(child, refreshOptions, false, new Progress<double>(), cancellationToken) + .ConfigureAwait(false); } + + numComplete++; + double percent = numComplete; + percent /= count; + percent *= 100; + + progress.Report(percent); } - await Task.WhenAll(tasks).ConfigureAwait(false); progress.Report(100); } @@ -648,7 +683,7 @@ namespace MediaBrowser.Controller.Entities } }); - await child.ValidateChildrenWithCancellationSupport(innerProgress, cancellationToken, true, false, null, directoryService) + await child.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService) .ConfigureAwait(false); } } @@ -678,12 +713,12 @@ namespace MediaBrowser.Controller.Entities path = System.IO.Path.GetDirectoryName(path); } - if (ContainsPath(LibraryManager.GetDefaultVirtualFolders(), originalPath)) + if (ContainsPath(LibraryManager.GetVirtualFolders(), originalPath)) { return true; } - return UserManager.Users.Any(user => ContainsPath(LibraryManager.GetVirtualFolders(user), originalPath)); + return ContainsPath(LibraryManager.GetVirtualFolders(), originalPath); } /// <summary> @@ -731,28 +766,6 @@ namespace MediaBrowser.Controller.Entities return childrenItems; } - /// <summary> - /// Retrieves the child. - /// </summary> - /// <param name="child">The child.</param> - /// <returns>BaseItem.</returns> - private BaseItem RetrieveChild(Guid child) - { - var item = LibraryManager.GetItemById(child); - - if (item != null) - { - if (item is IByReferenceItem) - { - return LibraryManager.GetOrAddByReferenceItem(item); - } - - item.Parent = this; - } - - return item; - } - private BaseItem RetrieveChild(BaseItem child) { if (child.Id == Guid.Empty) @@ -786,18 +799,31 @@ namespace MediaBrowser.Controller.Entities { var user = query.User; - var items = query.Recursive - ? GetRecursiveChildren(user) - : GetChildren(user, true); + Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); + + IEnumerable<BaseItem> items; + + if (query.User == null) + { + items = query.Recursive + ? GetRecursiveChildren(filter) + : Children.Where(filter); + } + else + { + items = query.Recursive + ? GetRecursiveChildren(user, filter) + : GetChildren(user, true).Where(filter); + } - var result = SortAndFilter(items, query); + var result = PostFilterAndSort(items, query); return Task.FromResult(result); } - protected QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items, InternalItemsQuery query) + protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query) { - return UserViewBuilder.SortAndFilter(items, this, null, query, LibraryManager, UserDataManager); + return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager); } /// <summary> @@ -822,11 +848,11 @@ namespace MediaBrowser.Controller.Entities //the true root should return our users root folder children if (IsPhysicalRoot) return user.RootFolder.GetChildren(user, includeLinkedChildren); - var list = new List<BaseItem>(); + var result = new Dictionary<Guid, BaseItem>(); - var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, includeHidden, false); + AddChildren(user, includeLinkedChildren, result, includeHidden, false, null); - return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list; + return result.Values; } protected virtual IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user) @@ -839,31 +865,30 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="user">The user.</param> /// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param> - /// <param name="list">The list.</param> + /// <param name="result">The result.</param> /// <param name="includeHidden">if set to <c>true</c> [include hidden].</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> + /// <param name="filter">The filter.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - private bool AddChildrenToList(User user, bool includeLinkedChildren, List<BaseItem> list, bool includeHidden, bool recursive) + private void AddChildren(User user, bool includeLinkedChildren, Dictionary<Guid, BaseItem> result, bool includeHidden, bool recursive, Func<BaseItem, bool> filter) { - var hasLinkedChildren = false; - foreach (var child in GetEligibleChildrenForRecursiveChildren(user)) { if (child.IsVisible(user)) { if (includeHidden || !child.IsHiddenFromUser(user)) { - list.Add(child); + if (filter == null || filter(child)) + { + result[child.Id] = child; + } } if (recursive && child.IsFolder) { var folder = (Folder)child; - if (folder.AddChildrenToList(user, includeLinkedChildren, list, includeHidden, true)) - { - hasLinkedChildren = true; - } + folder.AddChildren(user, includeLinkedChildren, result, includeHidden, true, filter); } } } @@ -874,14 +899,13 @@ namespace MediaBrowser.Controller.Entities { if (child.IsVisible(user)) { - hasLinkedChildren = true; - - list.Add(child); + if (filter == null || filter(child)) + { + result[child.Id] = child; + } } } } - - return hasLinkedChildren; } /// <summary> @@ -891,18 +915,23 @@ namespace MediaBrowser.Controller.Entities /// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param> /// <returns>IEnumerable{BaseItem}.</returns> /// <exception cref="System.ArgumentNullException"></exception> - public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true) + public IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true) + { + return GetRecursiveChildren(user, i => true); + } + + public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter) { if (user == null) { throw new ArgumentNullException("user"); } - var list = new List<BaseItem>(); + var result = new Dictionary<Guid, BaseItem>(); - var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, false, true); + AddChildren(user, true, result, false, true, filter); - return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list; + return result.Values; } /// <summary> @@ -911,9 +940,14 @@ namespace MediaBrowser.Controller.Entities /// <returns>IList{BaseItem}.</returns> public IList<BaseItem> GetRecursiveChildren() { + return GetRecursiveChildren(i => true); + } + + public IList<BaseItem> GetRecursiveChildren(Func<BaseItem, bool> filter) + { var list = new List<BaseItem>(); - AddChildrenToList(list, true, null); + AddChildrenToList(list, true, filter); return list; } @@ -1022,6 +1056,15 @@ namespace MediaBrowser.Controller.Entities .Where(i => i.Item2 != null); } + [IgnoreDataMember] + protected override bool SupportsOwnedItems + { + get + { + return base.SupportsOwnedItems || SupportsShortcutChildren; + } + } + protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) { var changesFound = false; @@ -1126,8 +1169,7 @@ namespace MediaBrowser.Controller.Entities bool resetPosition) { // Sweep through recursively and update status - var tasks = GetRecursiveChildren(user, true) - .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual) + var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual) .Select(c => c.MarkPlayed(user, datePlayed, resetPosition)); await Task.WhenAll(tasks).ConfigureAwait(false); @@ -1141,8 +1183,7 @@ namespace MediaBrowser.Controller.Entities public override async Task MarkUnplayed(User user) { // Sweep through recursively and update status - var tasks = GetRecursiveChildren(user, true) - .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual) + var tasks = GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual) .Select(c => c.MarkUnplayed(user)); await Task.WhenAll(tasks).ConfigureAwait(false); @@ -1171,15 +1212,15 @@ namespace MediaBrowser.Controller.Entities return this; } - return RecursiveChildren.FirstOrDefault(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) || + return GetRecursiveChildren(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase) || (!i.IsFolder && !i.IsInMixedFolder && string.Equals(i.ContainingFolderPath, path, StringComparison.OrdinalIgnoreCase)) || - i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase)); + i.PhysicalLocations.Contains(path, StringComparer.OrdinalIgnoreCase)) + .FirstOrDefault(); } public override bool IsPlayed(User user) { - return GetRecursiveChildren(user) - .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual) + return GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual) .All(i => i.IsPlayed(user)); } @@ -1206,8 +1247,7 @@ namespace MediaBrowser.Controller.Entities } else { - children = folder.GetRecursiveChildren(user) - .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual); + children = folder.GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual); } // Loop through each recursive child diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index bf32d3e63..899e5628f 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -1,10 +1,10 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -38,6 +38,13 @@ namespace MediaBrowser.Controller.Entities public List<Guid> LocalTrailerIds { get; set; } public List<Guid> RemoteTrailerIds { get; set; } + public override bool CanDownload() + { + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + /// <summary> /// Gets or sets the tags. /// </summary> @@ -88,7 +95,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> public List<string> MultiPartGameFiles { get; set; } - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var id = this.GetProviderId(MetadataProviders.Gamesdb); @@ -96,7 +103,7 @@ namespace MediaBrowser.Controller.Entities { return "Game-Gamesdb-" + id; } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } public override IEnumerable<string> GetDeletePaths() diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs index 825468954..b246b9388 100644 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ b/MediaBrowser.Controller/Entities/GameGenre.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -10,7 +11,7 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "GameGenre-" + Name; } @@ -20,6 +21,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -32,6 +34,7 @@ namespace MediaBrowser.Controller.Entities /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -40,9 +43,19 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => (i is Game) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase)); + return inputItems.Where(GetItemFilter()); + } + + public Func<BaseItem, bool> GetItemFilter() + { + return i => (i is Game) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase); } } } diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs index 758498977..cf6916763 100644 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ b/MediaBrowser.Controller/Entities/GameSystem.cs @@ -35,13 +35,13 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { if (!string.IsNullOrEmpty(GameSystemName)) { return "GameSystem-" + GameSystemName; } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 05442f2b7..e17a5c1d8 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities.Audio; +using System.Runtime.Serialization; +using MediaBrowser.Controller.Entities.Audio; using System; using System.Collections.Generic; using System.Linq; @@ -14,7 +15,7 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "Genre-" + Name; } @@ -24,6 +25,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -32,10 +34,16 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -46,7 +54,12 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => !(i is Game) && !(i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase)); + return inputItems.Where(GetItemFilter()); + } + + public Func<BaseItem, bool> GetItemFilter() + { + return i => !(i is Game) && !(i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase); } } } diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index 10ddaa474..3643c58b3 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -54,5 +54,10 @@ namespace MediaBrowser.Controller.Entities /// Gets the item identities. /// </summary> List<IItemIdentity> Identities { get; set; } + + /// <summary> + /// Afters the metadata refresh. + /// </summary> + void AfterMetadataRefresh(); } } diff --git a/MediaBrowser.Controller/Entities/IItemByName.cs b/MediaBrowser.Controller/Entities/IItemByName.cs index 70d5b840f..14b69b8fd 100644 --- a/MediaBrowser.Controller/Entities/IItemByName.cs +++ b/MediaBrowser.Controller/Entities/IItemByName.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace MediaBrowser.Controller.Entities { @@ -13,6 +14,12 @@ namespace MediaBrowser.Controller.Entities /// <param name="inputItems">The input items.</param> /// <returns>IEnumerable{BaseItem}.</returns> IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems); + + /// <summary> + /// Gets the item filter. + /// </summary> + /// <returns>Func<BaseItem, System.Boolean>.</returns> + Func<BaseItem, bool> GetItemFilter(); } public interface IHasDualAccess : IItemByName diff --git a/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs b/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs index 0fd463155..fbe5a06d0 100644 --- a/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs +++ b/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; - + namespace MediaBrowser.Controller.Entities { /// <summary> @@ -10,10 +8,5 @@ namespace MediaBrowser.Controller.Entities /// </summary> public interface ISupportsBoxSetGrouping { - /// <summary> - /// Gets or sets the box set identifier list. - /// </summary> - /// <value>The box set identifier list.</value> - List<Guid> BoxSetIdList { get; set; } } } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 30043682d..e99c11e87 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -17,7 +17,7 @@ namespace MediaBrowser.Controller.Entities public User User { get; set; } - public Func<BaseItem, User, bool> Filter { get; set; } + public Func<BaseItem, bool> Filter { get; set; } public bool? IsFolder { get; set; } public bool? IsFavorite { get; set; } diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 4483c7b0f..d874046ef 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -1,22 +1,22 @@ -using MediaBrowser.Common.Progress; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Movies { /// <summary> /// Class BoxSet /// </summary> - public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer, IHasShares + public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasDisplayOrder, IHasLookupInfo<BoxSetInfo>, IMetadataContainer, IHasShares { public List<Share> Shares { get; set; } @@ -54,14 +54,6 @@ namespace MediaBrowser.Controller.Entities.Movies /// <value>The tags.</value> public List<string> Keywords { get; set; } - public string PreferredMetadataLanguage { get; set; } - - /// <summary> - /// Gets or sets the preferred metadata country code. - /// </summary> - /// <value>The preferred metadata country code.</value> - public string PreferredMetadataCountryCode { get; set; } - /// <summary> /// Gets or sets the display order. /// </summary> @@ -82,6 +74,11 @@ namespace MediaBrowser.Controller.Entities.Movies } } + public override bool IsAuthorizedToDelete(User user) + { + return true; + } + /// <summary> /// Gets the trailer ids. /// </summary> @@ -93,6 +90,31 @@ namespace MediaBrowser.Controller.Entities.Movies return list; } + /// <summary> + /// Updates the official rating based on content and returns true or false indicating if it changed. + /// </summary> + /// <returns></returns> + public bool UpdateRatingToContent() + { + var currentOfficialRating = OfficialRating; + + // Gather all possible ratings + var ratings = GetRecursiveChildren() + .Concat(GetLinkedChildren()) + .Where(i => i is Movie || i is Series) + .Select(i => i.OfficialRating) + .Where(i => !string.IsNullOrEmpty(i)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Select(i => new Tuple<string, int?>(i, LocalizationManager.GetRatingLevel(i))) + .OrderBy(i => i.Item2 ?? 1000) + .Select(i => i.Item1); + + OfficialRating = ratings.FirstOrDefault() ?? currentOfficialRating; + + return !string.Equals(currentOfficialRating ?? string.Empty, OfficialRating ?? string.Empty, + StringComparison.OrdinalIgnoreCase); + } + public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren) { var children = base.GetChildren(user, includeLinkedChildren); @@ -122,34 +144,22 @@ namespace MediaBrowser.Controller.Entities.Movies { // Refresh bottom up, children first, then the boxset // By then hopefully the movies within will have Tmdb collection values - var items = RecursiveChildren.ToList(); + var items = GetRecursiveChildren().ToList(); var totalItems = items.Count; - var percentages = new Dictionary<Guid, double>(totalItems); + var numComplete = 0; // Refresh songs foreach (var item in items) { cancellationToken.ThrowIfCancellationRequested(); - var innerProgress = new ActionableProgress<double>(); - // Avoid implicitly captured closure - var currentChild = item; - innerProgress.RegisterAction(p => - { - lock (percentages) - { - percentages[currentChild.Id] = p / 100; - - var percent = percentages.Values.Sum(); - percent /= totalItems; - percent *= 100; - progress.Report(percent); - } - }); - - // Avoid implicitly captured closure - await RefreshItem(item, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false); + await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); } // Refresh current item @@ -158,13 +168,6 @@ namespace MediaBrowser.Controller.Entities.Movies progress.Report(100); } - private async Task RefreshItem(BaseItem item, MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) - { - await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); - - progress.Report(100); - } - public override bool IsVisible(User user) { if (base.IsVisible(user)) diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index b3774cfe0..cfe008bd7 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -25,12 +25,6 @@ namespace MediaBrowser.Controller.Entities.Movies public List<Guid> ThemeVideoIds { get; set; } public List<string> ProductionLocations { get; set; } - /// <summary> - /// This is just a cache to enable quick access by Id - /// </summary> - [IgnoreDataMember] - public List<Guid> BoxSetIdList { get; set; } - public Movie() { SpecialFeatureIds = new List<Guid>(); @@ -40,7 +34,6 @@ namespace MediaBrowser.Controller.Entities.Movies RemoteTrailerIds = new List<Guid>(); ThemeSongIds = new List<Guid>(); ThemeVideoIds = new List<Guid>(); - BoxSetIdList = new List<Guid>(); Taglines = new List<string>(); Keywords = new List<string>(); ProductionLocations = new List<string>(); @@ -107,9 +100,9 @@ namespace MediaBrowser.Controller.Entities.Movies /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { - return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey(); + return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.CreateUserDataKey(); } protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index 4ca8cf1c5..771c62fd6 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -48,21 +48,6 @@ namespace MediaBrowser.Controller.Entities } /// <summary> - /// TODO: Remove - /// </summary> - public string Artist - { - get { return Artists.FirstOrDefault(); } - set - { - if (!string.IsNullOrEmpty(value) && !Artists.Contains(value, StringComparer.OrdinalIgnoreCase)) - { - Artists.Add(value); - } - } - } - - /// <summary> /// Determines whether the specified name has artist. /// </summary> /// <param name="name">The name.</param> @@ -76,9 +61,9 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { - return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey(); + return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index fe8d61836..d8cb69ca1 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Providers; +using System.Runtime.Serialization; +using MediaBrowser.Controller.Providers; using System; using System.Collections.Generic; using System.Linq; @@ -15,12 +16,12 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The place of birth.</value> public string PlaceOfBirth { get; set; } - + /// <summary> /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "Person-" + Name; } @@ -35,6 +36,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -43,10 +45,16 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -57,7 +65,13 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => i.People.Any(p => string.Equals(p.Name, Name, StringComparison.OrdinalIgnoreCase))); + return inputItems.Where(GetItemFilter()); + } + + + public Func<BaseItem, bool> GetItemFilter() + { + return i => i.People.Any(p => string.Equals(p.Name, Name, StringComparison.OrdinalIgnoreCase)); } } diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index 0d934ad0a..31bbaf422 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -15,12 +16,12 @@ namespace MediaBrowser.Controller.Entities { Tags = new List<string>(); } - + /// <summary> /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "Studio-" + Name; } @@ -30,6 +31,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -38,10 +40,16 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -52,7 +60,13 @@ namespace MediaBrowser.Controller.Entities public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems) { - return inputItems.Where(i => i.Studios.Contains(Name, StringComparer.OrdinalIgnoreCase)); + return inputItems.Where(GetItemFilter()); + } + + + public Func<BaseItem, bool> GetItemFilter() + { + return i => i.Studios.Contains(Name, StringComparer.OrdinalIgnoreCase); } } } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 6b67cebc8..c8408365d 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -56,6 +56,15 @@ namespace MediaBrowser.Controller.Entities.TV } [IgnoreDataMember] + protected override bool SupportsOwnedItems + { + get + { + return IsStacked || MediaSourceCount > 1; + } + } + + [IgnoreDataMember] public int? AiredSeasonNumber { get @@ -117,7 +126,7 @@ namespace MediaBrowser.Controller.Entities.TV /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var series = Series; @@ -126,7 +135,7 @@ namespace MediaBrowser.Controller.Entities.TV return series.GetUserDataKey() + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000"); } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 54db12b6f..a99b8c659 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -81,10 +81,10 @@ namespace MediaBrowser.Controller.Entities.TV protected override IEnumerable<string> GetIndexByOptions() { return new List<string> { - {LocalizedStrings.Instance.GetString("NoneDispPref")}, - {LocalizedStrings.Instance.GetString("PerformerDispPref")}, - {LocalizedStrings.Instance.GetString("DirectorDispPref")}, - {LocalizedStrings.Instance.GetString("YearDispPref")}, + {"None"}, + {"Performer"}, + {"Director"}, + {"Year"}, }; } @@ -92,7 +92,7 @@ namespace MediaBrowser.Controller.Entities.TV /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { if (Series != null) { @@ -100,7 +100,7 @@ namespace MediaBrowser.Controller.Entities.TV return Series.GetUserDataKey() + seasonNo.ToString("000"); } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } /// <summary> @@ -244,7 +244,7 @@ namespace MediaBrowser.Controller.Entities.TV private IEnumerable<Episode> GetEpisodes() { - var episodes = RecursiveChildren.OfType<Episode>(); + var episodes = GetRecursiveChildren().OfType<Episode>(); var series = Series; if (series != null && series.ContainsEpisodesWithoutSeasonFolders) @@ -254,12 +254,12 @@ namespace MediaBrowser.Controller.Entities.TV if (seasonNumber.HasValue) { - list.AddRange(series.RecursiveChildren.OfType<Episode>() + list.AddRange(series.GetRecursiveChildren().OfType<Episode>() .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value)); } else { - list.AddRange(series.RecursiveChildren.OfType<Episode>() + list.AddRange(series.GetRecursiveChildren().OfType<Episode>() .Where(i => !i.ParentIndexNumber.HasValue)); } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 55cfffeb2..619617e9f 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Controller.Localization; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; @@ -14,7 +16,7 @@ namespace MediaBrowser.Controller.Entities.TV /// <summary> /// Class Series /// </summary> - public class Series : Folder, IHasSoundtracks, IHasTrailers, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IHasSpecialFeatures + public class Series : Folder, IHasSoundtracks, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IHasSpecialFeatures, IMetadataContainer { public List<Guid> SpecialFeatureIds { get; set; } public List<Guid> SoundtrackIds { get; set; } @@ -23,12 +25,6 @@ namespace MediaBrowser.Controller.Entities.TV public int? AnimeSeriesIndex { get; set; } - /// <summary> - /// Gets or sets the preferred metadata country code. - /// </summary> - /// <value>The preferred metadata country code.</value> - public string PreferredMetadataCountryCode { get; set; } - public Series() { AirDays = new List<DayOfWeek>(); @@ -93,7 +89,7 @@ namespace MediaBrowser.Controller.Entities.TV { get { - return RecursiveChildren.OfType<Episode>() + return GetRecursiveChildren(i => i is Episode) .Select(i => i.DateCreated) .OrderByDescending(i => i) .FirstOrDefault(); @@ -117,9 +113,9 @@ namespace MediaBrowser.Controller.Entities.TV /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { - return this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom) ?? base.GetUserDataKey(); + return this.GetProviderId(MetadataProviders.Tvdb) ?? this.GetProviderId(MetadataProviders.Tvcom) ?? base.CreateUserDataKey(); } /// <summary> @@ -137,10 +133,10 @@ namespace MediaBrowser.Controller.Entities.TV protected override IEnumerable<string> GetIndexByOptions() { return new List<string> { - {LocalizedStrings.Instance.GetString("NoneDispPref")}, - {LocalizedStrings.Instance.GetString("PerformerDispPref")}, - {LocalizedStrings.Instance.GetString("DirectorDispPref")}, - {LocalizedStrings.Instance.GetString("YearDispPref")}, + {"None"}, + {"Performer"}, + {"Director"}, + {"Year"}, }; } @@ -191,6 +187,85 @@ namespace MediaBrowser.Controller.Entities.TV .Cast<Season>(); } + public IEnumerable<Episode> GetEpisodes(User user) + { + var config = user.Configuration; + + return GetEpisodes(user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); + } + + public IEnumerable<Episode> GetEpisodes(User user, bool includeMissing, bool includeVirtualUnaired) + { + var allEpisodes = GetSeasons(user, true, true) + .SelectMany(i => i.GetEpisodes(user, includeMissing, includeVirtualUnaired)) + .Reverse() + .ToList(); + + // Specials could appear twice based on above - once in season 0, once in the aired season + // This depends on settings for that series + // When this happens, remove the duplicate from season 0 + var returnList = new List<Episode>(); + + foreach (var episode in allEpisodes) + { + if (!returnList.Contains(episode)) + { + returnList.Insert(0, episode); + } + } + + return returnList; + } + + public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) + { + // Refresh bottom up, children first, then the boxset + // By then hopefully the movies within will have Tmdb collection values + var items = GetRecursiveChildren().ToList(); + + var seasons = items.OfType<Season>().ToList(); + var otherItems = items.Except(seasons).ToList(); + + var totalItems = seasons.Count + otherItems.Count; + var numComplete = 0; + + refreshOptions = new MetadataRefreshOptions(refreshOptions); + refreshOptions.IsPostRecursiveRefresh = true; + + // Refresh songs + foreach (var item in seasons) + { + cancellationToken.ThrowIfCancellationRequested(); + + await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); + } + + // Refresh current item + await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + + // Refresh all non-songs + foreach (var item in otherItems) + { + cancellationToken.ThrowIfCancellationRequested(); + + await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + + numComplete++; + double percent = numComplete; + percent /= totalItems; + progress.Report(percent * 100); + } + + await ProviderManager.RefreshMetadata(this, refreshOptions, cancellationToken).ConfigureAwait(false); + + progress.Report(100); + } + public IEnumerable<Episode> GetEpisodes(User user, int seasonNumber) { var config = user.Configuration; @@ -206,8 +281,8 @@ namespace MediaBrowser.Controller.Entities.TV internal IEnumerable<Episode> GetEpisodes(User user, int seasonNumber, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> additionalEpisodes) { - var episodes = GetRecursiveChildren(user) - .OfType<Episode>(); + var episodes = GetRecursiveChildren(user, i => i is Episode) + .Cast<Episode>(); episodes = FilterEpisodesBySeason(episodes, seasonNumber, DisplaySpecialsWithSeasons); @@ -262,8 +337,6 @@ namespace MediaBrowser.Controller.Entities.TV return config.BlockUnratedItems.Contains(UnratedItem.Series); } - public string PreferredMetadataLanguage { get; set; } - public SeriesInfo GetLookupInfo() { var info = GetItemLookupInfo<SeriesInfo>(); diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 7a1eef8db..522e6edf6 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -1,12 +1,12 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.Serialization; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -79,7 +79,7 @@ namespace MediaBrowser.Controller.Entities } } - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var key = this.GetProviderId(MetadataProviders.Imdb) ?? this.GetProviderId(MetadataProviders.Tmdb); @@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Entities return key; } - return base.GetUserDataKey(); + return base.CreateUserDataKey(); } protected override bool GetBlockUnratedValue(UserPolicy config) diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 626afcfdf..01a7486b3 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The password.</value> public string Password { get; set; } - public string LocalPassword { get; set; } + public string EasyPassword { get; set; } public string ConnectUserName { get; set; } public string ConnectUserId { get; set; } @@ -62,6 +62,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -74,6 +75,7 @@ namespace MediaBrowser.Controller.Entities /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -166,7 +168,7 @@ namespace MediaBrowser.Controller.Entities } // If only the casing is changing, leave the file system alone - if (!UsesIdForConfigurationPath && !newName.Equals(Name, StringComparison.OrdinalIgnoreCase)) + if (!UsesIdForConfigurationPath && !string.Equals(newName, Name, StringComparison.OrdinalIgnoreCase)) { UsesIdForConfigurationPath = true; @@ -177,7 +179,7 @@ namespace MediaBrowser.Controller.Entities // Exceptions will be thrown if these paths already exist if (Directory.Exists(newConfigDirectory)) { - Directory.Delete(newConfigDirectory, true); + FileSystem.DeleteDirectory(newConfigDirectory, true); } if (Directory.Exists(oldConfigurationDirectory)) @@ -227,16 +229,16 @@ namespace MediaBrowser.Controller.Entities /// <returns>System.String.</returns> private string GetConfigurationDirectoryPath(string username) { - if (string.IsNullOrEmpty(username)) - { - throw new ArgumentNullException("username"); - } - var parentPath = ConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath; // Legacy if (!UsesIdForConfigurationPath) { + if (string.IsNullOrEmpty(username)) + { + throw new ArgumentNullException("username"); + } + var safeFolderName = FileSystem.GetValidFilename(username); return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, safeFolderName); diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index a7276e262..b065ae171 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -18,10 +18,13 @@ namespace MediaBrowser.Controller.Entities { public override async Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query) { + var user = query.User; + Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); + if (query.Recursive) { - var items = query.User.RootFolder.GetRecursiveChildren(query.User); - return SortAndFilter(items, query); + var items = query.User.RootFolder.GetRecursiveChildren(query.User, filter); + return PostFilterAndSort(items, query); } var result = await UserViewManager.GetUserViews(new UserViewQuery @@ -30,7 +33,7 @@ namespace MediaBrowser.Controller.Entities }, CancellationToken.None).ConfigureAwait(false); - return SortAndFilter(result, query); + return PostFilterAndSort(result.Where(filter), query); } public override bool IsPreSorted diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 0364ff678..5f7ca3d3f 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -40,12 +40,18 @@ namespace MediaBrowser.Controller.Entities return result.Items; } - public override IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true) + public override bool CanDelete() + { + return false; + } + + public override IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter) { var result = GetItems(new InternalItemsQuery { User = user, - Recursive = true + Recursive = true, + Filter = filter }).Result; @@ -63,8 +69,7 @@ namespace MediaBrowser.Controller.Entities { CollectionType.Books, CollectionType.HomeVideos, - CollectionType.Photos, - string.Empty + CollectionType.Photos }; var collectionFolder = folder as ICollectionFolder; diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 166d56c51..b5ca053ec 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -18,6 +18,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MoreLinq; namespace MediaBrowser.Controller.Entities { @@ -117,7 +118,7 @@ namespace MediaBrowser.Controller.Entities return await GetGameView(user, queryParent, query).ConfigureAwait(false); case CollectionType.BoxSets: - return GetResult(GetMediaFolders(user).SelectMany(i => i.GetRecursiveChildren(user)).OfType<BoxSet>(), queryParent, query); + return await GetBoxsetView(queryParent, user, query).ConfigureAwait(false); case CollectionType.TvShows: return await GetTvView(queryParent, user, query).ConfigureAwait(false); @@ -238,7 +239,9 @@ namespace MediaBrowser.Controller.Entities { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }, i => FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } var list = new List<BaseItem>(); @@ -392,27 +395,54 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> GetMusicAlbums(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicAlbum), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }, i => (i is MusicAlbum) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMusicSongs(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is Audio.Audio), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }, i => (i is Audio.Audio) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMusicLatest(Folder parent, User user, InternalItemsQuery query) { - query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; - query.SortOrder = SortOrder.Descending; + var items = _userViewManager.GetLatestItems(new LatestItemsQuery + { + UserId = user.Id.ToString("N"), + Limit = GetSpecialItemsLimit(), + IncludeItemTypes = new[] { typeof(Audio.Audio).Name }, + ParentId = (parent == null ? null : parent.Id.ToString("N")), + GroupItems = true + + }).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i != null); + + query.SortBy = new string[] { }; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicVideo || i is Audio.Audio), parent, GetSpecialItemsLimit(), query); + //var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }, i => i is MusicVideo || i is Audio.Audio && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), parent, query); + var recursiveItems = GetRecursiveChildren(parent, user, + new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }) + .Where(i => i is Movie || i is BoxSet); + + //var collections = _collectionManager.CollapseItemsWithinBoxSets(recursiveItems, user).ToList(); + + //if (collections.Count > 0) + //{ + // recursiveItems.AddRange(_collectionManager.CollapseItemsWithinBoxSets(recursiveItems, user)); + // recursiveItems = recursiveItems.DistinctBy(i => i.Id).ToList(); + //} + + return GetResult(recursiveItems, parent, query); } var list = new List<BaseItem>(); @@ -431,45 +461,59 @@ namespace MediaBrowser.Controller.Entities { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => (i is Movie) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => (i is Series) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Episode), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => (i is Episode) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetFavoriteSongs(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is Audio.Audio), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }, i => (i is Audio.Audio) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetFavoriteAlbums(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicAlbum), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }, i => (i is MusicAlbum) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => (i is Movie) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => (i is BoxSet) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query) @@ -477,7 +521,9 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => i is Movie && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query) @@ -486,7 +532,9 @@ namespace MediaBrowser.Controller.Entities query.SortOrder = SortOrder.Descending; query.IsResumable = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }, i => i is Movie && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private async Task<QueryResult<BaseItem>> GetMovieGenres(Folder parent, User user, InternalItemsQuery query) @@ -526,11 +574,30 @@ namespace MediaBrowser.Controller.Entities return GetResult(items, queryParent, query); } + private async Task<QueryResult<BaseItem>> GetBoxsetView(Folder parent, User user, InternalItemsQuery query) + { + return GetResult(GetMediaFolders(user).SelectMany(i => + { + var hasCollectionType = i as ICollectionFolder; + Func<BaseItem, bool> filter = b => b is BoxSet; + + if (hasCollectionType != null && string.Equals(hasCollectionType.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) + { + return i.GetChildren(user, true).Where(filter); + } + + return i.GetRecursiveChildren(user, filter); + + }), parent, query); + } + private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => (i is Series || i is Season || i is Episode) && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } var list = new List<BaseItem>(); @@ -550,7 +617,8 @@ namespace MediaBrowser.Controller.Entities { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => FilterItem(i, query)); + return PostFilterAndSort(items, parent, null, query); } var list = new List<BaseItem>(); @@ -569,7 +637,9 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is Game && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, InternalItemsQuery query) @@ -578,14 +648,17 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is Game && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is Game && FilterItem(i, query)); + return PostFilterAndSort(items, parent, null, query); } private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query) @@ -593,7 +666,9 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => i is Episode && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetTvNextUp(Folder parent, InternalItemsQuery query) @@ -617,12 +692,16 @@ namespace MediaBrowser.Controller.Entities query.SortOrder = SortOrder.Descending; query.IsResumable = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), parent, GetSpecialItemsLimit(), query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => i is Episode && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, GetSpecialItemsLimit(), query); } private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Series>(), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }, i => i is Series && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private async Task<QueryResult<BaseItem>> GetTvGenres(Folder parent, User user, InternalItemsQuery query) @@ -664,14 +743,15 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<GameSystem>(), parent, query); + var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }, i => i is GameSystem && FilterItem(i, query)); + + return PostFilterAndSort(items, parent, null, query); } private async Task<QueryResult<BaseItem>> GetGameGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) { - var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Games }) - .OfType<Game>() - .Where(i => i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase)); + var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Games }, + i => i is Game && i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase)); return GetResult(items, queryParent, query); } @@ -719,29 +799,32 @@ namespace MediaBrowser.Controller.Entities InternalItemsQuery query) where T : BaseItem { - return GetResult(items, queryParent, null, query); + items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager)); + + return PostFilterAndSort(items, queryParent, null, query, _libraryManager); } - private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items, + public bool FilterItem(BaseItem item, InternalItemsQuery query) + { + return Filter(item, query.User, query, _userDataManager, _libraryManager); + } + + private QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, BaseItem queryParent, int? totalRecordLimit, InternalItemsQuery query) - where T : BaseItem { - return SortAndFilter(items, queryParent, totalRecordLimit, query, _libraryManager, _userDataManager); + return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager); } - public static QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items, + public static QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, BaseItem queryParent, int? totalRecordLimit, InternalItemsQuery query, - ILibraryManager libraryManager, - IUserDataManager userDataManager) + ILibraryManager libraryManager) { var user = query.User; - items = items.Where(i => Filter(i, user, query, userDataManager, libraryManager)); - items = FilterVirtualEpisodes(items, query.IsMissing, query.IsVirtualUnaired, @@ -763,6 +846,11 @@ namespace MediaBrowser.Controller.Entities BaseItem queryParent, User user) { + if (items == null) + { + throw new ArgumentNullException("items"); + } + if (CollapseBoxSetItems(query, queryParent, user)) { items = BaseItem.CollectionManager.CollapseItemsWithinBoxSets(items, user); @@ -1140,7 +1228,7 @@ namespace MediaBrowser.Controller.Entities }; } - private static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) + public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) { if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { @@ -1162,7 +1250,7 @@ namespace MediaBrowser.Controller.Entities return false; } - if (query.Filter != null && !query.Filter(item, user)) + if (query.Filter != null && !query.Filter(item)) { return false; } @@ -1612,6 +1700,16 @@ namespace MediaBrowser.Controller.Entities return parent.GetRecursiveChildren(user); } + private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, IEnumerable<string> viewTypes, Func<BaseItem, bool> filter) + { + if (parent == null || parent is UserView) + { + return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user, filter)); + } + + return parent.GetRecursiveChildren(user, filter); + } + private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user) { var list = new List<BaseItem>(); diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 3abaf095c..d4507bc33 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -64,6 +64,19 @@ namespace MediaBrowser.Controller.Entities LinkedAlternateVersions = new List<LinkedChild>(); } + public override bool CanDownload() + { + if (VideoType == VideoType.HdDvd || VideoType == VideoType.Dvd || + VideoType == VideoType.BluRay) + { + return false; + } + + var locationType = LocationType; + return locationType != LocationType.Remote && + locationType != LocationType.Virtual; + } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { @@ -409,7 +422,7 @@ namespace MediaBrowser.Controller.Entities public virtual IEnumerable<MediaStream> GetMediaStreams() { - return ItemRepository.GetMediaStreams(new MediaStreamQuery + return MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = Id }); @@ -422,7 +435,7 @@ namespace MediaBrowser.Controller.Entities return null; } - return ItemRepository.GetMediaStreams(new MediaStreamQuery + return MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = Id, Index = DefaultVideoStreamIndex.Value @@ -461,7 +474,8 @@ namespace MediaBrowser.Controller.Entities private static MediaSourceInfo GetVersionInfo(bool enablePathSubstitution, Video i, MediaSourceType type) { - var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(); + var mediaStreams = MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }) + .ToList(); var locationType = i.LocationType; diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index 8deb930e8..cf3ad3b6a 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities { @@ -13,7 +15,7 @@ namespace MediaBrowser.Controller.Entities /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return "Year-" + Name; } @@ -23,6 +25,7 @@ namespace MediaBrowser.Controller.Entities /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -31,10 +34,16 @@ namespace MediaBrowser.Controller.Entities } } + public override bool CanDelete() + { + return false; + } + /// <summary> /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -47,8 +56,8 @@ namespace MediaBrowser.Controller.Entities { int year; - var usCulture = new CultureInfo("en-US"); - + var usCulture = new CultureInfo("en-US"); + if (!int.TryParse(Name, NumberStyles.Integer, usCulture, out year)) { return inputItems; @@ -56,5 +65,23 @@ namespace MediaBrowser.Controller.Entities return inputItems.Where(i => i.ProductionYear.HasValue && i.ProductionYear.Value == year); } + + public int? GetYearValue() + { + int i; + + if (int.TryParse(Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out i)) + { + return i; + } + + return null; + } + + public Func<BaseItem, bool> GetItemFilter() + { + var val = GetYearValue(); + return i => i.ProductionYear.HasValue && val.HasValue && i.ProductionYear.Value == val.Value; + } } } diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index d1a9b386c..105e4e2f0 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; -using MediaBrowser.Common; +using MediaBrowser.Common; using MediaBrowser.Model.System; using System; +using System.Collections.Generic; namespace MediaBrowser.Controller { @@ -19,12 +19,6 @@ namespace MediaBrowser.Controller SystemInfo GetSystemInfo(); /// <summary> - /// Gets the name of the web application. - /// </summary> - /// <value>The name of the web application.</value> - string WebApplicationName { get; } - - /// <summary> /// Gets a value indicating whether [supports automatic run at startup]. /// </summary> /// <value><c>true</c> if [supports automatic run at startup]; otherwise, <c>false</c>.</value> @@ -34,7 +28,19 @@ namespace MediaBrowser.Controller /// Gets the HTTP server port. /// </summary> /// <value>The HTTP server port.</value> - int HttpServerPort { get; } + int HttpPort { get; } + + /// <summary> + /// Gets the HTTPS port. + /// </summary> + /// <value>The HTTPS port.</value> + int HttpsPort { get; } + + /// <summary> + /// Gets a value indicating whether [supports HTTPS]. + /// </summary> + /// <value><c>true</c> if [supports HTTPS]; otherwise, <c>false</c>.</value> + bool EnableHttps { get; } /// <summary> /// Gets a value indicating whether this instance has update available. @@ -49,9 +55,15 @@ namespace MediaBrowser.Controller string FriendlyName { get; } /// <summary> - /// Gets the HTTP server ip addresses. + /// Gets the local ip address. + /// </summary> + /// <value>The local ip address.</value> + string LocalIpAddress { get; } + + /// <summary> + /// Gets the local API URL. /// </summary> - /// <value>The HTTP server ip addresses.</value> - IEnumerable<string> HttpServerIpAddresses { get; } + /// <value>The local API URL.</value> + string LocalApiUrl { get; } } } diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs index e3438c3d2..c07934d0b 100644 --- a/MediaBrowser.Controller/IServerApplicationPaths.cs +++ b/MediaBrowser.Controller/IServerApplicationPaths.cs @@ -60,12 +60,6 @@ namespace MediaBrowser.Controller string GameGenrePath { get; } /// <summary> - /// Gets the artists path. - /// </summary> - /// <value>The artists path.</value> - string ArtistsPath { get; } - - /// <summary> /// Gets the path to the Studio directory /// </summary> /// <value>The studio path.</value> diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 2ebd1cab9..9871ef3c5 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -123,14 +123,7 @@ namespace MediaBrowser.Controller.Library /// Gets the default view. /// </summary> /// <returns>IEnumerable{VirtualFolderInfo}.</returns> - IEnumerable<VirtualFolderInfo> GetDefaultVirtualFolders(); - - /// <summary> - /// Gets the view. - /// </summary> - /// <param name="user">The user.</param> - /// <returns>IEnumerable{VirtualFolderInfo}.</returns> - IEnumerable<VirtualFolderInfo> GetVirtualFolders(User user); + IEnumerable<VirtualFolderInfo> GetVirtualFolders(); /// <summary> /// Gets the item by id. diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs new file mode 100644 index 000000000..4378bc85d --- /dev/null +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -0,0 +1,11 @@ +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Entities; +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Library +{ + public interface IMediaSourceManager + { + IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query); + } +} diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs index f66f18401..0ce0687cc 100644 --- a/MediaBrowser.Controller/Library/IMusicManager.cs +++ b/MediaBrowser.Controller/Library/IMusicManager.cs @@ -1,6 +1,5 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Playlists; using System.Collections.Generic; namespace MediaBrowser.Controller.Library @@ -13,7 +12,7 @@ namespace MediaBrowser.Controller.Library /// <param name="item">The item.</param> /// <param name="user">The user.</param> /// <returns>IEnumerable{Audio}.</returns> - IEnumerable<Audio> GetInstantMixFromSong(Audio item, User user); + IEnumerable<Audio> GetInstantMixFromItem(BaseItem item, User user); /// <summary> /// Gets the instant mix from artist. /// </summary> @@ -22,20 +21,6 @@ namespace MediaBrowser.Controller.Library /// <returns>IEnumerable{Audio}.</returns> IEnumerable<Audio> GetInstantMixFromArtist(string name, User user); /// <summary> - /// Gets the instant mix from album. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="user">The user.</param> - /// <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 f5846973e..97a3cced9 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -118,6 +118,21 @@ namespace MediaBrowser.Controller.Library Task ResetPassword(User user); /// <summary> + /// Gets the offline user dto. + /// </summary> + /// <param name="user">The user.</param> + /// <param name="deviceId">The device identifier.</param> + /// <returns>UserDto.</returns> + UserDto GetOfflineUserDto(User user, string deviceId); + + /// <summary> + /// Resets the easy password. + /// </summary> + /// <param name="user">The user.</param> + /// <returns>Task.</returns> + Task ResetEasyPassword(User user); + + /// <summary> /// Changes the password. /// </summary> /// <param name="user">The user.</param> @@ -126,6 +141,14 @@ namespace MediaBrowser.Controller.Library Task ChangePassword(User user, string newPasswordSha1); /// <summary> + /// Changes the easy password. + /// </summary> + /// <param name="user">The user.</param> + /// <param name="newPasswordSha1">The new password sha1.</param> + /// <returns>Task.</returns> + Task ChangeEasyPassword(User user, string newPasswordSha1); + + /// <summary> /// Gets the user dto. /// </summary> /// <param name="user">The user.</param> diff --git a/MediaBrowser.Controller/Library/IUserViewManager.cs b/MediaBrowser.Controller/Library/IUserViewManager.cs index 727ccd00a..f55c17924 100644 --- a/MediaBrowser.Controller/Library/IUserViewManager.cs +++ b/MediaBrowser.Controller/Library/IUserViewManager.cs @@ -1,5 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Library; +using MediaBrowser.Model.Querying; +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -16,5 +18,7 @@ namespace MediaBrowser.Controller.Library Task<UserView> GetUserView(string type, string sortName, CancellationToken cancellationToken); Task<UserView> GetUserView(string category, string type, User user, string sortName, CancellationToken cancellationToken); + + List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request); } } diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 4fa07421c..db441d285 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -17,7 +17,6 @@ namespace MediaBrowser.Controller.Library /// The _app paths /// </summary> private readonly IServerApplicationPaths _appPaths; - private readonly ILibraryManager _libraryManager; public IDirectoryService DirectoryService { get; private set; } @@ -25,11 +24,10 @@ namespace MediaBrowser.Controller.Library /// Initializes a new instance of the <see cref="ItemResolveArgs" /> class. /// </summary> /// <param name="appPaths">The app paths.</param> - /// <param name="libraryManager">The library manager.</param> - public ItemResolveArgs(IServerApplicationPaths appPaths, ILibraryManager libraryManager, IDirectoryService directoryService) + /// <param name="directoryService">The directory service.</param> + public ItemResolveArgs(IServerApplicationPaths appPaths, IDirectoryService directoryService) { _appPaths = appPaths; - _libraryManager = libraryManager; DirectoryService = directoryService; } @@ -137,18 +135,6 @@ namespace MediaBrowser.Controller.Library } /// <summary> - /// Gets a value indicating whether this instance is root. - /// </summary> - /// <value><c>true</c> if this instance is root; otherwise, <c>false</c>.</value> - public bool IsRoot - { - get - { - return Parent == null; - } - } - - /// <summary> /// Gets or sets the additional locations. /// </summary> /// <value>The additional locations.</value> diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs index ba1cb3043..784cb6ea1 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs @@ -25,5 +25,9 @@ namespace MediaBrowser.Controller.LiveTv Task RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken); PlayAccess GetPlayAccess(User user); + + bool CanDelete(); + + bool CanDelete(User user); } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs index b95d67ad8..9815066ef 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs @@ -1,8 +1,10 @@ -using MediaBrowser.Controller.Entities.Audio; +using System.Runtime.Serialization; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using System.Linq; using MediaBrowser.Model.Users; +using System.Linq; namespace MediaBrowser.Controller.LiveTv { @@ -12,7 +14,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var name = GetClientTypeName(); @@ -32,6 +34,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -40,6 +43,7 @@ namespace MediaBrowser.Controller.LiveTv } } + [IgnoreDataMember] public override string MediaType { get @@ -48,6 +52,7 @@ namespace MediaBrowser.Controller.LiveTv } } + [IgnoreDataMember] public override LocationType LocationType { get @@ -71,6 +76,7 @@ namespace MediaBrowser.Controller.LiveTv return false; } + [IgnoreDataMember] public override bool SupportsLocalMetadata { get @@ -83,5 +89,15 @@ namespace MediaBrowser.Controller.LiveTv { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram); } + + protected override string GetInternalMetadataPath(string basePath) + { + return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N")); + } + + public override bool IsAuthorizedToDelete(User user) + { + return user.Policy.EnableLiveTvManagement; + } } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index de72accff..eaea6cfa4 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -4,9 +4,10 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Users; using System.Collections.Generic; using System.Linq; -using MediaBrowser.Model.Users; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.LiveTv { @@ -16,24 +17,11 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return GetClientTypeName() + "-" + Name; } - /// <summary> - /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself - /// </summary> - /// <value>The containing folder path.</value> - public override string ContainingFolderPath - { - get - { - return Path; - } - } - protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvChannel); @@ -43,6 +31,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -51,11 +40,6 @@ namespace MediaBrowser.Controller.LiveTv } } - public override bool IsSaveLocalMetadataEnabled() - { - return true; - } - /// <summary> /// Gets or sets the number. /// </summary> @@ -106,6 +90,7 @@ namespace MediaBrowser.Controller.LiveTv return number.ToString("000-") + (Name ?? string.Empty); } + [IgnoreDataMember] public override string MediaType { get @@ -145,5 +130,15 @@ namespace MediaBrowser.Controller.LiveTv return list; } + + protected override string GetInternalMetadataPath(string basePath) + { + return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"), "metadata"); + } + + public override bool CanDelete() + { + return false; + } } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 29b23a551..ee85ce20b 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -2,11 +2,12 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.LiveTv; +using MediaBrowser.Model.Users; using System; +using System.Linq; +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; -using System.Linq; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { @@ -16,7 +17,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { return GetClientTypeName() + "-" + Name; } @@ -138,6 +139,7 @@ namespace MediaBrowser.Controller.LiveTv /// If the item is a folder, it returns the folder itself /// </summary> /// <value>The containing folder path.</value> + [IgnoreDataMember] public override string ContainingFolderPath { get @@ -150,6 +152,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -158,6 +161,7 @@ namespace MediaBrowser.Controller.LiveTv } } + [IgnoreDataMember] public override string MediaType { get @@ -166,6 +170,7 @@ namespace MediaBrowser.Controller.LiveTv } } + [IgnoreDataMember] public bool IsAiring { get @@ -176,6 +181,7 @@ namespace MediaBrowser.Controller.LiveTv } } + [IgnoreDataMember] public bool HasAired { get @@ -204,5 +210,15 @@ namespace MediaBrowser.Controller.LiveTv { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram); } + + protected override string GetInternalMetadataPath(string basePath) + { + return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N")); + } + + public override bool CanDelete() + { + return false; + } } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs index 6fc985643..207684d55 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities; +using System.Runtime.Serialization; +using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System.Linq; @@ -12,7 +13,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the user data key. /// </summary> /// <returns>System.String.</returns> - public override string GetUserDataKey() + protected override string CreateUserDataKey() { var name = GetClientTypeName(); @@ -28,6 +29,7 @@ namespace MediaBrowser.Controller.LiveTv public string ServiceName { get; set; } + [IgnoreDataMember] public override string MediaType { get @@ -36,6 +38,7 @@ namespace MediaBrowser.Controller.LiveTv } } + [IgnoreDataMember] public override LocationType LocationType { get @@ -53,6 +56,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets a value indicating whether this instance is owned item. /// </summary> /// <value><c>true</c> if this instance is owned item; otherwise, <c>false</c>.</value> + [IgnoreDataMember] public override bool IsOwnedItem { get @@ -83,5 +87,15 @@ namespace MediaBrowser.Controller.LiveTv { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram); } + + protected override string GetInternalMetadataPath(string basePath) + { + return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N")); + } + + public override bool IsAuthorizedToDelete(User user) + { + return user.Policy.EnableLiveTvManagement; + } } } diff --git a/MediaBrowser.Controller/Localization/BaseStrings.cs b/MediaBrowser.Controller/Localization/BaseStrings.cs deleted file mode 100644 index 22486d90d..000000000 --- a/MediaBrowser.Controller/Localization/BaseStrings.cs +++ /dev/null @@ -1,287 +0,0 @@ - -namespace MediaBrowser.Controller.Localization -{ - public class BaseStrings : LocalizedStringData - { - public BaseStrings() - { - ThisVersion = "1.0002"; - Prefix = LocalizedStrings.BasePrefix; - } - - - - //Config Panel - public string ConfigConfig = "Configuration"; - public string VersionConfig = "Version"; - public string MediaOptionsConfig = "Media Options"; - public string ThemesConfig = "Theme Options"; - public string ParentalControlConfig = "Parental Control"; - public string ContinueConfig = "Continue"; - public string ResetDefaultsConfig = "Reset Defaults"; - public string ClearCacheConfig = "Clear Cache"; - public string UnlockConfig = "Unlock"; - public string GeneralConfig = "General"; - public string EnableScreenSaverConfig = "Screen Saver"; - public string SSTimeOutConfig = "Timeout (mins)"; - public string TrackingConfig = "Tracking"; - public string AssumeWatchedIfOlderThanConfig = "Assume Played If Older Than"; - public string MetadataConfig = "Metadata"; - public string EnableInternetProvidersConfig = "Allow Internet Providers"; - public string UpdatesConfig = "Updates"; - public string AutomaticUpdatesConfig = "Check For Updates"; - public string LoggingConfig = "Logging"; - public string BetaUpdatesConfig = "Beta Updates"; - public string GlobalConfig = "Global"; - public string EnableEHSConfig = "Enable EHS"; - public string ShowClockConfig = "Show Clock"; - public string DimUnselectedPostersConfig = "Dim Unselected Posters"; - public string HideFocusFrameConfig = "Hide Focus Frame"; - public string AlwaysShowDetailsConfig = "Always Show Details"; - public string ExcludeRemoteContentInSearchesConfig = "Exclude Remote Content In Searches"; - public string EnhancedMouseSupportConfig = "Enhanced Mouse Support"; - public string ViewsConfig = "Views"; - public string PosterGridSpacingConfig = "Poster Grid Spacing"; - public string ThumbWidthSplitConfig = "Thumb Width Split"; - public string BreadcrumbCountConfig = "Breadcrumb Count"; - public string ShowFanArtonViewsConfig = "Show Fan Art on Views"; - public string ShowInitialFolderBackgroundConfig = "Show Initial Folder Background"; - public string ShowThemeBackgroundConfig = "Show Theme Background"; - public string ShowHDOverlayonPostersConfig = "Show HD Overlay on Posters"; - public string ShowIcononRemoteContentConfig = "Show Icon on Remote Content"; - public string EnableAdvancedCmdsConfig = "Enable Advanced Commands"; - public string MediaTrackingConfig = "Media Tracking"; - public string RememberFolderIndexingConfig = "Remember Folder Indexing"; - public string ShowUnwatchedCountConfig = "Show Unplayed Count"; - public string WatchedIndicatoronFoldersConfig = "Played Indicator on Folders"; - public string HighlightUnwatchedItemsConfig = "Highlight Unplayed Items"; - public string WatchedIndicatoronVideosConfig = "Played Indicator on Items"; - public string WatchedIndicatorinDetailViewConfig = "Played Indicator in Detail View"; - public string DefaultToFirstUnwatchedItemConfig = "Default To First Unplayed Item"; - public string GeneralBehaviorConfig = "General Behavior"; - public string AllowNestedMovieFoldersConfig = "Allow Nested Movie Folders"; - public string AutoEnterSingleFolderItemsConfig = "Auto Enter Single Folder Items"; - public string MultipleFileBehaviorConfig = "Multiple File Behavior"; - public string TreatMultipleFilesAsSingleMovieConfig = "Treat Multiple Files As Single Movie"; - public string MultipleFileSizeLimitConfig = "Multiple File Size Limit"; - public string MBThemeConfig = "Media Browser Theme"; - public string VisualThemeConfig = "Visual Theme"; - public string ColorSchemeConfig = "Color Scheme *"; - public string FontSizeConfig = "Font Size *"; - public string RequiresRestartConfig = "* Requires a restart to take effect."; - public string ThemeSettingsConfig = "Theme Specific Settings"; - public string ShowConfigButtonConfig = "Show Config Button"; - public string AlphaBlendingConfig = "Alpha Blending"; - public string SecurityPINConfig = "Security PIN"; - public string PCUnlockedTxtConfig = "Parental Controls are Temporarily Unlocked. You cannot change values unless you re-lock."; - public string RelockBtnConfig = "Re-Lock"; - public string EnableParentalBlocksConfig = "Enable Parental Blocks"; - public string MaxAllowedRatingConfig = "Max Allowed Rating "; - public string BlockUnratedContentConfig = "Block Unrated Content"; - public string HideBlockedContentConfig = "Hide Blocked Content"; - public string UnlockonPINEntryConfig = "Unlock on PIN Entry"; - public string UnlockPeriodHoursConfig = "Unlock Period (Hours)"; - public string EnterNewPINConfig = "Enter New PIN"; - public string RandomizeBackdropConfig = "Randomize"; - public string RotateBackdropConfig = "Rotate"; - public string UpdateLibraryConfig = "Update Library"; - public string BackdropSettingsConfig = "Backdrop Settings"; - public string BackdropRotationIntervalConfig = "Rotation Time"; - public string BackdropTransitionIntervalConfig = "Transition Time"; - public string BackdropLoadDelayConfig = "Load Delay"; - public string AutoScrollTextConfig = "Auto Scroll Overview"; - public string SortYearsAscConfig = "Sort by Year in Ascending Order"; - public string AutoValidateConfig = "Automatically Validate Items"; - public string SaveLocalMetaConfig = "Save Locally"; - public string HideEmptyFoldersConfig = "Hide Empty TV Folders"; - - - //EHS - public string RecentlyWatchedEHS = "last played"; - public string RecentlyAddedEHS = "last added"; - public string RecentlyAddedUnwatchedEHS = "last added unplayed"; - public string WatchedEHS = "Played"; - public string AddedEHS = "Added"; - public string UnwatchedEHS = "Unplayed"; - public string AddedOnEHS = "Added on"; - public string OnEHS = "on"; - public string OfEHS = "of"; - public string NoItemsEHS = "No Items To Show"; - public string VariousEHS = "(various)"; - - //Context menu - public string CloseCMenu = "Close"; - public string PlayMenuCMenu = "Play Menu"; - public string ItemMenuCMenu = "Item Menu"; - public string PlayAllCMenu = "Play All"; - public string PlayAllFromHereCMenu = "Play All From Here"; - public string ResumeCMenu = "Resume"; - public string MarkUnwatchedCMenu = "Mark Unplayed"; - public string MarkWatchedCMenu = "Mark Played"; - public string ShufflePlayCMenu = "Shuffle Play"; - - //Media Detail Page - public string GeneralDetail = "General"; - public string ActorsDetail = "Actors"; - public string ArtistsDetail = "Artists"; - public string PlayDetail = "Play"; - public string ResumeDetail = "Resume"; - public string RefreshDetail = "Refresh"; - public string PlayTrailersDetail = "Trailer"; - public string CacheDetail = "Cache 2 xml"; - public string DeleteDetail = "Delete"; - public string TMDBRatingDetail = "TMDb Rating"; - public string OutOfDetail = "out of"; - public string DirectorDetail = "Director"; - public string ComposerDetail = "Composer"; - public string HostDetail = "Host"; - public string RuntimeDetail = "Runtime"; - public string NextItemDetail = "Next"; - public string PreviousItemDetail = "Previous"; - public string FirstAiredDetail = "First aired"; - public string LastPlayedDetail = "Last played"; - public string TrackNumberDetail = "Track"; - - public string DirectedByDetail = "Directed By: "; - public string WrittenByDetail = "Written By: "; - public string ComposedByDetail = "Composed By: "; - - //Display Prefs - public string ViewDispPref = "View"; - public string ViewSearch = "Search"; - public string CoverFlowDispPref = "Cover Flow"; - public string DetailDispPref = "Detail"; - public string PosterDispPref = "Poster"; - public string ThumbDispPref = "Thumb"; - public string ThumbStripDispPref = "Thumb Strip"; - public string ShowLabelsDispPref = "Show Labels"; - public string VerticalScrollDispPref = "Vertical Scroll"; - public string UseBannersDispPref = "Use Banners"; - public string UseCoverflowDispPref = "Use Coverflow Style"; - public string ThumbSizeDispPref = "Thumb Size"; - public string NameDispPref = "Name"; - public string DateDispPref = "Date"; - public string RatingDispPref = "User Rating"; - public string OfficialRatingDispPref = "Rating"; - public string RuntimeDispPref = "Runtime"; - public string UnWatchedDispPref = "Unplayed"; - public string YearDispPref = "Year"; - public string NoneDispPref = "None"; - public string PerformerDispPref = "Performer"; - public string ActorDispPref = "Actor"; - public string GenreDispPref = "Genre"; - public string DirectorDispPref = "Director"; - public string StudioDispPref = "Studio"; - - //Dialog boxes - //public string BrokenEnvironmentDial = "Application will now close due to broken MediaCenterEnvironment object, possibly due to 5 minutes of idle time and/or running with TVPack installed."; - //public string InitialConfigDial = "Initial configuration is complete, please restart Media Browser"; - //public string DeleteMediaDial = "Are you sure you wish to delete this media item?"; - //public string DeleteMediaCapDial = "Delete Confirmation"; - //public string NotDeletedDial = "Item NOT Deleted."; - //public string NotDeletedCapDial = "Delete Cancelled by User"; - //public string NotDelInvalidPathDial = "The selected media item cannot be deleted due to an invalid path. Or you may not have sufficient access rights to perform this command."; - //public string DelFailedDial = "Delete Failed"; - //public string NotDelUnknownDial = "The selected media item cannot be deleted due to an unknown error."; - //public string NotDelTypeDial = "The selected media item cannot be deleted due to its Item-Type or you have not enabled this feature in the configuration file."; - //public string FirstTimeDial = "As this is the first time you have run Media Browser please setup the inital configuration"; - //public string FirstTimeCapDial = "Configure"; - //public string EntryPointErrorDial = "Media Browser could not launch directly into "; - //public string EntryPointErrorCapDial = "Entrypoint Error"; - //public string CriticalErrorDial = "Media Browser encountered a critical error and had to shut down: "; - //public string CriticalErrorCapDial = "Critical Error"; - //public string ClearCacheErrorDial = "An error occured during the clearing of the cache, you may wish to manually clear it from {0} before restarting Media Browser"; - //public string RestartMBDial = "Please restart Media Browser"; - //public string ClearCacheDial = "Are you sure you wish to clear the cache?\nThis will erase all cached and downloaded information and images."; - //public string ClearCacheCapDial = "Clear Cache"; - //public string CacheClearedDial = "Cache Cleared"; - //public string ResetConfigDial = "Are you sure you wish to reset all configuration to defaults?"; - //public string ResetConfigCapDial = "Reset Configuration"; - //public string ConfigResetDial = "Configuration Reset"; - //public string UpdateMBDial = "Please visit www.mediabrowser.tv/download to install the new version."; - //public string UpdateMBCapDial = "Update Available"; - //public string UpdateMBExtDial = "There is an update available for Media Browser. Please update Media Browser next time you are at your MediaCenter PC."; - //public string DLUpdateFailDial = "Media Browser will operate normally and prompt you again the next time you load it."; - //public string DLUpdateFailCapDial = "Update Download Failed"; - //public string UpdateSuccessDial = "Media Browser must now exit to apply the update. It will restart automatically when it is done"; - //public string UpdateSuccessCapDial = "Update Downloaded"; - //public string CustomErrorDial = "Customisation Error"; - //public string ConfigErrorDial = "Reset to default?"; - //public string ConfigErrorCapDial = "Error in configuration file"; - //public string ContentErrorDial = "There was a problem playing the content. Check location exists"; - //public string ContentErrorCapDial = "Content Error"; - //public string CannotMaximizeDial = "We can not maximize the window! This is a known bug with Windows 7 and TV Pack, you will have to restart Media Browser!"; - //public string IncorrectPINDial = "Incorrect PIN Entered"; - //public string ContentProtected = "Content Protected"; - //public string CantChangePINDial = "Cannot Change PIN"; - //public string LibraryUnlockedDial = "Library Temporarily Unlocked. Will Re-Lock in {0} Hour(s) or on Application Re-Start"; - //public string LibraryUnlockedCapDial = "Unlock"; - //public string PINChangedDial = "PIN Successfully Changed"; - //public string PINChangedCapDial = "PIN Change"; - //public string EnterPINToViewDial = "Please Enter PIN to View Protected Content"; - //public string EnterPINToPlayDial = "Please Enter PIN to Play Protected Content"; - //public string EnterCurrentPINDial = "Please Enter CURRENT PIN."; - //public string EnterNewPINDial = "Please Enter NEW PIN (exactly 4 digits)."; - //public string EnterPINDial = "Please Enter PIN to Unlock Library"; - //public string NoContentDial = "No Content that can be played in this context."; - //public string FontsMissingDial = "CustomFonts.mcml as been patched with missing values"; - //public string StyleMissingDial = "{0} has been patched with missing values"; - //public string ManualRefreshDial = "Library Update Started. Will proceed in the background."; - //public string ForcedRebuildDial = "Your library is currently being migrated by the service. The service will re-start when it is finished and you may then run Media Browser."; - //public string ForcedRebuildCapDial = "Library Migration"; - //public string RefreshFailedDial = "The last service refresh process failed. Please run a manual refresh from the service."; - //public string RefreshFailedCapDial = "Service Refresh Failed"; - //public string RebuildNecDial = "This version of Media Browser requires a re-build of your library. It has started automatically in the service. Some information may be incomplete until this process finishes."; - //public string MigrateNecDial = "This version of Media Browser requires a migration of your library. It has started automatically in the service. The service will restart when it is complete and you may then run Media Browser."; - //public string RebuildFailedDial = "There was an error attempting to tell the service to re-build your library. Please run the service and do a manual refresh with the cache clear options selected."; - //public string MigrateFailedDial = "There was an error attempting to tell the service to re-build your library. Please run the service and do a manual refresh with the cache clear options selected."; - //public string RefreshFolderDial = "Refresh all contents too?"; - //public string RefreshFolderCapDial = "Refresh Folder"; - - //Generic - public string Restartstr = "Restart"; - public string Errorstr = "Error"; - public string Playstr = "Play"; - public string MinutesStr = "mins"; //Minutes abbreviation - public string HoursStr = "hrs"; //Hours abbreviation - public string EndsStr = "Ends"; - public string KBsStr = "Kbps"; //Kilobytes per second - public string FrameRateStr = "fps"; //Frames per second - public string AtStr = "at"; //x at y, e.g. 1920x1080 at 25 fps - public string Rated = "Rated"; - public string Or = "Or "; - public string Lower = "Lower"; - public string Higher = "Higher"; - public string Search = "Search"; - public string Cancel = "Cancel"; - public string TitleContains = "Title Contains "; - public string Any = "Any"; - - //Search - public string IncludeNested = "Include Subfolders"; - public string UnwatchedOnly = "Include Only Unwatched"; - public string FilterByRated = "Filter by Rating"; - - //Profiler - public string WelcomeProf = "Welcome to Media Browser"; - public string ProfilerTimeProf = "{1} took {2} seconds."; - public string RefreshProf = "Refresh"; - public string SetWatchedProf = "Set Played {0}"; - public string RefreshFolderProf = "Refresh Folder and all Contents of"; - public string ClearWatchedProf = "Clear Played {0}"; - public string FullRefreshProf = "Full Library Refresh"; - public string FullValidationProf = "Full Library Validation"; - public string FastRefreshProf = "Fast Metadata refresh"; - public string SlowRefresh = "Slow Metadata refresh"; - public string ImageRefresh = "Image refresh"; - public string PluginUpdateProf = "An update is available for plug-in {0}"; - public string NoPluginUpdateProf = "No Plugin Updates Currently Available."; - public string LibraryUnLockedProf = "Library Temporarily UnLocked. Will Re-Lock in {0} Hour(s)"; - public string LibraryReLockedProf = "Library Re-Locked"; - - //Messages - public string FullRefreshMsg = "Updating Media Library..."; - public string FullRefreshFinishedMsg = "Library update complete"; - - } -} diff --git a/MediaBrowser.Controller/Localization/LocalizedStringData.cs b/MediaBrowser.Controller/Localization/LocalizedStringData.cs deleted file mode 100644 index 71200b8c8..000000000 --- a/MediaBrowser.Controller/Localization/LocalizedStringData.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.IO; -using System.Xml.Serialization; - -namespace MediaBrowser.Controller.Localization -{ - /// <summary> - /// Class LocalizedStringData - /// </summary> - public class LocalizedStringData - { - /// <summary> - /// The this version - /// </summary> - [XmlIgnore] - public string ThisVersion = "1.0000"; - /// <summary> - /// The prefix - /// </summary> - [XmlIgnore] - public string Prefix = ""; - /// <summary> - /// The file name - /// </summary> - public string FileName; //this is public so it will serialize and we know where to save ourselves - /// <summary> - /// The version - /// </summary> - public string Version = ""; //this will get saved so we can check it against us for changes - - /// <summary> - /// Saves this instance. - /// </summary> - public void Save() - { - Save(FileName); - } - - /// <summary> - /// Saves the specified file. - /// </summary> - /// <param name="file">The file.</param> - public void Save(string file) - { - var xs = new XmlSerializer(GetType()); - using (var fs = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None)) - { - xs.Serialize(fs, this); - } - } - } -} diff --git a/MediaBrowser.Controller/Localization/LocalizedStrings.cs b/MediaBrowser.Controller/Localization/LocalizedStrings.cs deleted file mode 100644 index 94ac90271..000000000 --- a/MediaBrowser.Controller/Localization/LocalizedStrings.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; - -namespace MediaBrowser.Controller.Localization -{ - /// <summary> - /// Class LocalizedStrings - /// </summary> - public class LocalizedStrings - { - public static IServerApplicationPaths ApplicationPaths; - - /// <summary> - /// Gets the list of Localized string files - /// </summary> - /// <value>The string files.</value> - public static IEnumerable<LocalizedStringData> StringFiles { get; set; } - - /// <summary> - /// The base prefix - /// </summary> - public const string BasePrefix = "base-"; - /// <summary> - /// The local strings - /// </summary> - protected ConcurrentDictionary<string, string> LocalStrings = new ConcurrentDictionary<string, string>(); - /// <summary> - /// The _instance - /// </summary> - private static LocalizedStrings _instance; - - private readonly IServerApplicationPaths _appPaths; - - /// <summary> - /// Gets the instance. - /// </summary> - /// <value>The instance.</value> - public static LocalizedStrings Instance { get { return _instance ?? (_instance = new LocalizedStrings(ApplicationPaths)); } } - - /// <summary> - /// Initializes a new instance of the <see cref="LocalizedStrings" /> class. - /// </summary> - public LocalizedStrings(IServerApplicationPaths appPaths) - { - _appPaths = appPaths; - - foreach (var stringObject in StringFiles) - { - AddStringData(LoadFromFile(GetFileName(stringObject),stringObject.GetType())); - } - } - - /// <summary> - /// Gets the name of the file. - /// </summary> - /// <param name="stringObject">The string object.</param> - /// <returns>System.String.</returns> - protected string GetFileName(LocalizedStringData stringObject) - { - var path = _appPaths.LocalizationPath; - var name = Path.Combine(path, stringObject.Prefix + "strings-" + CultureInfo.CurrentCulture + ".xml"); - if (File.Exists(name)) - { - return name; - } - - name = Path.Combine(path, stringObject.Prefix + "strings-" + CultureInfo.CurrentCulture.Parent + ".xml"); - if (File.Exists(name)) - { - return name; - } - - //just return default - return Path.Combine(path, stringObject.Prefix + "strings-en.xml"); - } - - /// <summary> - /// Loads from file. - /// </summary> - /// <param name="file">The file.</param> - /// <param name="t">The t.</param> - /// <returns>LocalizedStringData.</returns> - protected LocalizedStringData LoadFromFile(string file, Type t) - { - return new BaseStrings {FileName = file}; - //var xs = new XmlSerializer(t); - //var strings = (LocalizedStringData)Activator.CreateInstance(t); - //strings.FileName = file; - //Logger.Info("Using String Data from {0}", file); - //if (File.Exists(file)) - //{ - // using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read)) - // { - // strings = (LocalizedStringData)xs.Deserialize(fs); - // } - //} - //else - //{ - // strings.Save(); //brand new - save it - //} - - //if (strings.ThisVersion != strings.Version && file.ToLower().Contains("-en.xml")) - //{ - // //only re-save the english version as that is the one defined internally - // strings = new BaseStrings {FileName = file}; - // strings.Save(); - //} - //return strings; - - } - - /// <summary> - /// Adds the string data. - /// </summary> - /// <param name="stringData">The string data.</param> - public void AddStringData(object stringData ) - { - //translate our object definition into a dictionary for lookups - // and a reverse dictionary so we can lookup keys by value - foreach (var field in stringData.GetType().GetFields().Where(f => f != null && f.FieldType == typeof(string))) - { - string value; - - try - { - value = field.GetValue(stringData) as string; - } - catch (TargetException) - { - //Logger.ErrorException("Error getting value for field: {0}", ex, field.Name); - continue; - } - catch (FieldAccessException) - { - //Logger.ErrorException("Error getting value for field: {0}", ex, field.Name); - continue; - } - catch (NotSupportedException) - { - //Logger.ErrorException("Error getting value for field: {0}", ex, field.Name); - continue; - } - - LocalStrings.TryAdd(field.Name, value); - } - } - - /// <summary> - /// Gets the string. - /// </summary> - /// <param name="key">The key.</param> - /// <returns>System.String.</returns> - public string GetString(string key) - { - string value; - - LocalStrings.TryGetValue(key, out value); - return value; - } - } -} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 0667730fd..e9531e057 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -101,6 +101,7 @@ <Compile Include="Collections\ICollectionManager.cs" /> <Compile Include="Connect\IConnectManager.cs" /> <Compile Include="Connect\UserLinkResult.cs" /> + <Compile Include="Devices\CameraImageUploadInfo.cs" /> <Compile Include="Devices\IDeviceManager.cs" /> <Compile Include="Devices\IDeviceRepository.cs" /> <Compile Include="Dlna\ControlRequest.cs" /> @@ -110,6 +111,7 @@ <Compile Include="Dlna\IContentDirectory.cs" /> <Compile Include="Dlna\IDlnaManager.cs" /> <Compile Include="Dlna\IEventManager.cs" /> + <Compile Include="Dlna\IMediaReceiverRegistrar.cs" /> <Compile Include="Dlna\IUpnpService.cs" /> <Compile Include="Drawing\IImageProcessor.cs" /> <Compile Include="Drawing\ImageProcessingOptions.cs" /> @@ -117,7 +119,6 @@ <Compile Include="Drawing\ImageStream.cs" /> <Compile Include="Dto\DtoOptions.cs" /> <Compile Include="Dto\IDtoService.cs" /> - <Compile Include="Entities\AdultVideo.cs" /> <Compile Include="Entities\Audio\IHasAlbumArtist.cs" /> <Compile Include="Entities\Audio\IHasMusicGenres.cs" /> <Compile Include="Entities\Book.cs" /> @@ -169,6 +170,7 @@ <Compile Include="FileOrganization\IFileOrganizationService.cs" /> <Compile Include="Library\DeleteOptions.cs" /> <Compile Include="Library\ILibraryPostScanTask.cs" /> + <Compile Include="Library\IMediaSourceManager.cs" /> <Compile Include="Library\IMetadataFileSaver.cs" /> <Compile Include="Library\IMetadataSaver.cs" /> <Compile Include="Library\IMusicManager.cs" /> @@ -312,9 +314,6 @@ <Compile Include="Library\ILibraryManager.cs" /> <Compile Include="Library\IUserManager.cs" /> <Compile Include="Library\Profiler.cs" /> - <Compile Include="Localization\BaseStrings.cs" /> - <Compile Include="Localization\LocalizedStringData.cs" /> - <Compile Include="Localization\LocalizedStrings.cs" /> <Compile Include="Persistence\IDisplayPreferencesRepository.cs" /> <Compile Include="Persistence\IItemRepository.cs" /> <Compile Include="Persistence\IRepository.cs" /> @@ -343,6 +342,7 @@ <Compile Include="Subtitles\SubtitleResponse.cs" /> <Compile Include="Subtitles\SubtitleSearchRequest.cs" /> <Compile Include="Sync\ICloudSyncProvider.cs" /> + <Compile Include="Sync\IServerSyncProvider.cs" /> <Compile Include="Sync\ISyncManager.cs" /> <Compile Include="Sync\ISyncProvider.cs" /> <Compile Include="Sync\ISyncRepository.cs" /> diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index a988c2f97..fe0fb3295 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Controller.MediaEncoding public class EncodingJobOptions { public string OutputContainer { get; set; } + public string OutputDirectory { get; set; } public long? StartTimeTicks { get; set; } public int? Width { get; set; } @@ -80,12 +81,17 @@ namespace MediaBrowser.Controller.MediaEncoding VideoCodec = info.VideoCodec; VideoBitRate = info.VideoBitrate; AudioStreamIndex = info.AudioStreamIndex; - SubtitleStreamIndex = info.SubtitleStreamIndex; MaxRefFrames = info.MaxRefFrames; MaxVideoBitDepth = info.MaxVideoBitDepth; SubtitleMethod = info.SubtitleDeliveryMethod; Cabac = info.Cabac; Context = info.Context; + + if (info.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode || + info.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Embed) + { + SubtitleStreamIndex = info.SubtitleStreamIndex; + } } } } diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs index 9e32fc32b..37c2bf4d2 100644 --- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs @@ -47,9 +47,8 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets the subtitle language encoding parameter. /// </summary> /// <param name="path">The path.</param> - /// <param name="language">The language.</param> /// <returns>System.String.</returns> - string GetSubtitleFileCharacterSet(string path, string language); + string GetSubtitleFileCharacterSet(string path); } } diff --git a/MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs b/MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs index 4a807df7a..57fddb2b1 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaStreamSelector.cs @@ -38,7 +38,8 @@ namespace MediaBrowser.Controller.MediaEncoding SubtitlePlaybackMode mode, string audioTrackLanguage) { - streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages).ToList(); + streams = GetSortedStreams(streams, MediaStreamType.Subtitle, preferredLanguages) + .ToList(); var full = streams.Where(s => !s.IsForced); @@ -81,21 +82,24 @@ namespace MediaBrowser.Controller.MediaEncoding private static IEnumerable<MediaStream> GetSortedStreams(IEnumerable<MediaStream> streams, MediaStreamType type, List<string> languagePreferences) { - var orderStreams = streams - .Where(i => i.Type == type); - // Give some preferance to external text subs for better performance - return orderStreams.OrderBy(i => + return streams.Where(i => i.Type == type) + .OrderBy(i => { var index = languagePreferences.FindIndex(l => string.Equals(i.Language, l, StringComparison.OrdinalIgnoreCase)); return index == -1 ? 100 : index; }) - .ThenBy(i => i.IsDefault) - .ThenBy(i => i.IsTextSubtitleStream) - .ThenBy(i => i.IsExternal) - .ThenBy(i => i.Index) - .ToList(); + .ThenBy(i => GetBooleanOrderBy(i.IsDefault)) + .ThenBy(i => GetBooleanOrderBy(i.SupportsExternalStream)) + .ThenBy(i => GetBooleanOrderBy(i.IsTextSubtitleStream)) + .ThenBy(i => GetBooleanOrderBy(i.IsExternal)) + .ThenBy(i => i.Index); + } + + private static int GetBooleanOrderBy(bool value) + { + return value ? 0 : 1; } } } diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index f1e371c1a..990d23970 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -93,6 +93,11 @@ namespace MediaBrowser.Controller.Net } } + protected virtual void ParseMessageParams(string[] values) + { + + } + /// <summary> /// Starts sending messages over a web socket /// </summary> @@ -104,6 +109,11 @@ namespace MediaBrowser.Controller.Net var dueTimeMs = long.Parse(vals[0], UsCulture); var periodMs = long.Parse(vals[1], UsCulture); + if (vals.Length > 2) + { + ParseMessageParams(vals.Skip(2).ToArray()); + } + var cancellationTokenSource = new CancellationTokenSource(); Logger.Info("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs index 5b179d479..315b48b83 100644 --- a/MediaBrowser.Controller/Net/IHttpServer.cs +++ b/MediaBrowser.Controller/Net/IHttpServer.cs @@ -1,4 +1,3 @@ -using MediaBrowser.Common.Net; using System; using System.Collections.Generic; @@ -16,10 +15,18 @@ namespace MediaBrowser.Controller.Net IEnumerable<string> UrlPrefixes { get; } /// <summary> + /// Gets the certificate path. + /// </summary> + /// <value>The certificate path.</value> + string CertificatePath { get; } + + /// <summary> /// Starts the specified server name. /// </summary> /// <param name="urlPrefixes">The URL prefixes.</param> - void StartServer(IEnumerable<string> urlPrefixes); + /// <param name="certificatePath">If an https prefix is specified, + /// the ssl certificate localtion on the file system.</param> + void StartServer(IEnumerable<string> urlPrefixes, string certificatePath); /// <summary> /// Gets the local end points. diff --git a/MediaBrowser.Controller/Net/IServerManager.cs b/MediaBrowser.Controller/Net/IServerManager.cs index dff086347..d90a0f8ed 100644 --- a/MediaBrowser.Controller/Net/IServerManager.cs +++ b/MediaBrowser.Controller/Net/IServerManager.cs @@ -15,7 +15,9 @@ namespace MediaBrowser.Controller.Net /// Starts this instance. /// </summary> /// <param name="urlPrefixes">The URL prefixes.</param> - void Start(IEnumerable<string> urlPrefixes); + /// <param name="certificatePath">If an https prefix is specified, + /// the ssl certificate localtion on the file system.</param> + void Start(IEnumerable<string> urlPrefixes, string certificatePath); /// <summary> /// Sends a message to all clients currently connected via a web socket diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index e48cddaaa..3479902cb 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -1,7 +1,5 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using System; @@ -40,6 +38,11 @@ namespace MediaBrowser.Controller.Playlists } } + public override bool IsAuthorizedToDelete(User user) + { + return true; + } + public override bool IsSaveLocalMetadataEnabled() { return true; @@ -50,9 +53,16 @@ namespace MediaBrowser.Controller.Playlists return GetPlayableItems(user); } - public override IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true) + public override IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter) { - return GetPlayableItems(user); + var items = GetPlayableItems(user); + + if (filter != null) + { + items = items.Where(filter); + } + + return items; } public IEnumerable<Tuple<LinkedChild, BaseItem>> GetManageableItems() @@ -76,75 +86,51 @@ namespace MediaBrowser.Controller.Playlists .Where(m => string.Equals(m.MediaType, playlistMediaType, StringComparison.OrdinalIgnoreCase)); } - private static IEnumerable<BaseItem> GetPlaylistItems(BaseItem i, User user) + private static IEnumerable<BaseItem> GetPlaylistItems(BaseItem item, User user) { - var musicGenre = i as MusicGenre; + var musicGenre = item as MusicGenre; if (musicGenre != null) { - var items = user == null - ? LibraryManager.RootFolder.GetRecursiveChildren() - : user.RootFolder.GetRecursiveChildren(user, true); - - var songs = items - .OfType<Audio>() - .Where(a => a.Genres.Contains(musicGenre.Name, StringComparer.OrdinalIgnoreCase)); + Func<BaseItem, bool> filter = i => i is Audio && i.Genres.Contains(musicGenre.Name, StringComparer.OrdinalIgnoreCase); - return LibraryManager.Sort(songs, user, new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }, SortOrder.Ascending); - } - - var musicArtist = i as MusicArtist; - if (musicArtist != null) - { var items = user == null - ? LibraryManager.RootFolder.GetRecursiveChildren() - : user.RootFolder.GetRecursiveChildren(user, true); + ? LibraryManager.RootFolder.GetRecursiveChildren(filter) + : user.RootFolder.GetRecursiveChildren(user, filter); - var songs = items - .OfType<Audio>() - .Where(a => a.HasArtist(musicArtist.Name)); - - return LibraryManager.Sort(songs, user, new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }, SortOrder.Ascending); + return LibraryManager.Sort(items, user, new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }, SortOrder.Ascending); } - // Grab these explicitly to avoid the sorting that will happen below - var collection = i as BoxSet; - if (collection != null) + var musicArtist = item as MusicArtist; + if (musicArtist != null) { - var items = user == null - ? collection.Children - : collection.GetChildren(user, true); + Func<BaseItem, bool> filter = i => + { + var audio = i as Audio; + return audio != null && audio.HasArtist(musicArtist.Name); + }; - return items - .Where(m => !m.IsFolder); - } - - // Grab these explicitly to avoid the sorting that will happen below - var season = i as Season; - if (season != null) - { var items = user == null - ? season.Children - : season.GetChildren(user, true); + ? LibraryManager.RootFolder.GetRecursiveChildren(filter) + : user.RootFolder.GetRecursiveChildren(user, filter); - return items - .Where(m => !m.IsFolder); + return LibraryManager.Sort(items, user, new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }, SortOrder.Ascending); } - var folder = i as Folder; - + var folder = item as Folder; if (folder != null) { var items = user == null - ? folder.GetRecursiveChildren() - : folder.GetRecursiveChildren(user, true); - - items = items - .Where(m => !m.IsFolder); + ? folder.GetRecursiveChildren(m => !m.IsFolder) + : folder.GetRecursiveChildren(user, m => !m.IsFolder); + if (folder.IsPreSorted) + { + return items; + } return LibraryManager.Sort(items, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending); } - return new[] { i }; + return new[] { item }; } [IgnoreDataMember] diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index a9e155509..2cd119cf5 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -11,6 +11,8 @@ namespace MediaBrowser.Controller.Providers /// </summary> public bool ReplaceAllMetadata { get; set; } + public bool IsPostRecursiveRefresh { get; set; } + public MetadataRefreshMode MetadataRefreshMode { get; set; } public bool ForceSave { get; set; } diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs index d6dd7698e..a4badee47 100644 --- a/MediaBrowser.Controller/Session/ISessionController.cs +++ b/MediaBrowser.Controller/Session/ISessionController.cs @@ -105,5 +105,15 @@ namespace MediaBrowser.Controller.Session /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> Task SendServerRestartNotification(CancellationToken cancellationToken); + + /// <summary> + /// Sends the message. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="name">The name.</param> + /// <param name="data">The data.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task SendMessage<T>(string name, T data, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index f0272b335..4082f5600 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -171,6 +171,29 @@ namespace MediaBrowser.Controller.Session Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken); /// <summary> + /// Sends the message to user sessions. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="userId">The user identifier.</param> + /// <param name="name">The name.</param> + /// <param name="data">The data.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task SendMessageToUserSessions<T>(string userId, string name, T data, CancellationToken cancellationToken); + + /// <summary> + /// Sends the message to user device sessions. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="deviceId">The device identifier.</param> + /// <param name="name">The name.</param> + /// <param name="data">The data.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task SendMessageToUserDeviceSessions<T>(string deviceId, string name, T data, + CancellationToken cancellationToken); + + /// <summary> /// Sends the restart required message. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index d8a2464d6..078d4d70f 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -160,6 +160,11 @@ namespace MediaBrowser.Controller.Session } } + public bool ContainsUser(string userId) + { + return ContainsUser(new Guid(userId)); + } + public bool ContainsUser(Guid userId) { return (UserId ?? Guid.Empty) == userId || AdditionalUsers.Any(i => userId == new Guid(i.UserId)); diff --git a/MediaBrowser.Controller/Sync/ICloudSyncProvider.cs b/MediaBrowser.Controller/Sync/ICloudSyncProvider.cs index f93360c64..f9327a71c 100644 --- a/MediaBrowser.Controller/Sync/ICloudSyncProvider.cs +++ b/MediaBrowser.Controller/Sync/ICloudSyncProvider.cs @@ -1,4 +1,6 @@ - +using MediaBrowser.Model.Sync; +using System.Collections.Generic; + namespace MediaBrowser.Controller.Sync { public interface ICloudSyncProvider @@ -8,5 +10,12 @@ namespace MediaBrowser.Controller.Sync /// </summary> /// <value>The name.</value> string Name { get; } + + /// <summary> + /// Gets the synchronize targets. + /// </summary> + /// <param name="userId">The user identifier.</param> + /// <returns>IEnumerable<SyncTarget>.</returns> + IEnumerable<SyncTarget> GetSyncTargets(string userId); } } diff --git a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs new file mode 100644 index 000000000..8ef54fd43 --- /dev/null +++ b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs @@ -0,0 +1,42 @@ +using MediaBrowser.Model.Sync; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Sync +{ + public interface IServerSyncProvider : ISyncProvider + { + /// <summary> + /// Gets the server item ids. + /// </summary> + /// <param name="serverId">The server identifier.</param> + /// <param name="target">The target.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task<List<System.String>>.</returns> + Task<List<string>> GetServerItemIds(string serverId, SyncTarget target, CancellationToken cancellationToken); + + /// <summary> + /// Removes the item. + /// </summary> + /// <param name="serverId">The server identifier.</param> + /// <param name="itemId">The item identifier.</param> + /// <param name="target">The target.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task DeleteItem(string serverId, string itemId, SyncTarget target, CancellationToken cancellationToken); + + /// <summary> + /// Transfers the file. + /// </summary> + /// <param name="serverId">The server identifier.</param> + /// <param name="itemId">The item identifier.</param> + /// <param name="pathParts">The path parts.</param> + /// <param name="name">The name.</param> + /// <param name="fileType">Type of the file.</param> + /// <param name="target">The target.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task TransferItemFile(string serverId, string itemId, string[] pathParts, string name, ItemFileType fileType, SyncTarget target, CancellationToken cancellationToken); + } +} diff --git a/MediaBrowser.Controller/Sync/ISyncManager.cs b/MediaBrowser.Controller/Sync/ISyncManager.cs index 59136c0e6..4d654575e 100644 --- a/MediaBrowser.Controller/Sync/ISyncManager.cs +++ b/MediaBrowser.Controller/Sync/ISyncManager.cs @@ -1,8 +1,10 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Events; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Sync; using MediaBrowser.Model.Users; +using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -10,6 +12,12 @@ namespace MediaBrowser.Controller.Sync { public interface ISyncManager { + event EventHandler<GenericEventArgs<SyncJobCreationResult>> SyncJobCreated; + event EventHandler<GenericEventArgs<SyncJob>> SyncJobCancelled; + event EventHandler<GenericEventArgs<SyncJob>> SyncJobUpdated; + event EventHandler<GenericEventArgs<SyncJobItem>> SyncJobItemUpdated; + event EventHandler<GenericEventArgs<SyncJobItem>> SyncJobItemCreated; + /// <summary> /// Creates the job. /// </summary> @@ -29,7 +37,7 @@ namespace MediaBrowser.Controller.Sync /// <param name="query">The query.</param> /// <returns>QueryResult<SyncJobItem>.</returns> QueryResult<SyncJobItem> GetJobItems(SyncJobItemQuery query); - + /// <summary> /// Gets the job. /// </summary> @@ -45,6 +53,20 @@ namespace MediaBrowser.Controller.Sync Task UpdateJob(SyncJob job); /// <summary> + /// Res the enable job item. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Task.</returns> + Task ReEnableJobItem(string id); + + /// <summary> + /// Cnacels the job item. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Task.</returns> + Task CancelJobItem(string id); + + /// <summary> /// Cancels the job. /// </summary> /// <param name="id">The identifier.</param> @@ -109,5 +131,55 @@ namespace MediaBrowser.Controller.Sync /// <param name="request">The request.</param> /// <returns>Task<SyncDataResponse>.</returns> Task<SyncDataResponse> SyncData(SyncDataRequest request); + + /// <summary> + /// Marks the job item for removal. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Task.</returns> + Task MarkJobItemForRemoval(string id); + + /// <summary> + /// Unmarks the job item for removal. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Task.</returns> + Task UnmarkJobItemForRemoval(string id); + + /// <summary> + /// Gets the library item ids. + /// </summary> + /// <param name="query">The query.</param> + /// <returns>QueryResult<System.String>.</returns> + QueryResult<string> GetLibraryItemIds(SyncJobItemQuery query); + + /// <summary> + /// Gets the audio options. + /// </summary> + /// <param name="jobItem">The job item.</param> + /// <returns>AudioOptions.</returns> + AudioOptions GetAudioOptions(SyncJobItem jobItem); + + /// <summary> + /// Gets the video options. + /// </summary> + /// <param name="jobItem">The job item.</param> + /// <param name="job">The job.</param> + /// <returns>VideoOptions.</returns> + VideoOptions GetVideoOptions(SyncJobItem jobItem, SyncJob job); + + /// <summary> + /// Reports the synchronize job item transfer beginning. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Task.</returns> + Task ReportSyncJobItemTransferBeginning(string id); + + /// <summary> + /// Reports the synchronize job item transfer failed. + /// </summary> + /// <param name="id">The identifier.</param> + /// <returns>Task.</returns> + Task ReportSyncJobItemTransferFailed(string id); } } diff --git a/MediaBrowser.Controller/Sync/ISyncProvider.cs b/MediaBrowser.Controller/Sync/ISyncProvider.cs index af08edb5e..6f24eac1a 100644 --- a/MediaBrowser.Controller/Sync/ISyncProvider.cs +++ b/MediaBrowser.Controller/Sync/ISyncProvider.cs @@ -15,12 +15,6 @@ namespace MediaBrowser.Controller.Sync /// <summary> /// Gets the synchronize targets. /// </summary> - /// <returns>IEnumerable<SyncTarget>.</returns> - IEnumerable<SyncTarget> GetSyncTargets(); - - /// <summary> - /// Gets the synchronize targets. - /// </summary> /// <param name="userId">The user identifier.</param> /// <returns>IEnumerable<SyncTarget>.</returns> IEnumerable<SyncTarget> GetSyncTargets(string userId); diff --git a/MediaBrowser.Controller/Sync/ISyncRepository.cs b/MediaBrowser.Controller/Sync/ISyncRepository.cs index f1bcd7f07..315f5f541 100644 --- a/MediaBrowser.Controller/Sync/ISyncRepository.cs +++ b/MediaBrowser.Controller/Sync/ISyncRepository.cs @@ -68,5 +68,12 @@ namespace MediaBrowser.Controller.Sync /// <param name="query">The query.</param> /// <returns>IEnumerable<SyncJobItem>.</returns> QueryResult<SyncJobItem> GetJobItems(SyncJobItemQuery query); + + /// <summary> + /// Gets the library item ids. + /// </summary> + /// <param name="query">The query.</param> + /// <returns>QueryResult<System.String>.</returns> + QueryResult<string> GetLibraryItemIds(SyncJobItemQuery query); } } |
