using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Querying; using ServiceStack; using System; using System.Collections.Generic; using System.Linq; namespace MediaBrowser.Api { [Route("/Songs/{Id}/InstantMix", "GET")] [Api(Description = "Creates an instant playlist based on a given song")] public class GetInstantMixFromSong : BaseGetSimilarItemsFromItem { } [Route("/Albums/{Id}/InstantMix", "GET")] [Api(Description = "Creates an instant playlist based on a given album")] public class GetInstantMixFromAlbum : BaseGetSimilarItemsFromItem { } [Route("/Artists/{Name}/InstantMix", "GET")] [Api(Description = "Creates an instant playlist based on a given artist")] public class GetInstantMixFromArtist : BaseGetSimilarItems { [ApiMember(Name = "Name", Description = "The artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Name { get; set; } } [Route("/MusicGenres/{Name}/InstantMix", "GET")] [Api(Description = "Creates an instant playlist based on a music genre")] public class GetInstantMixFromMusicGenre : BaseGetSimilarItems { [ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Name { get; set; } } public class InstantMixService : BaseApiService { private readonly IUserManager _userManager; private readonly ILibraryManager _libraryManager; private readonly IDtoService _dtoService; public InstantMixService(IUserManager userManager, ILibraryManager libraryManager, IDtoService dtoService) { _userManager = userManager; _libraryManager = libraryManager; _dtoService = dtoService; } public object Get(GetInstantMixFromSong request) { var item = _dtoService.GetItemByDtoId(request.Id); var result = GetInstantMixResult(request, item.Genres); return ToOptimizedSerializedResultUsingCache(result); } public object Get(GetInstantMixFromAlbum request) { var album = (MusicAlbum)_dtoService.GetItemByDtoId(request.Id); var genres = album .RecursiveChildren .OfType<Audio>() .SelectMany(i => i.Genres) .Concat(album.Genres) .Distinct(StringComparer.OrdinalIgnoreCase); var result = GetInstantMixResult(request, genres); return ToOptimizedSerializedResultUsingCache(result); } public object Get(GetInstantMixFromMusicGenre request) { var genre = GetMusicGenre(request.Name, _libraryManager); var result = GetInstantMixResult(request, new[] { genre.Name }); return ToOptimizedSerializedResultUsingCache(result); } public object Get(GetInstantMixFromArtist request) { var artist = GetArtist(request.Name, _libraryManager); var genres = _libraryManager.RootFolder .RecursiveChildren .OfType<Audio>() .Where(i => i.HasArtist(artist.Name)) .SelectMany(i => i.Genres) .Concat(artist.Genres) .Distinct(StringComparer.OrdinalIgnoreCase); var result = GetInstantMixResult(request, genres); return ToOptimizedSerializedResultUsingCache(result); } private ItemsResult GetInstantMixResult(BaseGetSimilarItems request, IEnumerable<string> genres) { var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null; var fields = request.GetItemFields().ToList(); var inputItems = user == null ? _libraryManager.RootFolder.RecursiveChildren : user.RootFolder.GetRecursiveChildren(user); var genresDictionary = genres.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); var limit = request.Limit.HasValue ? request.Limit.Value * 2 : 100; var items = inputItems .OfType<Audio>() .Select(i => new Tuple<Audio, int>(i, i.Genres.Count(genresDictionary.ContainsKey))) .OrderByDescending(i => i.Item2) .ThenBy(i => Guid.NewGuid()) .Select(i => i.Item1) .Take(limit) .OrderBy(i => Guid.NewGuid()) .ToList(); var result = new ItemsResult { TotalRecordCount = items.Count }; var dtos = items.Take(request.Limit ?? items.Count) .Select(i => _dtoService.GetBaseItemDto(i, fields, user)); result.Items = dtos.ToArray(); return result; } } }