aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Api')
-rw-r--r--MediaBrowser.Api/BaseApiService.cs5
-rw-r--r--MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs6
-rw-r--r--MediaBrowser.Api/GamesService.cs2
-rw-r--r--MediaBrowser.Api/ItemUpdateService.cs16
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj9
-rw-r--r--MediaBrowser.Api/Movies/CollectionService.cs80
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs324
-rw-r--r--MediaBrowser.Api/Movies/TrailersService.cs (renamed from MediaBrowser.Api/TrailersService.cs)2
-rw-r--r--MediaBrowser.Api/MoviesService.cs82
-rw-r--r--MediaBrowser.Api/Music/AlbumsService.cs (renamed from MediaBrowser.Api/AlbumsService.cs)2
-rw-r--r--MediaBrowser.Api/Music/InstantMixService.cs (renamed from MediaBrowser.Api/InstantMixService.cs)2
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs128
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs10
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs2
-rw-r--r--MediaBrowser.Api/Playback/StreamRequest.cs2
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs18
-rw-r--r--MediaBrowser.Api/SearchService.cs12
-rw-r--r--MediaBrowser.Api/SessionsService.cs4
-rw-r--r--MediaBrowser.Api/SimilarItemsHelper.cs12
-rw-r--r--MediaBrowser.Api/TvShowsService.cs104
-rw-r--r--MediaBrowser.Api/UserLibrary/ArtistsService.cs14
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs43
-rw-r--r--MediaBrowser.Api/UserLibrary/GameGenresService.cs9
-rw-r--r--MediaBrowser.Api/UserLibrary/GenresService.cs9
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs15
-rw-r--r--MediaBrowser.Api/UserLibrary/MusicGenresService.cs9
-rw-r--r--MediaBrowser.Api/UserLibrary/PersonsService.cs9
-rw-r--r--MediaBrowser.Api/UserLibrary/StudiosService.cs9
-rw-r--r--MediaBrowser.Api/UserLibrary/UserLibraryService.cs42
-rw-r--r--MediaBrowser.Api/UserLibrary/YearsService.cs19
32 files changed, 732 insertions, 272 deletions
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 5fba539fe5..08686b43a8 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -164,7 +164,10 @@ namespace MediaBrowser.Api
return name;
}
- return libraryManager.GetAllArtists()
+ return libraryManager.RootFolder.RecursiveChildren
+ .OfType<Audio>()
+ .SelectMany(i => i.AllArtists)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
.FirstOrDefault(i =>
{
i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
diff --git a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs
index afba8c3604..c9c4cbc43f 100644
--- a/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs
+++ b/MediaBrowser.Api/DefaultTheme/DefaultThemeService.cs
@@ -194,8 +194,10 @@ namespace MediaBrowser.Api.DefaultTheme
.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
.ToList();
- var artists = _libraryManager.GetAllArtists(allItems)
- .Randomize()
+ var artists = allItems.OfType<Audio>()
+ .SelectMany(i => i.AllArtists)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .Randomize()
.Select(i =>
{
try
diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs
index eabda673a4..e371791f81 100644
--- a/MediaBrowser.Api/GamesService.cs
+++ b/MediaBrowser.Api/GamesService.cs
@@ -155,7 +155,7 @@ namespace MediaBrowser.Api
var games = items.OfType<Game>().ToList();
- summary.ClientInstalledGameCount = games.Count(i => !i.IsPlaceHolder);
+ summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder);
summary.GameCount = games.Count;
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index 1eaf4acb1b..b15e67ffa7 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -98,7 +98,7 @@ namespace MediaBrowser.Api
UpdateItem(request, item);
- await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
if (dontFetchMetaChanged && item.IsFolder)
{
@@ -107,7 +107,7 @@ namespace MediaBrowser.Api
foreach (var child in folder.RecursiveChildren.ToList())
{
child.DontFetchMeta = newLockData;
- await _libraryManager.UpdateItem(child, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ await child.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
}
}
@@ -125,7 +125,7 @@ namespace MediaBrowser.Api
UpdateItem(request, item);
- await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
public void Post(UpdateArtist request)
@@ -141,7 +141,7 @@ namespace MediaBrowser.Api
UpdateItem(request, item);
- await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
public void Post(UpdateStudio request)
@@ -157,7 +157,7 @@ namespace MediaBrowser.Api
UpdateItem(request, item);
- await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
public void Post(UpdateMusicGenre request)
@@ -173,7 +173,7 @@ namespace MediaBrowser.Api
UpdateItem(request, item);
- await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
public void Post(UpdateGameGenre request)
@@ -189,7 +189,7 @@ namespace MediaBrowser.Api
UpdateItem(request, item);
- await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
public void Post(UpdateGenre request)
@@ -205,7 +205,7 @@ namespace MediaBrowser.Api
UpdateItem(request, item);
- await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+ await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
}
private void UpdateItem(BaseItemDto request, BaseItem item)
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index bcc487a5d5..e19fbb967f 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -66,7 +66,8 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
- <Compile Include="AlbumsService.cs" />
+ <Compile Include="Movies\CollectionService.cs" />
+ <Compile Include="Music\AlbumsService.cs" />
<Compile Include="AppThemeService.cs" />
<Compile Include="BaseApiService.cs" />
<Compile Include="ConfigurationService.cs" />
@@ -81,7 +82,7 @@
<Compile Include="Images\ImageRequest.cs" />
<Compile Include="Images\ImageService.cs" />
<Compile Include="Images\ImageWriter.cs" />
- <Compile Include="InstantMixService.cs" />
+ <Compile Include="Music\InstantMixService.cs" />
<Compile Include="ItemLookupService.cs" />
<Compile Include="ItemRefreshService.cs" />
<Compile Include="ItemUpdateService.cs" />
@@ -91,7 +92,7 @@
<Compile Include="Library\LibraryStructureService.cs" />
<Compile Include="LiveTv\LiveTvService.cs" />
<Compile Include="LocalizationService.cs" />
- <Compile Include="MoviesService.cs" />
+ <Compile Include="Movies\MoviesService.cs" />
<Compile Include="NewsService.cs" />
<Compile Include="NotificationsService.cs" />
<Compile Include="PackageReviewService.cs" />
@@ -118,7 +119,7 @@
<Compile Include="SessionsService.cs" />
<Compile Include="SimilarItemsHelper.cs" />
<Compile Include="SystemService.cs" />
- <Compile Include="TrailersService.cs" />
+ <Compile Include="Movies\TrailersService.cs" />
<Compile Include="TvShowsService.cs" />
<Compile Include="UserLibrary\ArtistsService.cs" />
<Compile Include="UserLibrary\BaseItemsByNameService.cs" />
diff --git a/MediaBrowser.Api/Movies/CollectionService.cs b/MediaBrowser.Api/Movies/CollectionService.cs
new file mode 100644
index 0000000000..456449b7b6
--- /dev/null
+++ b/MediaBrowser.Api/Movies/CollectionService.cs
@@ -0,0 +1,80 @@
+using MediaBrowser.Controller.Collections;
+using ServiceStack;
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api.Movies
+{
+ [Route("/Collections", "POST")]
+ [Api(Description = "Creates a new collection")]
+ public class CreateCollection : IReturnVoid
+ {
+ [ApiMember(Name = "IsLocked", Description = "Whether or not to lock the new collection.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")]
+ public bool IsLocked { get; set; }
+
+ [ApiMember(Name = "Name", Description = "The name of the new collection.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string Name { get; set; }
+
+ [ApiMember(Name = "ParentId", Description = "Optional - create the collection within a specific folder", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public Guid? ParentId { get; set; }
+ }
+
+ [Route("/Collections/{Id}/Items", "POST")]
+ [Api(Description = "Adds items to a collection")]
+ public class AddToCollection : IReturnVoid
+ {
+ [ApiMember(Name = "Ids", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string Ids { get; set; }
+
+ [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+ public Guid Id { get; set; }
+ }
+
+ [Route("/Collections/{Id}/Items", "DELETE")]
+ [Api(Description = "Removes items from a collection")]
+ public class RemoveFromCollection : IReturnVoid
+ {
+ [ApiMember(Name = "Ids", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+ public string Ids { get; set; }
+
+ [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+ public Guid Id { get; set; }
+ }
+
+ public class CollectionService : BaseApiService
+ {
+ private readonly ICollectionManager _collectionManager;
+
+ public CollectionService(ICollectionManager collectionManager)
+ {
+ _collectionManager = collectionManager;
+ }
+
+ public void Post(CreateCollection request)
+ {
+ var task = _collectionManager.CreateCollection(new CollectionCreationOptions
+ {
+ IsLocked = request.IsLocked,
+ Name = request.Name,
+ ParentId = request.ParentId
+ });
+
+ Task.WaitAll(task);
+ }
+
+ public void Post(AddToCollection request)
+ {
+ var task = _collectionManager.AddToCollection(request.Id, request.Ids.Split(',').Select(i => new Guid(i)));
+
+ Task.WaitAll(task);
+ }
+
+ public void Delete(RemoveFromCollection request)
+ {
+ var task = _collectionManager.RemoveFromCollection(request.Id, request.Ids.Split(',').Select(i => new Guid(i)));
+
+ Task.WaitAll(task);
+ }
+ }
+}
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
new file mode 100644
index 0000000000..3360d97363
--- /dev/null
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -0,0 +1,324 @@
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
+using ServiceStack;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MediaBrowser.Api.Movies
+{
+ /// <summary>
+ /// Class GetSimilarMovies
+ /// </summary>
+ [Route("/Movies/{Id}/Similar", "GET")]
+ [Api(Description = "Finds movies and trailers similar to a given movie.")]
+ public class GetSimilarMovies : BaseGetSimilarItemsFromItem
+ {
+ [ApiMember(Name = "IncludeTrailers", Description = "Whether or not to include trailers within the results. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+ public bool IncludeTrailers { get; set; }
+
+ public GetSimilarMovies()
+ {
+ IncludeTrailers = true;
+ }
+ }
+
+ [Route("/Movies/Recommendations", "GET")]
+ [Api(Description = "Gets movie recommendations")]
+ public class GetMovieRecommendations : IReturn<RecommendationDto[]>, IHasItemFields
+ {
+ [ApiMember(Name = "CategoryLimit", Description = "The max number of categories to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int CategoryLimit { get; set; }
+
+ [ApiMember(Name = "ItemLimit", Description = "The max number of items to return per category", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int ItemLimit { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid? UserId { get; set; }
+
+ public GetMovieRecommendations()
+ {
+ CategoryLimit = 5;
+ ItemLimit = 8;
+ }
+
+ public string Fields { get; set; }
+ }
+
+ /// <summary>
+ /// Class MoviesService
+ /// </summary>
+ public class MoviesService : BaseApiService
+ {
+ /// <summary>
+ /// The _user manager
+ /// </summary>
+ private readonly IUserManager _userManager;
+
+ /// <summary>
+ /// The _user data repository
+ /// </summary>
+ private readonly IUserDataManager _userDataRepository;
+ /// <summary>
+ /// The _library manager
+ /// </summary>
+ private readonly ILibraryManager _libraryManager;
+
+ private readonly IItemRepository _itemRepo;
+ private readonly IDtoService _dtoService;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MoviesService"/> class.
+ /// </summary>
+ /// <param name="userManager">The user manager.</param>
+ /// <param name="userDataRepository">The user data repository.</param>
+ /// <param name="libraryManager">The library manager.</param>
+ public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
+ {
+ _userManager = userManager;
+ _userDataRepository = userDataRepository;
+ _libraryManager = libraryManager;
+ _itemRepo = itemRepo;
+ _dtoService = dtoService;
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
+ public object Get(GetSimilarMovies request)
+ {
+ var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
+ _itemRepo,
+ _libraryManager,
+ _userDataRepository,
+ _dtoService,
+ Logger,
+ request, item => item is Movie || (item is Trailer && request.IncludeTrailers),
+ SimilarItemsHelper.GetSimiliarityScore);
+
+ return ToOptimizedSerializedResultUsingCache(result);
+ }
+
+ public object Get(GetMovieRecommendations request)
+ {
+ var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
+
+ var folder = user.RootFolder;
+ var movies = folder.RecursiveChildren.OfType<Movie>().ToList();
+
+ var result = GetRecommendationCategories(user, movies, request.CategoryLimit, request.ItemLimit, request.GetItemFields().ToList());
+
+ return ToOptimizedResult(result);
+ }
+
+ private IEnumerable<RecommendationDto> GetRecommendationCategories(User user, List<Movie> allMovies, int categoryLimit, int itemLimit, List<ItemFields> fields)
+ {
+ var categories = new List<RecommendationDto>();
+
+ var recentlyPlayedMovies = allMovies
+ .Select(i =>
+ {
+ var userdata = _userDataRepository.GetUserData(user.Id, i.GetUserDataKey());
+ return new Tuple<Movie, bool, DateTime>(i, userdata.Played, userdata.LastPlayedDate ?? DateTime.MinValue);
+ })
+ .Where(i => i.Item2)
+ .OrderByDescending(i => i.Item3)
+ .Select(i => i.Item1)
+ .ToList();
+
+ var excludeFromLiked = recentlyPlayedMovies.Take(10);
+ var likedMovies = allMovies
+ .Select(i =>
+ {
+ var score = 0;
+ var userData = _userDataRepository.GetUserData(user.Id, i.GetUserDataKey());
+
+ if (userData.IsFavorite)
+ {
+ score = 2;
+ }
+ else
+ {
+ score = userData.Likes.HasValue ? userData.Likes.Value ? 1 : -1 : 0;
+ }
+
+ return new Tuple<Movie, int>(i, score);
+ })
+ .OrderByDescending(i => i.Item2)
+ .ThenBy(i => Guid.NewGuid())
+ .Where(i => i.Item2 > 0)
+ .Select(i => i.Item1)
+ .Where(i => !excludeFromLiked.Contains(i));
+
+ var mostRecentMovies = recentlyPlayedMovies.Take(6).ToList();
+ // Get recently played directors
+ var recentDirectors = GetDirectors(mostRecentMovies)
+ .OrderBy(i => Guid.NewGuid())
+ .ToList();
+
+ // Get recently played actors
+ var recentActors = GetActors(mostRecentMovies)
+ .OrderBy(i => Guid.NewGuid())
+ .ToList();
+
+ var similarToRecentlyPlayed = GetSimilarTo(user, allMovies, recentlyPlayedMovies.Take(7).OrderBy(i => Guid.NewGuid()), itemLimit, fields, RecommendationType.SimilarToRecentlyPlayed).GetEnumerator();
+ var similarToLiked = GetSimilarTo(user, allMovies, likedMovies, itemLimit, fields, RecommendationType.SimilarToLikedItem).GetEnumerator();
+
+ var hasDirectorFromRecentlyPlayed = GetWithDirector(user, allMovies, recentDirectors, itemLimit, fields, RecommendationType.HasDirectorFromRecentlyPlayed).GetEnumerator();
+ var hasActorFromRecentlyPlayed = GetWithActor(user, allMovies, recentActors, itemLimit, fields, RecommendationType.HasActorFromRecentlyPlayed).GetEnumerator();
+
+ var categoryTypes = new List<IEnumerator<RecommendationDto>>
+ {
+ // Give this extra weight
+ similarToRecentlyPlayed,
+ similarToRecentlyPlayed,
+
+ // Give this extra weight
+ similarToLiked,
+ similarToLiked,
+
+ hasDirectorFromRecentlyPlayed,
+ hasActorFromRecentlyPlayed
+ };
+
+ while (categories.Count < categoryLimit)
+ {
+ var allEmpty = true;
+
+ foreach (var category in categoryTypes)
+ {
+ if (category.MoveNext())
+ {
+ categories.Add(category.Current);
+ allEmpty = false;
+
+ if (categories.Count >= categoryLimit)
+ {
+ break;
+ }
+ }
+ }
+
+ if (allEmpty)
+ {
+ break;
+ }
+ }
+
+ //// Get the lead actor for all movies
+ //var allActors = GetActors(allMovies)
+ // .ToList();
+
+ //foreach (var actor in recentActors)
+ //{
+
+ //}
+
+ return categories.OrderBy(i => i.RecommendationType).ThenBy(i => Guid.NewGuid());
+ }
+
+ private IEnumerable<RecommendationDto> GetWithDirector(User user, List<Movie> allMovies, IEnumerable<string> directors, int itemLimit, List<ItemFields> fields, RecommendationType type)
+ {
+ var userId = user.Id;
+
+ foreach (var director in directors)
+ {
+ var items = allMovies
+ .Where(i => !_userDataRepository.GetUserData(userId, i.GetUserDataKey()).Played && i.People.Any(p => string.Equals(p.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) && string.Equals(p.Name, director, StringComparison.OrdinalIgnoreCase)))
+ .Take(itemLimit)
+ .ToList();
+
+ if (items.Count > 0)
+ {
+ yield return new RecommendationDto
+ {
+ BaselineItemName = director,
+ CategoryId = director.GetMD5().ToString("N"),
+ RecommendationType = type,
+ Items = items.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray()
+ };
+ }
+ }
+ }
+
+ private IEnumerable<RecommendationDto> GetWithActor(User user, List<Movie> allMovies, IEnumerable<string> names, int itemLimit, List<ItemFields> fields, RecommendationType type)
+ {
+ var userId = user.Id;
+
+ foreach (var name in names)
+ {
+ var items = allMovies
+ .Where(i => !_userDataRepository.GetUserData(userId, i.GetUserDataKey()).Played && i.People.Any(p => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase)))
+ .Take(itemLimit)
+ .ToList();
+
+ if (items.Count > 0)
+ {
+ yield return new RecommendationDto
+ {
+ BaselineItemName = name,
+ CategoryId = name.GetMD5().ToString("N"),
+ RecommendationType = type,
+ Items = items.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray()
+ };
+ }
+ }
+ }
+
+ private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<Movie> allMovies, IEnumerable<Movie> baselineItems, int itemLimit, List<ItemFields> fields, RecommendationType type)
+ {
+ var userId = user.Id;
+
+ foreach (var item in baselineItems)
+ {
+ var similar = SimilarItemsHelper
+ .GetSimilaritems(item, allMovies, SimilarItemsHelper.GetSimiliarityScore)
+ .Where(i => !_userDataRepository.GetUserData(userId, i.GetUserDataKey()).Played)
+ .Take(itemLimit)
+ .ToList();
+
+ if (similar.Count > 0)
+ {
+ yield return new RecommendationDto
+ {
+ BaselineItemName = item.Name,
+ CategoryId = item.Id.ToString("N"),
+ RecommendationType = type,
+ Items = similar.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray()
+ };
+ }
+ }
+ }
+
+ private IEnumerable<string> GetActors(IEnumerable<BaseItem> items)
+ {
+ // Get the two leading actors for all movies
+ return items
+ .SelectMany(i => i.People.Where(p => !string.Equals(PersonType.Director, p.Type, StringComparison.OrdinalIgnoreCase)).Take(2))
+ .Select(i => i.Name)
+ .Distinct(StringComparer.OrdinalIgnoreCase);
+ }
+
+ private IEnumerable<string> GetDirectors(IEnumerable<BaseItem> items)
+ {
+ return items
+ .Select(i => i.People.FirstOrDefault(p => string.Equals(PersonType.Director, p.Type, StringComparison.OrdinalIgnoreCase)))
+ .Where(i => i != null)
+ .Select(i => i.Name)
+ .Distinct(StringComparer.OrdinalIgnoreCase);
+ }
+ }
+}
diff --git a/MediaBrowser.Api/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs
index ca465b5e32..4e17bc7b50 100644
--- a/MediaBrowser.Api/TrailersService.cs
+++ b/MediaBrowser.Api/Movies/TrailersService.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack;
-namespace MediaBrowser.Api
+namespace MediaBrowser.Api.Movies
{
/// <summary>
/// Class GetSimilarTrailers
diff --git a/MediaBrowser.Api/MoviesService.cs b/MediaBrowser.Api/MoviesService.cs
deleted file mode 100644
index 2a99bca8b0..0000000000
--- a/MediaBrowser.Api/MoviesService.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
-using ServiceStack;
-
-namespace MediaBrowser.Api
-{
- /// <summary>
- /// Class GetSimilarMovies
- /// </summary>
- [Route("/Movies/{Id}/Similar", "GET")]
- [Api(Description = "Finds movies and trailers similar to a given movie.")]
- public class GetSimilarMovies : BaseGetSimilarItemsFromItem
- {
- [ApiMember(Name = "IncludeTrailers", Description = "Whether or not to include trailers within the results. Defaults to true.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
- public bool IncludeTrailers { get; set; }
-
- public GetSimilarMovies()
- {
- IncludeTrailers = true;
- }
- }
-
- /// <summary>
- /// Class MoviesService
- /// </summary>
- public class MoviesService : BaseApiService
- {
- /// <summary>
- /// The _user manager
- /// </summary>
- private readonly IUserManager _userManager;
-
- /// <summary>
- /// The _user data repository
- /// </summary>
- private readonly IUserDataManager _userDataRepository;
- /// <summary>
- /// The _library manager
- /// </summary>
- private readonly ILibraryManager _libraryManager;
-
- private readonly IItemRepository _itemRepo;
- private readonly IDtoService _dtoService;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="MoviesService"/> class.
- /// </summary>
- /// <param name="userManager">The user manager.</param>
- /// <param name="userDataRepository">The user data repository.</param>
- /// <param name="libraryManager">The library manager.</param>
- public MoviesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
- {
- _userManager = userManager;
- _userDataRepository = userDataRepository;
- _libraryManager = libraryManager;
- _itemRepo = itemRepo;
- _dtoService = dtoService;
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- public object Get(GetSimilarMovies request)
- {
- var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
- _itemRepo,
- _libraryManager,
- _userDataRepository,
- _dtoService,
- Logger,
- request, item => item is Movie || (item is Trailer && request.IncludeTrailers),
- SimilarItemsHelper.GetSimiliarityScore);
-
- return ToOptimizedSerializedResultUsingCache(result);
- }
- }
-}
diff --git a/MediaBrowser.Api/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs
index 5787ad180c..a80dd796a0 100644
--- a/MediaBrowser.Api/AlbumsService.cs
+++ b/MediaBrowser.Api/Music/AlbumsService.cs
@@ -8,7 +8,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
-namespace MediaBrowser.Api
+namespace MediaBrowser.Api.Music
{
[Route("/Albums/{Id}/Similar", "GET")]
[Api(Description = "Finds albums similar to a given album.")]
diff --git a/MediaBrowser.Api/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs
index 624137677c..a8446a7ef2 100644
--- a/MediaBrowser.Api/InstantMixService.cs
+++ b/MediaBrowser.Api/Music/InstantMixService.cs
@@ -7,7 +7,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
-namespace MediaBrowser.Api
+namespace MediaBrowser.Api.Music
{
[Route("/Songs/{Id}/InstantMix", "GET")]
[Api(Description = "Creates an instant playlist based on a given song")]
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 926dfe9553..3993866cf5 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -279,8 +279,19 @@ namespace MediaBrowser.Api.Playback
/// </summary>
/// <returns>System.Int32.</returns>
/// <exception cref="System.Exception">Unrecognized MediaEncodingQuality value.</exception>
- protected int GetNumberOfThreads(bool isWebm)
+ protected int GetNumberOfThreads(StreamState state, bool isWebm)
{
+ // Use more when this is true. -re will keep cpu usage under control
+ if (state.ReadInputAtNativeFramerate)
+ {
+ if (isWebm)
+ {
+ return Math.Max(Environment.ProcessorCount - 1, 1);
+ }
+
+ return 0;
+ }
+
// Webm: http://www.webmproject.org/docs/encoder-parameters/
// The decoder will usually automatically use an appropriate number of threads according to how many cores are available but it can only use multiple threads
// for the coefficient data if the encoder selected --token-parts > 0 at encode time.
@@ -491,16 +502,16 @@ namespace MediaBrowser.Api.Playback
return string.Format("{4} -vf \"{0}scale=trunc({1}/2)*2:trunc({2}/2)*2{3}\"", yadifParam, widthParam, heightParam, assSubtitleParam, copyTsParam);
}
-
- // If Max dimensions were supplied
- //this makes my brain hurt. For width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size
- if (request.MaxWidth.HasValue && request.MaxHeight.HasValue)
- {
- var MaxwidthParam = request.MaxWidth.Value.ToString(UsCulture);
- var MaxheightParam = request.MaxHeight.Value.ToString(UsCulture);
-
- return string.Format("{4} -vf \"{0}scale=trunc(min(iw\\,{1})/2)*2:trunc(min((iw/dar)\\,{2})/2)*2{3}\"", yadifParam, MaxwidthParam, MaxheightParam, assSubtitleParam, copyTsParam);
- }
+
+ // If Max dimensions were supplied
+ //this makes my brain hurt. For width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size
+ if (request.MaxWidth.HasValue && request.MaxHeight.HasValue)
+ {
+ var MaxwidthParam = request.MaxWidth.Value.ToString(UsCulture);
+ var MaxheightParam = request.MaxHeight.Value.ToString(UsCulture);
+
+ return string.Format("{4} -vf \"{0}scale=trunc(min(iw\\,{1})/2)*2:trunc(min((iw/dar)\\,{2})/2)*2{3}\"", yadifParam, MaxwidthParam, MaxheightParam, assSubtitleParam, copyTsParam);
+ }
var isH264Output = outputVideoCodec.Equals("libx264", StringComparison.OrdinalIgnoreCase);
@@ -603,7 +614,7 @@ namespace MediaBrowser.Api.Playback
private string GetExtractedAssPath(StreamState state, bool performConversion)
{
var path = EncodingManager.GetSubtitleCachePath(state.MediaPath, state.SubtitleStream.Index, ".ass");
-
+
if (performConversion)
{
InputType type;
@@ -987,20 +998,15 @@ namespace MediaBrowser.Api.Playback
if (state.VideoStream != null)
{
- var isUpscaling = false;
-
- if (state.VideoRequest.Height.HasValue && state.VideoStream.Height.HasValue &&
- state.VideoRequest.Height.Value > state.VideoStream.Height.Value)
- {
- isUpscaling = true;
- }
+ var isUpscaling = state.VideoRequest.Height.HasValue && state.VideoStream.Height.HasValue &&
+ state.VideoRequest.Height.Value > state.VideoStream.Height.Value;
if (state.VideoRequest.Width.HasValue && state.VideoStream.Width.HasValue &&
state.VideoRequest.Width.Value > state.VideoStream.Width.Value)
{
isUpscaling = true;
}
-
+
// Don't allow bitrate increases unless upscaling
if (!isUpscaling)
{
@@ -1199,65 +1205,73 @@ namespace MediaBrowser.Api.Playback
}
else if (i == 1)
{
+ request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
+ }
+ else if (i == 2)
+ {
if (videoRequest != null)
{
videoRequest.VideoCodec = (VideoCodecs)Enum.Parse(typeof(VideoCodecs), val, true);
}
}
- else if (i == 2)
+ else if (i == 3)
{
request.AudioCodec = (AudioCodecs)Enum.Parse(typeof(AudioCodecs), val, true);
}
- else if (i == 3)
+ else if (i == 4)
{
if (videoRequest != null)
{
videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
}
}
- else if (i == 4)
+ else if (i == 5)
{
if (videoRequest != null)
{
videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
}
}
- else if (i == 5)
+ else if (i == 6)
{
if (videoRequest != null)
{
videoRequest.VideoBitRate = int.Parse(val, UsCulture);
}
}
- else if (i == 6)
+ else if (i == 7)
{
request.AudioBitRate = int.Parse(val, UsCulture);
}
- else if (i == 7)
+ else if (i == 8)
{
request.AudioChannels = int.Parse(val, UsCulture);
}
- else if (i == 8)
+ else if (i == 9)
{
if (videoRequest != null)
{
request.StartTimeTicks = long.Parse(val, UsCulture);
}
}
- else if (i == 9)
+ else if (i == 10)
{
if (videoRequest != null)
{
videoRequest.Profile = val;
}
}
- else if (i == 10)
+ else if (i == 11)
{
if (videoRequest != null)
{
videoRequest.Level = val;
}
}
+ else if (i == 12)
+ {
+ request.ForcedMimeType = val;
+ }
}
}
@@ -1309,37 +1323,39 @@ namespace MediaBrowser.Api.Playback
state.IsInputVideo = string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
state.PlayableStreamFileNames = new List<string>();
- if (!string.IsNullOrEmpty(recording.RecordingInfo.Path) && File.Exists(recording.RecordingInfo.Path))
+ var path = recording.RecordingInfo.Path;
+ var mediaUrl = recording.RecordingInfo.Url;
+
+ if (string.IsNullOrWhiteSpace(path) && string.IsNullOrWhiteSpace(mediaUrl))
{
- state.MediaPath = recording.RecordingInfo.Path;
+ var streamInfo = await LiveTvManager.GetRecordingStream(request.Id, cancellationToken).ConfigureAwait(false);
+
+ state.LiveTvStreamId = streamInfo.Id;
+
+ path = streamInfo.Path;
+ mediaUrl = streamInfo.Url;
+ }
+
+ if (!string.IsNullOrEmpty(path) && File.Exists(path))
+ {
+ state.MediaPath = path;
state.IsRemote = false;
+
+ state.SendInputOverStandardInput = recording.RecordingInfo.Status == RecordingStatus.InProgress;
}
- else if (!string.IsNullOrEmpty(recording.RecordingInfo.Url))
+ else if (!string.IsNullOrEmpty(mediaUrl))
{
- state.MediaPath = recording.RecordingInfo.Url;
+ state.MediaPath = mediaUrl;
state.IsRemote = true;
}
- else
- {
- var streamInfo = await LiveTvManager.GetRecordingStream(request.Id, cancellationToken).ConfigureAwait(false);
-
- state.LiveTvStreamId = streamInfo.Id;
- if (!string.IsNullOrEmpty(streamInfo.Path) && File.Exists(streamInfo.Path))
- {
- state.MediaPath = streamInfo.Path;
- state.IsRemote = false;
- }
- else if (!string.IsNullOrEmpty(streamInfo.Url))
- {
- state.MediaPath = streamInfo.Url;
- state.IsRemote = true;
- }
+ //state.RunTimeTicks = recording.RunTimeTicks;
+ if (recording.RecordingInfo.Status == RecordingStatus.InProgress && !state.IsRemote)
+ {
+ await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
}
- //state.RunTimeTicks = recording.RunTimeTicks;
state.ReadInputAtNativeFramerate = recording.RecordingInfo.Status == RecordingStatus.InProgress;
- state.SendInputOverStandardInput = recording.RecordingInfo.Status == RecordingStatus.InProgress;
state.AudioSync = "1000";
state.DeInterlace = true;
}
@@ -1359,6 +1375,8 @@ namespace MediaBrowser.Api.Playback
{
state.MediaPath = streamInfo.Path;
state.IsRemote = false;
+
+ await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
}
else if (!string.IsNullOrEmpty(streamInfo.Url))
{
@@ -1366,7 +1384,6 @@ namespace MediaBrowser.Api.Playback
state.IsRemote = true;
}
- state.SendInputOverStandardInput = true;
state.ReadInputAtNativeFramerate = true;
state.AudioSync = "1000";
state.DeInterlace = true;
@@ -1411,6 +1428,11 @@ namespace MediaBrowser.Api.Playback
state.SubtitleStream = GetMediaStream(mediaStreams, videoRequest.SubtitleStreamIndex, MediaStreamType.Subtitle, false);
state.AudioStream = GetMediaStream(mediaStreams, videoRequest.AudioStreamIndex, MediaStreamType.Audio);
+ if (state.VideoStream != null && state.VideoStream.IsInterlaced)
+ {
+ state.DeInterlace = true;
+ }
+
EnforceResolutionLimit(state, videoRequest);
}
else
@@ -1420,8 +1442,8 @@ namespace MediaBrowser.Api.Playback
state.HasMediaStreams = mediaStreams.Count > 0;
- state.SegmentLength = state.ReadInputAtNativeFramerate ? 3 : 10;
- state.HlsListSize = state.ReadInputAtNativeFramerate ? 20 : 1440;
+ state.SegmentLength = state.ReadInputAtNativeFramerate ? 5 : 10;
+ state.HlsListSize = state.ReadInputAtNativeFramerate ? 100 : 1440;
return state;
}
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 5324d2c805..aec271ff20 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -278,7 +278,7 @@ namespace MediaBrowser.Api.Playback.Hls
var itsOffset = itsOffsetMs == 0 ? string.Empty : string.Format("-itsoffset {0} ", TimeSpan.FromMilliseconds(itsOffsetMs).TotalSeconds);
- var threads = GetNumberOfThreads(false);
+ var threads = GetNumberOfThreads(state, false);
var inputModifier = GetInputModifier(state);
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index 909dd0f40f..4d8d3a5816 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -102,7 +102,7 @@ namespace MediaBrowser.Api.Playback.Progressive
const string vn = " -vn";
- var threads = GetNumberOfThreads(false);
+ var threads = GetNumberOfThreads(state, false);
var inputModifier = GetInputModifier(state);
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 023c597308..8ae61b5219 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -214,12 +214,16 @@ namespace MediaBrowser.Api.Playback.Progressive
if (request.Static)
{
- return ResultFactory.GetStaticFileResult(Request, state.MediaPath, FileShare.Read, responseHeaders, isHeadRequest);
+ var contentType = state.GetMimeType(state.MediaPath);
+
+ return ResultFactory.GetStaticFileResult(Request, state.MediaPath, contentType, FileShare.Read, responseHeaders, isHeadRequest);
}
if (outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive))
{
- return ResultFactory.GetStaticFileResult(Request, outputPath, FileShare.Read, responseHeaders, isHeadRequest);
+ var contentType = state.GetMimeType(outputPath);
+
+ return ResultFactory.GetStaticFileResult(Request, outputPath, contentType, FileShare.Read, responseHeaders, isHeadRequest);
}
return GetStreamResult(state, responseHeaders, isHeadRequest).Result;
@@ -287,7 +291,7 @@ namespace MediaBrowser.Api.Playback.Progressive
responseHeaders["Accept-Ranges"] = "none";
- var contentType = MimeTypes.GetMimeType(outputPath);
+ var contentType = state.GetMimeType(outputPath);
// Headers only
if (isHeadRequest)
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index 6deea4ffc6..43dc6f0d49 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -102,7 +102,7 @@ namespace MediaBrowser.Api.Playback.Progressive
format = " -f mp4 -movflags frag_keyframe+empty_moov";
}
- var threads = GetNumberOfThreads(string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase));
+ var threads = GetNumberOfThreads(state, string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase));
var inputModifier = GetInputModifier(state);
diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs
index a73a8f0d90..6b0375e2d2 100644
--- a/MediaBrowser.Api/Playback/StreamRequest.cs
+++ b/MediaBrowser.Api/Playback/StreamRequest.cs
@@ -66,6 +66,8 @@ namespace MediaBrowser.Api.Playback
public bool ThrowDebugError { get; set; }
public string Params { get; set; }
+
+ public string ForcedMimeType { get; set; }
}
public class VideoStreamRequest : StreamRequest
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index 3874fa6036..961ac0a2a2 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using System.Collections.Generic;
using System.IO;
@@ -72,5 +73,20 @@ namespace MediaBrowser.Api.Playback
public string InputVideoCodec { get; set; }
public string InputAudioCodec { get; set; }
+
+ public string GetMimeType(string outputPath)
+ {
+ if (!string.IsNullOrWhiteSpace(Request.ForcedMimeType))
+ {
+ if (VideoRequest == null)
+ {
+ return "audio/" + Request.ForcedMimeType;
+ }
+
+ return "video/" + Request.ForcedMimeType;
+ }
+
+ return MimeTypes.GetMimeType(outputPath);
+ }
}
}
diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs
index 18bd8c6956..f46c6b8e30 100644
--- a/MediaBrowser.Api/SearchService.cs
+++ b/MediaBrowser.Api/SearchService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Drawing;
+using System;
+using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -63,6 +64,9 @@ namespace MediaBrowser.Api
[ApiMember(Name = "IncludeArtists", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool IncludeArtists { get; set; }
+ [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; }
+
public GetSearchHints()
{
IncludeArtists = true;
@@ -130,7 +134,8 @@ namespace MediaBrowser.Api
IncludePeople = request.IncludePeople,
IncludeStudios = request.IncludeStudios,
StartIndex = request.StartIndex,
- UserId = request.UserId
+ UserId = request.UserId,
+ IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray()
}).ConfigureAwait(false);
@@ -206,7 +211,8 @@ namespace MediaBrowser.Api
result.SongCount = songs.Count;
- result.Artists = _libraryManager.GetAllArtists(songs)
+ result.Artists = songs.SelectMany(i => i.AllArtists)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
result.AlbumArtist = songs.Select(i => i.AlbumArtist).FirstOrDefault(i => !string.IsNullOrEmpty(i));
diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs
index f662e38170..b8ca70ba5e 100644
--- a/MediaBrowser.Api/SessionsService.cs
+++ b/MediaBrowser.Api/SessionsService.cs
@@ -211,7 +211,7 @@ namespace MediaBrowser.Api
[ApiMember(Name = "PlayableMediaTypes", Description = "A list of playable media types, comma delimited. Audio, Video, Book, Game, Photo.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string PlayableMediaTypes { get; set; }
}
-
+
/// <summary>
/// Class SessionsService
/// </summary>
@@ -368,4 +368,4 @@ namespace MediaBrowser.Api
.ToList();
}
}
-}
+} \ No newline at end of file
diff --git a/MediaBrowser.Api/SimilarItemsHelper.cs b/MediaBrowser.Api/SimilarItemsHelper.cs
index d1dc801bcd..1f02a63a09 100644
--- a/MediaBrowser.Api/SimilarItemsHelper.cs
+++ b/MediaBrowser.Api/SimilarItemsHelper.cs
@@ -73,7 +73,7 @@ namespace MediaBrowser.Api
var item = string.IsNullOrEmpty(request.Id) ?
(request.UserId.HasValue ? user.RootFolder :
- (Folder)libraryManager.RootFolder) : dtoService.GetItemByDtoId(request.Id, request.UserId);
+ libraryManager.RootFolder) : dtoService.GetItemByDtoId(request.Id, request.UserId);
var fields = request.GetItemFields().ToList();
@@ -81,7 +81,7 @@ namespace MediaBrowser.Api
? libraryManager.RootFolder.GetRecursiveChildren(i => i.Id != item.Id)
: user.RootFolder.GetRecursiveChildren(user, i => i.Id != item.Id);
- var items = GetSimilaritems(item, inputItems, includeInSearch, getSimilarityScore)
+ var items = GetSimilaritems(item, inputItems.Where(includeInSearch), getSimilarityScore)
.ToList();
IEnumerable<BaseItem> returnItems = items;
@@ -106,12 +106,12 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="item">The item.</param>
/// <param name="inputItems">The input items.</param>
- /// <param name="includeInSearch">The include in search.</param>
/// <param name="getSimilarityScore">The get similarity score.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
- internal static IEnumerable<BaseItem> GetSimilaritems(BaseItem item, IEnumerable<BaseItem> inputItems, Func<BaseItem, bool> includeInSearch, Func<BaseItem, BaseItem, int> getSimilarityScore)
+ internal static IEnumerable<BaseItem> GetSimilaritems(BaseItem item, IEnumerable<BaseItem> inputItems, Func<BaseItem, BaseItem, int> getSimilarityScore)
{
- inputItems = inputItems.Where(includeInSearch);
+ var itemId = item.Id;
+ inputItems = inputItems.Where(i => i.Id != itemId);
return inputItems.Select(i => new Tuple<BaseItem, int>(i, getSimilarityScore(item, i)))
.Where(i => i.Item2 > 2)
@@ -153,7 +153,7 @@ namespace MediaBrowser.Api
if (!string.IsNullOrEmpty(item1.OfficialRating) && string.Equals(item1.OfficialRating, item2.OfficialRating, StringComparison.OrdinalIgnoreCase))
{
- points += 1;
+ points += 10;
}
// Find common genres
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index 629f9b2333..9e58c9f53d 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Api
/// Class GetNextUpEpisodes
/// </summary>
[Route("/Shows/NextUp", "GET")]
- [Api(("Gets a list of currently installed plugins"))]
+ [Api(("Gets a list of next up episodes"))]
public class GetNextUpEpisodes : IReturn<ItemsResult>, IHasItemFields
{
/// <summary>
@@ -53,6 +53,39 @@ namespace MediaBrowser.Api
public string SeriesId { get; set; }
}
+ [Route("/Shows/Upcoming", "GET")]
+ [Api(("Gets a list of upcoming episodes"))]
+ public class GetUpcomingEpisodes : IReturn<ItemsResult>, IHasItemFields
+ {
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid UserId { get; set; }
+
+ /// <summary>
+ /// Skips over a given number of items within the results. Use for paging.
+ /// </summary>
+ /// <value>The start index.</value>
+ [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int? StartIndex { get; set; }
+
+ /// <summary>
+ /// The maximum number of items to return
+ /// </summary>
+ /// <value>The limit.</value>
+ [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ public int? Limit { get; set; }
+
+ /// <summary>
+ /// Fields to return within the items, in addition to basic information
+ /// </summary>
+ /// <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: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, OverviewHtml, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+ public string Fields { get; set; }
+ }
+
[Route("/Shows/{Id}/Similar", "GET")]
[Api(Description = "Finds tv shows similar to a given one.")]
public class GetSimilarShows : BaseGetSimilarItemsFromItem
@@ -85,7 +118,7 @@ namespace MediaBrowser.Api
[ApiMember(Name = "SeasonId", Description = "Optional. Filter by season id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string SeasonId { get; set; }
-
+
[ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsMissing { get; set; }
@@ -186,6 +219,39 @@ namespace MediaBrowser.Api
return ToOptimizedSerializedResultUsingCache(result);
}
+ public object Get(GetUpcomingEpisodes request)
+ {
+ var user = _userManager.GetUserById(request.UserId);
+
+ var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager)
+ .OfType<Episode>();
+
+ var itemsList = _libraryManager.Sort(items, user, new[] { "PremiereDate", "AirTime", "SortName" }, SortOrder.Ascending)
+ .Cast<Episode>()
+ .ToList();
+
+ var unairedEpisodes = itemsList.Where(i => i.IsUnaired).ToList();
+
+ var minPremiereDate = DateTime.Now.Date.AddDays(-1).ToUniversalTime();
+ var previousEpisodes = itemsList.Where(i => !i.IsUnaired && (i.PremiereDate ?? DateTime.MinValue) >= minPremiereDate).ToList();
+
+ previousEpisodes.AddRange(unairedEpisodes);
+
+ var pagedItems = ApplyPaging(previousEpisodes, request.StartIndex, request.Limit);
+
+ var fields = request.GetItemFields().ToList();
+
+ var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray();
+
+ var result = new ItemsResult
+ {
+ TotalRecordCount = itemsList.Count,
+ Items = returnItems
+ };
+
+ return ToOptimizedSerializedResultUsingCache(result);
+ }
+
/// <summary>
/// Gets the specified request.
/// </summary>
@@ -198,7 +264,7 @@ namespace MediaBrowser.Api
var itemsList = GetNextUpEpisodes(request)
.ToList();
- var pagedItems = ApplyPaging(request, itemsList);
+ var pagedItems = ApplyPaging(itemsList, request.StartIndex, request.Limit);
var fields = request.GetItemFields().ToList();
@@ -234,11 +300,13 @@ namespace MediaBrowser.Api
return FilterSeries(request, series)
.AsParallel()
- .Select(i => GetNextUp(i, currentUser, request).Item1)
- .Where(i => i != null)
+ .Select(i => GetNextUp(i, currentUser))
+ .Where(i => i.Item1 != null)
.OrderByDescending(i =>
{
- var seriesUserData = _userDataManager.GetUserData(user.Id, i.Series.GetUserDataKey());
+ var episode = i.Item1;
+
+ var seriesUserData = _userDataManager.GetUserData(user.Id, episode.Series.GetUserDataKey());
if (seriesUserData.IsFavorite)
{
@@ -252,7 +320,9 @@ namespace MediaBrowser.Api
return 0;
})
- .ThenByDescending(i => i.PremiereDate ?? DateTime.MinValue);
+ .ThenByDescending(i =>i.Item2)
+ .ThenByDescending(i => i.Item1.PremiereDate ?? DateTime.MinValue)
+ .Select(i => i.Item1);
}
/// <summary>
@@ -260,9 +330,8 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="series">The series.</param>
/// <param name="user">The user.</param>
- /// <param name="request">The request.</param>
/// <returns>Task{Episode}.</returns>
- private Tuple<Episode, DateTime> GetNextUp(Series series, User user, GetNextUpEpisodes request)
+ private Tuple<Episode, DateTime> GetNextUp(Series series, User user)
{
// Get them in display order, then reverse
var allEpisodes = series.GetSeasons(user, true, true)
@@ -321,21 +390,22 @@ namespace MediaBrowser.Api
/// <summary>
/// Applies the paging.
/// </summary>
- /// <param name="request">The request.</param>
/// <param name="items">The items.</param>
+ /// <param name="startIndex">The start index.</param>
+ /// <param name="limit">The limit.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
- private IEnumerable<BaseItem> ApplyPaging(GetNextUpEpisodes request, IEnumerable<BaseItem> items)
+ private IEnumerable<BaseItem> ApplyPaging(IEnumerable<BaseItem> items, int? startIndex, int? limit)
{
// Start at
- if (request.StartIndex.HasValue)
+ if (startIndex.HasValue)
{
- items = items.Skip(request.StartIndex.Value);
+ items = items.Skip(startIndex.Value);
}
// Return limit
- if (request.Limit.HasValue)
+ if (limit.HasValue)
{
- items = items.Take(request.Limit.Value);
+ items = items.Take(limit.Value);
}
return items;
@@ -409,7 +479,7 @@ namespace MediaBrowser.Api
return items;
}
-
+
public object Get(GetEpisodes request)
{
var user = _userManager.GetUserById(request.UserId);
@@ -435,7 +505,7 @@ namespace MediaBrowser.Api
{
throw new ResourceNotFoundException("No season exists with Id " + request.SeasonId);
}
-
+
episodes = season.GetEpisodes(user);
}
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
index a96630efe4..9972ac3eff 100644
--- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
@@ -85,10 +85,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetItemByNameDto(item, fields.ToList(), user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetItemByNameDto(item, fields.ToList());
}
/// <summary>
@@ -111,7 +111,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<MusicArtist> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
- return LibraryManager.GetAllArtists(items)
+ return items
+ .OfType<Audio>()
+ .SelectMany(i => i.AllArtists)
+ .Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name =>
{
try
@@ -126,10 +129,5 @@ namespace MediaBrowser.Api.UserLibrary
}).Where(i => i != null);
}
-
- protected override IEnumerable<BaseItem> GetLibraryItems(MusicArtist item, IEnumerable<BaseItem> libraryItems)
- {
- return libraryItems.OfType<IHasArtist>().Where(i => i.HasArtist(item.Name)).Cast<BaseItem>();
- }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 5c2c9967e3..d21014dfed 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -56,15 +56,21 @@ namespace MediaBrowser.Api.UserLibrary
{
User user = null;
BaseItem item;
+ List<BaseItem> libraryItems;
if (request.UserId.HasValue)
{
user = UserManager.GetUserById(request.UserId.Value);
item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoService.GetItemByDtoId(request.ParentId, user.Id);
+
+ libraryItems = user.RootFolder.GetRecursiveChildren(user).ToList();
+
}
else
{
item = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : DtoService.GetItemByDtoId(request.ParentId);
+
+ libraryItems = LibraryManager.RootFolder.RecursiveChildren.ToList();
}
IEnumerable<BaseItem> items;
@@ -93,7 +99,7 @@ namespace MediaBrowser.Api.UserLibrary
var filteredItems = FilterItems(request, extractedItems, user);
- filteredItems = FilterByLibraryItems(request, filteredItems, user);
+ filteredItems = FilterByLibraryItems(request, filteredItems, user, libraryItems);
filteredItems = ItemsService.ApplySortOrder(request, filteredItems, user, LibraryManager).Cast<TItemType>();
@@ -122,45 +128,39 @@ namespace MediaBrowser.Api.UserLibrary
var fields = request.GetItemFields().ToList();
- var dtos = ibnItems.Select(i => GetDto(i, user, fields));
+ var tuples = ibnItems.Select(i => new Tuple<TItemType, List<BaseItem>>(i, i.GetTaggedItems(libraryItems).ToList()));
+
+ var dtos = tuples.Select(i => GetDto(i.Item1, user, fields, i.Item2));
result.Items = dtos.Where(i => i != null).ToArray();
return result;
}
- private IEnumerable<TItemType> FilterByLibraryItems(GetItemsByName request, IEnumerable<TItemType> items, User user)
+ private IEnumerable<TItemType> FilterByLibraryItems(GetItemsByName request, IEnumerable<TItemType> items, User user, IEnumerable<BaseItem> libraryItems)
{
var filters = request.GetFilters().ToList();
if (filters.Contains(ItemFilter.IsPlayed))
{
- var libraryItems = user.RootFolder.GetRecursiveChildren(user).ToList();
-
- items = items.Where(i => GetLibraryItems(i, libraryItems).All(l => l.IsPlayed(user)));
+ items = items.Where(i => i.GetTaggedItems(libraryItems).All(l => l.IsPlayed(user)));
}
if (filters.Contains(ItemFilter.IsUnplayed))
{
- var libraryItems = user.RootFolder.GetRecursiveChildren(user).ToList();
-
- items = items.Where(i => GetLibraryItems(i, libraryItems).All(l => l.IsUnplayed(user)));
+ items = items.Where(i => i.GetTaggedItems(libraryItems).All(l => l.IsUnplayed(user)));
}
if (request.IsPlayed.HasValue)
{
var val = request.IsPlayed.Value;
- var libraryItems = user.RootFolder.GetRecursiveChildren(user).ToList();
-
- items = items.Where(i => GetLibraryItems(i, libraryItems).All(l => l.IsPlayed(user)) == val);
+ items = items.Where(i => i.GetTaggedItems(libraryItems).All(l => l.IsPlayed(user)) == val);
}
return items;
}
- protected abstract IEnumerable<BaseItem> GetLibraryItems(TItemType item, IEnumerable<BaseItem> libraryItems);
-
/// <summary>
/// Filters the items.
/// </summary>
@@ -174,6 +174,10 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1);
}
+ if (!string.IsNullOrEmpty(request.NameStartsWith))
+ {
+ items = items.Where(i => string.Compare(request.NameStartsWith, i.SortName.Substring(0, 1), StringComparison.CurrentCultureIgnoreCase) == 0);
+ }
if (!string.IsNullOrEmpty(request.NameLessThan))
{
@@ -288,11 +292,11 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="item">The item.</param>
/// <param name="user">The user.</param>
/// <param name="fields">The fields.</param>
+ /// <param name="libraryItems">The library items.</param>
/// <returns>Task{DtoBaseItem}.</returns>
- private BaseItemDto GetDto(TItemType item, User user, List<ItemFields> fields)
+ private BaseItemDto GetDto(TItemType item, User user, List<ItemFields> fields, List<BaseItem> libraryItems)
{
- var dto = user == null ? DtoService.GetBaseItemDto(item, fields) :
- DtoService.GetBaseItemDto(item, fields, user);
+ var dto = DtoService.GetItemByNameDto(item, fields, libraryItems, user);
return dto;
}
@@ -313,9 +317,12 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string NameStartsWithOrGreater { get; set; }
+ [ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string NameStartsWith { get; set; }
+
[ApiMember(Name = "NameLessThan", Description = "Optional filter by items whose name is sorted less than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string NameLessThan { get; set; }
-
+
public GetItemsByName()
{
Recursive = true;
diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
index d282ee091d..34eadc3c35 100644
--- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GameGenresService.cs
@@ -76,10 +76,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetItemByNameDto(item, fields.ToList(), user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetItemByNameDto(item, fields.ToList());
}
/// <summary>
@@ -109,10 +109,5 @@ namespace MediaBrowser.Api.UserLibrary
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => LibraryManager.GetGameGenre(name));
}
-
- protected override IEnumerable<BaseItem> GetLibraryItems(GameGenre item, IEnumerable<BaseItem> libraryItems)
- {
- return libraryItems.Where(i => (i is Game) && i.Genres.Contains(item.Name, StringComparer.OrdinalIgnoreCase));
- }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index 092c638822..5d362c61a3 100644
--- a/MediaBrowser.Api/UserLibrary/GenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GenresService.cs
@@ -81,10 +81,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetItemByNameDto(item, fields.ToList(), user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetItemByNameDto(item, fields.ToList());
}
/// <summary>
@@ -112,10 +112,5 @@ namespace MediaBrowser.Api.UserLibrary
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => LibraryManager.GetGenre(name));
}
-
- protected override IEnumerable<BaseItem> GetLibraryItems(Genre item, IEnumerable<BaseItem> libraryItems)
- {
- return libraryItems.Where(i => !(i is Game) && !(i is IHasMusicGenres) && i.Genres.Contains(item.Name, StringComparer.OrdinalIgnoreCase));
- }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 871c9aecb4..b040d3dd81 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -111,6 +111,12 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string NameStartsWithOrGreater { get; set; }
+ [ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string NameStartsWith { get; set; }
+
+ [ApiMember(Name = "NameLessThan", Description = "Optional filter by items whose name is equally or lesser than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public string NameLessThan { get; set; }
+
[ApiMember(Name = "AlbumArtistStartsWithOrGreater", Description = "Optional filter by items whose album artist is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string AlbumArtistStartsWithOrGreater { get; set; }
@@ -768,6 +774,15 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1);
}
+ if (!string.IsNullOrEmpty(request.NameStartsWith))
+ {
+ items = items.Where(i => string.Compare(request.NameStartsWith, i.SortName.Substring(0, 1), StringComparison.CurrentCultureIgnoreCase) == 0);
+ }
+
+ if (!string.IsNullOrEmpty(request.NameLessThan))
+ {
+ items = items.Where(i => string.Compare(request.NameLessThan, i.SortName, StringComparison.CurrentCultureIgnoreCase) == 1);
+ }
if (!string.IsNullOrEmpty(request.AlbumArtistStartsWithOrGreater))
{
diff --git a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
index 3f960ccbe9..9b7a941d84 100644
--- a/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/MusicGenresService.cs
@@ -76,10 +76,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetItemByNameDto(item, fields.ToList(), user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetItemByNameDto(item, fields.ToList());
}
/// <summary>
@@ -109,10 +109,5 @@ namespace MediaBrowser.Api.UserLibrary
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => LibraryManager.GetMusicGenre(name));
}
-
- protected override IEnumerable<BaseItem> GetLibraryItems(MusicGenre item, IEnumerable<BaseItem> libraryItems)
- {
- return libraryItems.Where(i => (i is IHasMusicGenres) && i.Genres.Contains(item.Name, StringComparer.OrdinalIgnoreCase));
- }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs
index 32700d21ab..f7ea4198d6 100644
--- a/MediaBrowser.Api/UserLibrary/PersonsService.cs
+++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs
@@ -93,10 +93,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetItemByNameDto(item, fields.ToList(), user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetItemByNameDto(item, fields.ToList());
}
/// <summary>
@@ -163,10 +163,5 @@ namespace MediaBrowser.Api.UserLibrary
people.Where(p => personTypes.Contains(p.Type ?? string.Empty, StringComparer.OrdinalIgnoreCase) || personTypes.Contains(p.Role ?? string.Empty, StringComparer.OrdinalIgnoreCase));
}
-
- protected override IEnumerable<BaseItem> GetLibraryItems(Person item, IEnumerable<BaseItem> libraryItems)
- {
- return libraryItems.Where(i => i.People.Any(p => string.Equals(p.Name, item.Name, StringComparison.OrdinalIgnoreCase)));
- }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs
index cf4e333e1b..fc7fdd1600 100644
--- a/MediaBrowser.Api/UserLibrary/StudiosService.cs
+++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs
@@ -81,10 +81,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetItemByNameDto(item, fields.ToList(), user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetItemByNameDto(item, fields.ToList());
}
/// <summary>
@@ -114,10 +114,5 @@ namespace MediaBrowser.Api.UserLibrary
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => LibraryManager.GetStudio(name));
}
-
- protected override IEnumerable<BaseItem> GetLibraryItems(Studio item, IEnumerable<BaseItem> libraryItems)
- {
- return libraryItems.Where(i => i.Studios.Contains(item.Name, StringComparer.OrdinalIgnoreCase));
- }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index c2abc6ad11..e026aec038 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -680,18 +680,34 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
public object Post(MarkPlayedItem request)
{
+ var result = MarkPlayed(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ private async Task<UserItemDataDto> MarkPlayed(MarkPlayedItem request)
+ {
var user = _userManager.GetUserById(request.UserId);
DateTime? datePlayed = null;
-
+
if (!string.IsNullOrEmpty(request.DatePlayed))
{
datePlayed = DateTime.ParseExact(request.DatePlayed, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
}
- var task = UpdatePlayedStatus(user, request.Id, true, datePlayed);
+ var session = GetSession();
+
+ var dto = await UpdatePlayedStatus(user, request.Id, true, datePlayed).ConfigureAwait(false);
- return ToOptimizedResult(task.Result);
+ foreach (var additionalUserInfo in session.AdditionalUsers)
+ {
+ var additionalUser = _userManager.GetUserById(new Guid(additionalUserInfo.UserId));
+
+ await UpdatePlayedStatus(additionalUser, request.Id, true, datePlayed).ConfigureAwait(false);
+ }
+
+ return dto;
}
private SessionInfo GetSession()
@@ -780,11 +796,27 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
public object Delete(MarkUnplayedItem request)
{
+ var task = MarkUnplayed(request);
+
+ return ToOptimizedResult(task.Result);
+ }
+
+ private async Task<UserItemDataDto> MarkUnplayed(MarkUnplayedItem request)
+ {
var user = _userManager.GetUserById(request.UserId);
- var task = UpdatePlayedStatus(user, request.Id, false, null);
+ var session = GetSession();
+
+ var dto = await UpdatePlayedStatus(user, request.Id, false, null).ConfigureAwait(false);
- return ToOptimizedResult(task.Result);
+ foreach (var additionalUserInfo in session.AdditionalUsers)
+ {
+ var additionalUser = _userManager.GetUserById(new Guid(additionalUserInfo.UserId));
+
+ await UpdatePlayedStatus(additionalUser, request.Id, false, null).ConfigureAwait(false);
+ }
+
+ return dto;
}
/// <summary>
diff --git a/MediaBrowser.Api/UserLibrary/YearsService.cs b/MediaBrowser.Api/UserLibrary/YearsService.cs
index 7024d52563..b8b0aa9e94 100644
--- a/MediaBrowser.Api/UserLibrary/YearsService.cs
+++ b/MediaBrowser.Api/UserLibrary/YearsService.cs
@@ -7,7 +7,6 @@ using MediaBrowser.Model.Querying;
using ServiceStack;
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
namespace MediaBrowser.Api.UserLibrary
@@ -81,10 +80,10 @@ namespace MediaBrowser.Api.UserLibrary
{
var user = UserManager.GetUserById(request.UserId.Value);
- return DtoService.GetBaseItemDto(item, fields.ToList(), user);
+ return DtoService.GetItemByNameDto(item, fields.ToList(), user);
}
- return DtoService.GetBaseItemDto(item, fields.ToList());
+ return DtoService.GetItemByNameDto(item, fields.ToList());
}
/// <summary>
@@ -115,19 +114,5 @@ namespace MediaBrowser.Api.UserLibrary
.Distinct()
.Select(year => LibraryManager.GetYear(year));
}
-
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- protected override IEnumerable<BaseItem> GetLibraryItems(Year item, IEnumerable<BaseItem> libraryItems)
- {
- int year;
-
- if (!int.TryParse(item.Name, NumberStyles.Integer, UsCulture, out year))
- {
- return libraryItems;
- }
-
- return libraryItems.Where(i => i.ProductionYear.HasValue && i.ProductionYear.Value == year);
- }
}
}