diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index a482f45fe0..ab76f4e67f 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 1379ba829e..75a09a7b04 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 e85dee354a..fe9bea53b1 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 7aa924be0f..e3dd832248 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 96b728bdc1..da55724075 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 ba3065bc9d..561ae1e41e 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 8d22f25a90..bf5624f7a9 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 c8e09dd826..7f71c85c59 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 0000000000..5a30c435cf
--- /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 0000000000..bce75b41fc
--- /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 9606cbe3fe..c82b887bae 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 37f7e31fa6..47903525b6 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 184a7f9a4e..cb99b57bbd 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 a75f4c83bb..e78b19c059 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 bc610b7b65..19098a3eea 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -90,7 +90,7 @@
PreserveNewest
-
+
PreserveNewest