aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs29
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs81
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs153
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs12
-rw-r--r--MediaBrowser.WebDashboard/ApiClient.js48
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj12
-rw-r--r--MediaBrowser.WebDashboard/packages.config2
7 files changed, 209 insertions, 128 deletions
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index a0ad1fb2a..f96a4baa7 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -62,7 +62,12 @@ namespace MediaBrowser.Api.UserLibrary
items = new[] { item };
}
+ items = FilterItems(request, items, user);
+
+ items = ItemsService.ApplySortOrder(request, items, user, LibraryManager);
+
var ibnItemsArray = GetAllItems(request, items, user).ToArray();
+
IEnumerable<Tuple<string, Func<int>>> ibnItems = ibnItemsArray;
var result = new ItemsResult
@@ -84,7 +89,7 @@ namespace MediaBrowser.Api.UserLibrary
}
- var fields = GetItemFields(request).ToList();
+ var fields = request.GetItemFields().ToList();
var tasks = ibnItems.Select(i => GetDto(i, user, fields));
@@ -96,20 +101,28 @@ namespace MediaBrowser.Api.UserLibrary
}
/// <summary>
- /// Gets the item fields.
+ /// Filters the items.
/// </summary>
/// <param name="request">The request.</param>
- /// <returns>IEnumerable{ItemFields}.</returns>
- private IEnumerable<ItemFields> GetItemFields(GetItemsByName request)
+ /// <param name="items">The items.</param>
+ /// <param name="user">The user.</param>
+ /// <returns>IEnumerable{BaseItem}.</returns>
+ private IEnumerable<BaseItem> FilterItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
{
- var val = request.Fields;
+ items = items.AsParallel();
- if (string.IsNullOrEmpty(val))
+ items = ItemsService.ApplyAdditionalFilters(request, items);
+
+ // Apply filters
+ // Run them starting with the ones that are likely to reduce the list the most
+ foreach (var filter in request.GetFilters().OrderByDescending(f => (int)f))
{
- return new ItemFields[] { };
+ items = ItemsService.ApplyFilter(items, filter, user, UserManager);
}
- return val.Split(',').Select(v => (ItemFields)Enum.Parse(typeof(ItemFields), v, true));
+ items = items.AsEnumerable();
+
+ return items;
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index c348bf5f5..4975b653a 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -1,4 +1,7 @@
-using MediaBrowser.Model.Entities;
+using System.Collections.Generic;
+using System.Linq;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
using System;
@@ -14,6 +17,13 @@ namespace MediaBrowser.Api.UserLibrary
public Guid UserId { get; set; }
/// <summary>
+ /// What to sort the results by
+ /// </summary>
+ /// <value>The sort by.</value>
+ [ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, CommunityRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Runtime", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ public string SortBy { get; set; }
+
+ /// <summary>
/// Skips over a given number of items within the results. Use for paging.
/// </summary>
/// <value>The start index.</value>
@@ -54,5 +64,74 @@ namespace MediaBrowser.Api.UserLibrary
/// <value>The fields.</value>
[ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: AudioInfo, Chapters, DateCreated, DisplayMediaType, DisplayPreferences, Genres, ItemCounts, IndexOptions, MediaStreams, Overview, OverviewHtml, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, SeriesInfo, SortName, Studios, Taglines, TrailerUrls, UserData", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string Fields { get; set; }
+
+ /// <summary>
+ /// Gets or sets the exclude item types.
+ /// </summary>
+ /// <value>The exclude item types.</value>
+ [ApiMember(Name = "ExcludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ public string ExcludeItemTypes { get; set; }
+
+ /// <summary>
+ /// Gets or sets the include item types.
+ /// </summary>
+ /// <value>The include item types.</value>
+ [ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ public string IncludeItemTypes { get; set; }
+
+ /// <summary>
+ /// Filters to apply to the results
+ /// </summary>
+ /// <value>The filters.</value>
+ [ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsRecentlyAdded, IsResumable, Likes, Dislikes", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ public string Filters { get; set; }
+
+ /// <summary>
+ /// Gets the filters.
+ /// </summary>
+ /// <returns>IEnumerable{ItemFilter}.</returns>
+ public IEnumerable<ItemFilter> GetFilters()
+ {
+ var val = Filters;
+
+ if (string.IsNullOrEmpty(val))
+ {
+ return new ItemFilter[] { };
+ }
+
+ return val.Split(',').Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true));
+ }
+
+ /// <summary>
+ /// Gets the item fields.
+ /// </summary>
+ /// <returns>IEnumerable{ItemFields}.</returns>
+ public IEnumerable<ItemFields> GetItemFields()
+ {
+ var val = Fields;
+
+ if (string.IsNullOrEmpty(val))
+ {
+ return new ItemFields[] { };
+ }
+
+ return val.Split(',').Select(v => (ItemFields)Enum.Parse(typeof(ItemFields), v, true));
+ }
+
+ /// <summary>
+ /// Gets the order by.
+ /// </summary>
+ /// <returns>IEnumerable{ItemSortBy}.</returns>
+ public IEnumerable<string> GetOrderBy()
+ {
+ var val = SortBy;
+
+ if (string.IsNullOrEmpty(val))
+ {
+ return new string[] { };
+ }
+
+ return val.Split(',');
+ }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 4561d823b..6a86c27f0 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -46,20 +46,6 @@ namespace MediaBrowser.Api.UserLibrary
public string IndexBy { get; set; }
/// <summary>
- /// What to sort the results by
- /// </summary>
- /// <value>The sort by.</value>
- [ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, CommunityRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Runtime", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string SortBy { get; set; }
-
- /// <summary>
- /// Filters to apply to the results
- /// </summary>
- /// <value>The filters.</value>
- [ApiMember(Name = "Filters", Description = "Optional. Specify additional filters to apply. This allows multiple, comma delimeted. Options: IsFolder, IsNotFolder, IsUnplayed, IsPlayed, IsFavorite, IsRecentlyAdded, IsResumable, Likes, Dislikes", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string Filters { get; set; }
-
- /// <summary>
/// Limit results to items containing specific genres
/// </summary>
/// <value>The genres.</value>
@@ -74,20 +60,6 @@ namespace MediaBrowser.Api.UserLibrary
public string Studios { get; set; }
/// <summary>
- /// Gets or sets the exclude item types.
- /// </summary>
- /// <value>The exclude item types.</value>
- [ApiMember(Name = "ExcludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string ExcludeItemTypes { get; set; }
-
- /// <summary>
- /// Gets or sets the include item types.
- /// </summary>
- /// <value>The include item types.</value>
- [ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
- public string IncludeItemTypes { get; set; }
-
- /// <summary>
/// Limit results to items containing specific years
/// </summary>
/// <value>The years.</value>
@@ -202,22 +174,22 @@ namespace MediaBrowser.Api.UserLibrary
// Apply filters
// Run them starting with the ones that are likely to reduce the list the most
- foreach (var filter in GetFilters(request).OrderByDescending(f => (int)f))
+ foreach (var filter in request.GetFilters().OrderByDescending(f => (int)f))
{
- items = ApplyFilter(items, filter, user);
+ items = ApplyFilter(items, filter, user, _userManager);
}
items = items.AsEnumerable();
items = ApplySearchTerm(request, items);
- items = ApplySortOrder(request, items, user);
+ items = ApplySortOrder(request, items, user, _libraryManager);
var itemsArray = items.ToArray();
var pagedItems = ApplyPaging(request, itemsArray);
- var fields = GetItemFields(request).ToList();
+ var fields = request.GetItemFields().ToList();
var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userManager);
@@ -264,12 +236,13 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <param name="user">The user.</param>
+ /// <param name="libraryManager">The library manager.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
- private IEnumerable<BaseItem> ApplySortOrder(GetItems request, IEnumerable<BaseItem> items, User user)
+ internal static IEnumerable<BaseItem> ApplySortOrder(BaseItemsRequest request, IEnumerable<BaseItem> items, User user, ILibraryManager libraryManager)
{
- var orderBy = GetOrderBy(request).ToArray();
+ var orderBy = request.GetOrderBy().ToArray();
- return orderBy.Length == 0 ? items : _libraryManager.Sort(items, user, orderBy, request.SortOrder ?? SortOrder.Ascending);
+ return orderBy.Length == 0 ? items : libraryManager.Sort(items, user, orderBy, request.SortOrder ?? SortOrder.Ascending);
}
/// <summary>
@@ -278,8 +251,9 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="items">The items.</param>
/// <param name="filter">The filter.</param>
/// <param name="user">The user.</param>
+ /// <param name="userManager">The user manager.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
- private IEnumerable<BaseItem> ApplyFilter(IEnumerable<BaseItem> items, ItemFilter filter, User user)
+ internal static IEnumerable<BaseItem> ApplyFilter(IEnumerable<BaseItem> items, ItemFilter filter, User user, IUserManager userManager)
{
// Avoids implicitly captured closure
var currentUser = user;
@@ -289,7 +263,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.Likes:
return items.Where(item =>
{
- var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result;
+ var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
});
@@ -297,7 +271,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.Dislikes:
return items.Where(item =>
{
- var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result;
+ var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
});
@@ -305,7 +279,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsFavorite:
return items.Where(item =>
{
- var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result;
+ var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
return userdata != null && userdata.IsFavorite;
});
@@ -316,7 +290,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsResumable:
return items.Where(item =>
{
- var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result;
+ var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
return userdata != null && userdata.PlaybackPositionTicks > 0;
});
@@ -324,7 +298,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsPlayed:
return items.Where(item =>
{
- var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result;
+ var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
return userdata != null && userdata.PlayCount > 0;
});
@@ -332,7 +306,7 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsUnplayed:
return items.Where(item =>
{
- var userdata = _userManager.GetUserData(user.Id, item.UserDataId).Result;
+ var userdata = userManager.GetUserData(user.Id, item.UserDataId).Result;
return userdata == null || userdata.PlayCount == 0;
});
@@ -350,11 +324,32 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Applies the additional filters.
/// </summary>
- /// <param name="request">The request.</param>
+ /// <param name="itemsRequest">The items request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
- private IEnumerable<BaseItem> ApplyAdditionalFilters(GetItems request, IEnumerable<BaseItem> items)
+ internal static IEnumerable<BaseItem> ApplyAdditionalFilters(BaseItemsRequest itemsRequest, IEnumerable<BaseItem> items)
{
+ // Exclude item types
+ if (!string.IsNullOrEmpty(itemsRequest.ExcludeItemTypes))
+ {
+ var vals = itemsRequest.ExcludeItemTypes.Split(',');
+ items = items.Where(f => !vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
+ }
+
+ // Include item types
+ if (!string.IsNullOrEmpty(itemsRequest.IncludeItemTypes))
+ {
+ var vals = itemsRequest.IncludeItemTypes.Split(',');
+ items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
+ }
+
+ var request = itemsRequest as GetItems;
+
+ if (request == null)
+ {
+ return items;
+ }
+
// Filter by Series Status
if (!string.IsNullOrEmpty(request.SeriesStatus))
{
@@ -400,21 +395,6 @@ namespace MediaBrowser.Api.UserLibrary
items = items.Where(item => imageTypes.Any(imageType => HasImage(item, imageType)));
}
- // Exclude item types
- var excludeItemTypes = request.ExcludeItemTypes;
- if (!string.IsNullOrEmpty(excludeItemTypes))
- {
- var vals = excludeItemTypes.Split(',');
- items = items.Where(f => !vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
- }
-
- var includeItemTypes = request.IncludeItemTypes;
- if (!string.IsNullOrEmpty(includeItemTypes))
- {
- var vals = includeItemTypes.Split(',');
- items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
- }
-
var genres = request.Genres;
// Apply genre filter
@@ -463,7 +443,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="item">The item.</param>
/// <param name="imageType">Type of the image.</param>
/// <returns><c>true</c> if the specified item has image; otherwise, <c>false</c>.</returns>
- private bool HasImage(BaseItem item, ImageType imageType)
+ private static bool HasImage(BaseItem item, ImageType imageType)
{
if (imageType == ImageType.Backdrop)
{
@@ -532,62 +512,11 @@ namespace MediaBrowser.Api.UserLibrary
}
/// <summary>
- /// Gets the filters.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>IEnumerable{ItemFilter}.</returns>
- private IEnumerable<ItemFilter> GetFilters(GetItems request)
- {
- var val = request.Filters;
-
- if (string.IsNullOrEmpty(val))
- {
- return new ItemFilter[] { };
- }
-
- return val.Split(',').Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true));
- }
-
- /// <summary>
- /// Gets the item fields.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>IEnumerable{ItemFields}.</returns>
- private IEnumerable<ItemFields> GetItemFields(GetItems request)
- {
- var val = request.Fields;
-
- if (string.IsNullOrEmpty(val))
- {
- return new ItemFields[] { };
- }
-
- return val.Split(',').Select(v => (ItemFields)Enum.Parse(typeof(ItemFields), v, true));
- }
-
- /// <summary>
- /// Gets the order by.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>IEnumerable{ItemSortBy}.</returns>
- private IEnumerable<string> GetOrderBy(GetItems request)
- {
- var val = request.SortBy;
-
- if (string.IsNullOrEmpty(val))
- {
- return new string[] { };
- }
-
- return val.Split(',');
- }
-
- /// <summary>
/// Gets the image types.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>IEnumerable{ImageType}.</returns>
- private IEnumerable<ImageType> GetImageTypes(GetItems request)
+ private static IEnumerable<ImageType> GetImageTypes(GetItems request)
{
var val = request.ImageTypes;
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index e3af7b311..4fafdab7c 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -461,12 +461,18 @@ namespace MediaBrowser.WebDashboard.Api
"mediaplayer.js",
"metadataconfigurationpage.js",
"metadataimagespage.js",
+ "moviegenres.js",
"movies.js",
"moviesrecommended.js",
+ "playlist.js",
"pluginspage.js",
"pluginupdatespage.js",
"scheduledtaskpage.js",
"scheduledtaskspage.js",
+ "supporterkeypage.js",
+ "supporterpage.js",
+ "tvgenres.js",
+ "tvseries.js",
"tvrecommended.js",
"tvshows.js",
"updatepasswordpage.js",
@@ -474,11 +480,7 @@ namespace MediaBrowser.WebDashboard.Api
"userprofilespage.js",
"wizardfinishpage.js",
"wizardstartpage.js",
- "wizarduserpage.js",
- "supporterkeypage.js",
- "supporterpage.js",
- "playlist.js",
- "tvseries.js"
+ "wizarduserpage.js"
};
var memoryStream = new MemoryStream();
diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js
index 5ac4ecd8f..f56d3744b 100644
--- a/MediaBrowser.WebDashboard/ApiClient.js
+++ b/MediaBrowser.WebDashboard/ApiClient.js
@@ -1498,7 +1498,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
};
/**
- * Gets items based on a query, typicall for children of a folder
+ * Gets items based on a query, typically for children of a folder
* @param {String} userId
* @param {Object} options
* Options accepts the following properties:
@@ -1530,6 +1530,52 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
};
/**
+ Gets genres from an item
+ */
+ self.getGenres = function (userId, options) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ var parentId = options.parentId || "root";
+
+ // Don't put these on the query string
+ delete options.parentId;
+
+ var url = self.getUrl("Users/" + userId + "/Items/" + parentId + "/Genres", options);
+
+ return self.ajax({
+ type: "GET",
+ url: url,
+ dataType: "json"
+ });
+ };
+
+ /**
+ Gets studios from an item
+ */
+ self.getStudios = function (userId, options) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ var parentId = options.parentId || "root";
+
+ // Don't put these on the query string
+ delete options.parentId;
+
+ var url = self.getUrl("Users/" + userId + "/Items/" + parentId + "/Studios", options);
+
+ return self.ajax({
+ type: "GET",
+ url: url,
+ dataType: "json"
+ });
+ };
+
+ /**
* Gets local trailers for an item
*/
self.getLocalTrailers = function (userId, itemId) {
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 44a36c4f7..22d40f9b6 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -198,6 +198,9 @@
</Content>
</ItemGroup>
<ItemGroup>
+ <Content Include="dashboard-ui\moviegenres.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\movies.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -219,6 +222,9 @@
<Content Include="dashboard-ui\scripts\itembynamedetailpage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\moviegenres.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\playlist.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -254,6 +260,9 @@
<Content Include="dashboard-ui\itembynamedetails.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\tvgenres.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\tvrecommended.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -275,6 +284,9 @@
<Content Include="dashboard-ui\thirdparty\jplayer\jquery.jplayer.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\tvgenres.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\tvrecommended.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index 30a541990..b9bc66602 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="MediaBrowser.ApiClient.Javascript" version="3.0.71" targetFramework="net45" />
+ <package id="MediaBrowser.ApiClient.Javascript" version="3.0.72" targetFramework="net45" />
<package id="ServiceStack.Common" version="3.9.43" targetFramework="net45" />
<package id="ServiceStack.Text" version="3.9.43" targetFramework="net45" />
</packages> \ No newline at end of file