diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index a482f45fe..ab76f4e67 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 { @@ -72,5 +73,10 @@ namespace MediaBrowser.Controller.Channels { return false; } + + protected override bool IsTagFilterEnforced(TagFilterMode mode) + { + return false; + } } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 1379ba829..75a09a7b0 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1080,7 +1080,7 @@ namespace MediaBrowser.Controller.Entities if (hasTags != null) { - if (user.Policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) + if (user.Policy.TagFilters.Any(i => !IsTagFilterAccepted(hasTags, i))) { return false; } @@ -1089,6 +1089,36 @@ namespace MediaBrowser.Controller.Entities return true; } + private bool IsTagFilterAccepted(IHasTags hasTags, TagFilter filter) + { + if (IsTagFilterEnforced(filter.Mode)) + { + if (filter.Mode == TagFilterMode.Block) + { + // If content has the tag, it's not allowed + if (hasTags.Tags.Contains(filter.Tag, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + } + else if (filter.Mode == TagFilterMode.Allow) + { + // If content doesn't have the tag, it's not allowed + if (!hasTags.Tags.Contains(filter.Tag, StringComparer.OrdinalIgnoreCase)) + { + return false; + } + } + } + + return true; + } + + protected virtual bool IsTagFilterEnforced(TagFilterMode mode) + { + return true; + } + /// /// Gets the block unrated value. /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index e85dee354..fe9bea53b 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -14,6 +14,7 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -79,6 +80,19 @@ namespace MediaBrowser.Controller.Entities } } + protected override bool IsTagFilterEnforced(TagFilterMode mode) + { + if (this is ICollectionFolder) + { + return false; + } + if (this is UserView) + { + return false; + } + return true; + } + /// /// Gets or sets a value indicating whether this instance is physical root. /// diff --git a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs index 7aa924be0..e3dd83224 100644 --- a/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs +++ b/MediaBrowser.Dlna/Profiles/Xbox360Profile.cs @@ -15,11 +15,11 @@ namespace MediaBrowser.Dlna.Profiles Name = "Xbox 360"; // Required according to above - ModelName = "Windows Media Connect"; + ModelName = "Windows Media Player Sharing"; ModelNumber = "12.0"; - FriendlyName = "${HostName} : 1 : Windows Media Connect"; + FriendlyName = "${HostName} : 1"; ModelUrl = "http://www.microsoft.com/"; Manufacturer = "Microsoft Corporation"; diff --git a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml index 96b728bdc..da5572407 100644 --- a/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml +++ b/MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml @@ -8,10 +8,10 @@ - ${HostName} : 1 : Windows Media Connect + ${HostName} : 1 Microsoft Corporation http://www.microsoft.com/ - Windows Media Connect + Windows Media Player Sharing Media Browser 12.0 http://www.microsoft.com/ diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index ba3065bc9..561ae1e41 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -1181,6 +1181,12 @@ Users\PinRedeemResult.cs + + Users\TagFilter.cs + + + Users\TagFilterMode.cs + Users\UserAction.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 8d22f25a9..bf5624f7a 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -1140,6 +1140,12 @@ Users\PinRedeemResult.cs + + Users\TagFilter.cs + + + Users\TagFilterMode.cs + Users\UserAction.cs diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index c8e09dd82..7f71c85c5 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -433,6 +433,8 @@ + + diff --git a/MediaBrowser.Model/Users/TagFilter.cs b/MediaBrowser.Model/Users/TagFilter.cs new file mode 100644 index 000000000..5a30c435c --- /dev/null +++ b/MediaBrowser.Model/Users/TagFilter.cs @@ -0,0 +1,9 @@ + +namespace MediaBrowser.Model.Users +{ + public class TagFilter + { + public string Tag { get; set; } + public TagFilterMode Mode { get; set; } + } +} diff --git a/MediaBrowser.Model/Users/TagFilterMode.cs b/MediaBrowser.Model/Users/TagFilterMode.cs new file mode 100644 index 000000000..bce75b41f --- /dev/null +++ b/MediaBrowser.Model/Users/TagFilterMode.cs @@ -0,0 +1,9 @@ + +namespace MediaBrowser.Model.Users +{ + public enum TagFilterMode + { + Block = 0, + Allow = 1 + } +} diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 9606cbe3f..c82b887ba 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -58,6 +58,8 @@ namespace MediaBrowser.Model.Users public string[] EnabledFolders { get; set; } public bool EnableAllFolders { get; set; } + + public TagFilter[] TagFilters { get; set; } public UserPolicy() { @@ -66,7 +68,6 @@ namespace MediaBrowser.Model.Users EnableLiveTvAccess = true; EnableSharedDeviceControl = true; - BlockedTags = new string[] { }; BlockUnratedItems = new UnratedItem[] { }; EnableUserPreferenceAccess = true; @@ -83,6 +84,8 @@ namespace MediaBrowser.Model.Users EnableAllDevices = true; EnableContentDownloading = true; + + TagFilters = new TagFilter[] { }; } } } diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 37f7e31fa..47903525b 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -168,6 +168,7 @@ namespace MediaBrowser.Server.Implementations.Library foreach (var user in users) { await DoPolicyMigration(user).ConfigureAwait(false); + await DoBlockedTagMigration(user).ConfigureAwait(false); } // If there are no local users with admin rights, make them all admins @@ -346,6 +347,25 @@ namespace MediaBrowser.Server.Implementations.Library } } + private async Task DoBlockedTagMigration(User user) + { + if (user.Policy.BlockedTags != null) + { + user.Policy.TagFilters = user.Policy + .BlockedTags + .Select(i => new TagFilter + { + Tag = i, + Mode = TagFilterMode.Block + }) + .ToArray(); + + user.Policy.BlockedTags = null; + + await UpdateUserPolicy(user, user.Policy, false); + } + } + public UserDto GetUserDto(User user, string remoteEndPoint = null) { if (user == null) diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 184a7f9a4..cb99b57bb 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -276,7 +276,7 @@ "ButtonStart": "Start", "HeaderChannels": "Channels", "HeaderMediaFolders": "Media Folders", - "HeaderBlockItemsWithNoRating": "Block items with no rating information:", + "HeaderBlockItemsWithNoRating": "Block content with no rating information:", "OptionBlockOthers": "Others", "OptionBlockTvShows": "TV Shows", "OptionBlockTrailers": "Trailers", diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index a75f4c83b..e78b19c05 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1356,8 +1356,10 @@ "HeaderVideoTypes": "Video Types", "HeaderYears": "Years", "HeaderAddTag": "Add Tag", - "LabelBlockItemsWithTags": "Block items with tags:", + "LabelBlockOrAllowItemsWithTags": "Block or allow content with tags:", "LabelTag": "Tag:", + "OptionBlockItemWithTag": "Block all content with this tag", + "OptionAllowItemWithTag": "Allow only content with this tag", "LabelEnableSingleImageInDidlLimit": "Limit to single embedded image", "LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.", "TabActivity": "Activity", @@ -1368,5 +1370,7 @@ "NameSeasonNumber": "Season {0}", "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)", "TabJobs": "Jobs", - "TabSyncJobs": "Sync Jobs" + "TabSyncJobs": "Sync Jobs", + "LabelTagFilterMode": "Mode:", + "LabelTagFilterAllowModeHelp": "If used as part of a deeply nested folder structure, content that is tagged with this mechanism will require parent folders to be tagged as well." } diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index bc610b7b6..19098a3ee 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -90,7 +90,7 @@ PreserveNewest - + PreserveNewest