Browse Source

Move AlbumsService to Jellyfin.Api

David 5 years ago
parent
commit
fa98013621

+ 128 - 0
Jellyfin.Api/Controllers/AlbumsController.cs

@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Jellyfin.Api.Extensions;
+using Jellyfin.Api.Helpers;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Querying;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Jellyfin.Api.Controllers
+{
+    /// <summary>
+    /// The albums controller.
+    /// </summary>
+    public class AlbumsController : BaseJellyfinApiController
+    {
+        private readonly IUserManager _userManager;
+        private readonly ILibraryManager _libraryManager;
+        private readonly IDtoService _dtoService;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AlbumsController"/> class.
+        /// </summary>
+        /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
+        /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
+        /// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
+        public AlbumsController(
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IDtoService dtoService)
+        {
+            _userManager = userManager;
+            _libraryManager = libraryManager;
+            _dtoService = dtoService;
+        }
+
+        /// <summary>
+        /// Finds albums similar to a given album.
+        /// </summary>
+        /// <param name="albumId">The album id.</param>
+        /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
+        /// <param name="excludeArtistIds">Optional. Ids of artists to exclude.</param>
+        /// <param name="limit">Optional. The maximum number of records to return.</param>
+        /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with similar albums.</returns>
+        [HttpGet("/Albums/{albumId}/Similar")]
+        public ActionResult<QueryResult<BaseItemDto>> GetSimilarAlbums(
+            [FromRoute] string albumId,
+            [FromQuery] Guid userId,
+            [FromQuery] string excludeArtistIds,
+            [FromQuery] int? limit)
+        {
+            var dtoOptions = new DtoOptions().AddClientFields(Request);
+
+            return SimilarItemsHelper.GetSimilarItemsResult(
+                dtoOptions,
+                _userManager,
+                _libraryManager,
+                _dtoService,
+                userId,
+                albumId,
+                excludeArtistIds,
+                limit,
+                new[] { typeof(MusicAlbum) },
+                GetAlbumSimilarityScore);
+        }
+
+        /// <summary>
+        /// Finds artists similar to a given artist.
+        /// </summary>
+        /// <param name="artistId">The artist id.</param>
+        /// <param name="userId">Optional. Filter by user id, and attach user data.</param>
+        /// <param name="excludeArtistIds">Optional. Ids of artists to exclude.</param>
+        /// <param name="limit">Optional. The maximum number of records to return.</param>
+        /// <returns>A <see cref="QueryResult{BaseItemDto}"/> with similar artists.</returns>
+        [HttpGet("/Artists/{artistId}/Similar")]
+        public ActionResult<QueryResult<BaseItemDto>> GetSimilarArtists(
+            [FromRoute] string artistId,
+            [FromQuery] Guid userId,
+            [FromQuery] string excludeArtistIds,
+            [FromQuery] int? limit)
+        {
+            var dtoOptions = new DtoOptions().AddClientFields(Request);
+
+            return SimilarItemsHelper.GetSimilarItemsResult(
+                dtoOptions,
+                _userManager,
+                _libraryManager,
+                _dtoService,
+                userId,
+                artistId,
+                excludeArtistIds,
+                limit,
+                new[] { typeof(MusicArtist) },
+                SimilarItemsHelper.GetSimiliarityScore);
+        }
+
+        /// <summary>
+        /// Gets a similairty score of two albums.
+        /// </summary>
+        /// <param name="item1">The first item.</param>
+        /// <param name="item1People">The item1 people.</param>
+        /// <param name="allPeople">All people.</param>
+        /// <param name="item2">The second item.</param>
+        /// <returns>System.Int32.</returns>
+        private int GetAlbumSimilarityScore(BaseItem item1, List<PersonInfo> item1People, List<PersonInfo> allPeople, BaseItem item2)
+        {
+            var points = SimilarItemsHelper.GetSimiliarityScore(item1, item1People, allPeople, item2);
+
+            var album1 = (MusicAlbum)item1;
+            var album2 = (MusicAlbum)item2;
+
+            var artists1 = album1
+                .GetAllArtists()
+                .DistinctNames()
+                .ToList();
+
+            var artists2 = new HashSet<string>(
+                album2.GetAllArtists().DistinctNames(),
+                StringComparer.OrdinalIgnoreCase);
+
+            return points + artists1.Where(artists2.Contains).Sum(i => 5);
+        }
+    }
+}

+ 182 - 0
Jellyfin.Api/Helpers/SimilarItemsHelper.cs

@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
+
+namespace Jellyfin.Api.Helpers
+{
+    /// <summary>
+    /// The similar items helper class.
+    /// </summary>
+    public static class SimilarItemsHelper
+    {
+        internal static QueryResult<BaseItemDto> GetSimilarItemsResult(
+            DtoOptions dtoOptions,
+            IUserManager userManager,
+            ILibraryManager libraryManager,
+            IDtoService dtoService,
+            Guid userId,
+            string id,
+            string excludeArtistIds,
+            int? limit,
+            Type[] includeTypes,
+            Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
+        {
+            var user = !userId.Equals(Guid.Empty) ? userManager.GetUserById(userId) : null;
+
+            var item = string.IsNullOrEmpty(id) ?
+                (!userId.Equals(Guid.Empty) ? libraryManager.GetUserRootFolder() :
+                libraryManager.RootFolder) : libraryManager.GetItemById(id);
+
+            var query = new InternalItemsQuery(user)
+            {
+                IncludeItemTypes = includeTypes.Select(i => i.Name).ToArray(),
+                Recursive = true,
+                DtoOptions = dtoOptions
+            };
+
+            query.ExcludeArtistIds = RequestHelpers.GetGuids(excludeArtistIds);
+
+            var inputItems = libraryManager.GetItemList(query);
+
+            var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore)
+                .ToList();
+
+            var returnItems = items;
+
+            if (limit.HasValue)
+            {
+                returnItems = returnItems.Take(limit.Value).ToList();
+            }
+
+            var dtos = dtoService.GetBaseItemDtos(returnItems, dtoOptions, user);
+
+            return new QueryResult<BaseItemDto>
+            {
+                Items = dtos,
+                TotalRecordCount = items.Count
+            };
+        }
+
+        /// <summary>
+        /// Gets the similaritems.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="libraryManager">The library manager.</param>
+        /// <param name="inputItems">The input items.</param>
+        /// <param name="getSimilarityScore">The get similarity score.</param>
+        /// <returns>IEnumerable{BaseItem}.</returns>
+        private static IEnumerable<BaseItem> GetSimilaritems(
+            BaseItem item,
+            ILibraryManager libraryManager,
+            IEnumerable<BaseItem> inputItems,
+            Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
+        {
+            var itemId = item.Id;
+            inputItems = inputItems.Where(i => i.Id != itemId);
+            var itemPeople = libraryManager.GetPeople(item);
+            var allPeople = libraryManager.GetPeople(new InternalPeopleQuery
+            {
+                AppearsInItemId = item.Id
+            });
+
+            return inputItems.Select(i => new Tuple<BaseItem, int>(i, getSimilarityScore(item, itemPeople, allPeople, i)))
+                .Where(i => i.Item2 > 2)
+                .OrderByDescending(i => i.Item2)
+                .Select(i => i.Item1);
+        }
+
+        private static IEnumerable<string> GetTags(BaseItem item)
+        {
+            return item.Tags;
+        }
+
+        /// <summary>
+        /// Gets the similiarity score.
+        /// </summary>
+        /// <param name="item1">The item1.</param>
+        /// <param name="item1People">The item1 people.</param>
+        /// <param name="allPeople">All people.</param>
+        /// <param name="item2">The item2.</param>
+        /// <returns>System.Int32.</returns>
+        internal static int GetSimiliarityScore(BaseItem item1, List<PersonInfo> item1People, List<PersonInfo> allPeople, BaseItem item2)
+        {
+            var points = 0;
+
+            if (!string.IsNullOrEmpty(item1.OfficialRating) && string.Equals(item1.OfficialRating, item2.OfficialRating, StringComparison.OrdinalIgnoreCase))
+            {
+                points += 10;
+            }
+
+            // Find common genres
+            points += item1.Genres.Where(i => item2.Genres.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
+
+            // Find common tags
+            points += GetTags(item1).Where(i => GetTags(item2).Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
+
+            // Find common studios
+            points += item1.Studios.Where(i => item2.Studios.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 3);
+
+            var item2PeopleNames = allPeople.Where(i => i.ItemId == item2.Id)
+                .Select(i => i.Name)
+                .Where(i => !string.IsNullOrWhiteSpace(i))
+                .DistinctNames()
+                .ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
+
+            points += item1People.Where(i => item2PeopleNames.ContainsKey(i.Name)).Sum(i =>
+            {
+                if (string.Equals(i.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Director, StringComparison.OrdinalIgnoreCase))
+                {
+                    return 5;
+                }
+
+                if (string.Equals(i.Type, PersonType.Actor, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Actor, StringComparison.OrdinalIgnoreCase))
+                {
+                    return 3;
+                }
+
+                if (string.Equals(i.Type, PersonType.Composer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Composer, StringComparison.OrdinalIgnoreCase))
+                {
+                    return 3;
+                }
+
+                if (string.Equals(i.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
+                {
+                    return 3;
+                }
+
+                if (string.Equals(i.Type, PersonType.Writer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase))
+                {
+                    return 2;
+                }
+
+                return 1;
+            });
+
+            if (item1.ProductionYear.HasValue && item2.ProductionYear.HasValue)
+            {
+                var diff = Math.Abs(item1.ProductionYear.Value - item2.ProductionYear.Value);
+
+                // Add if they came out within the same decade
+                if (diff < 10)
+                {
+                    points += 2;
+                }
+
+                // And more if within five years
+                if (diff < 5)
+                {
+                    points += 2;
+                }
+            }
+
+            return points;
+        }
+    }
+}

+ 0 - 132
MediaBrowser.Api/Music/AlbumsService.cs

@@ -1,132 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Services;
-using Microsoft.Extensions.Logging;
-
-namespace MediaBrowser.Api.Music
-{
-    [Route("/Albums/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")]
-    public class GetSimilarAlbums : BaseGetSimilarItemsFromItem
-    {
-    }
-
-    [Route("/Artists/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")]
-    public class GetSimilarArtists : BaseGetSimilarItemsFromItem
-    {
-    }
-
-    [Authenticated]
-    public class AlbumsService : 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;
-        private readonly IAuthorizationContext _authContext;
-
-        public AlbumsService(
-            ILogger<AlbumsService> logger,
-            IServerConfigurationManager serverConfigurationManager,
-            IHttpResultFactory httpResultFactory,
-            IUserManager userManager,
-            IUserDataManager userDataRepository,
-            ILibraryManager libraryManager,
-            IItemRepository itemRepo,
-            IDtoService dtoService,
-            IAuthorizationContext authContext)
-            : base(logger, serverConfigurationManager, httpResultFactory)
-        {
-            _userManager = userManager;
-            _userDataRepository = userDataRepository;
-            _libraryManager = libraryManager;
-            _itemRepo = itemRepo;
-            _dtoService = dtoService;
-            _authContext = authContext;
-        }
-
-        public object Get(GetSimilarArtists request)
-        {
-            var dtoOptions = GetDtoOptions(_authContext, request);
-
-            var result = SimilarItemsHelper.GetSimilarItemsResult(
-                dtoOptions, 
-                _userManager,
-                _itemRepo,
-                _libraryManager,
-                _userDataRepository,
-                _dtoService,
-                request, new[] { typeof(MusicArtist) },
-                SimilarItemsHelper.GetSimiliarityScore);
-
-            return ToOptimizedResult(result);
-        }
-
-        /// <summary>
-        /// Gets the specified request.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <returns>System.Object.</returns>
-        public object Get(GetSimilarAlbums request)
-        {
-            var dtoOptions = GetDtoOptions(_authContext, request);
-
-            var result = SimilarItemsHelper.GetSimilarItemsResult(
-                dtoOptions, 
-                _userManager,
-                _itemRepo,
-                _libraryManager,
-                _userDataRepository,
-                _dtoService,
-                request, new[] { typeof(MusicAlbum) },
-                GetAlbumSimilarityScore);
-
-            return ToOptimizedResult(result);
-        }
-
-        /// <summary>
-        /// Gets the album similarity score.
-        /// </summary>
-        /// <param name="item1">The item1.</param>
-        /// <param name="item1People">The item1 people.</param>
-        /// <param name="allPeople">All people.</param>
-        /// <param name="item2">The item2.</param>
-        /// <returns>System.Int32.</returns>
-        private int GetAlbumSimilarityScore(BaseItem item1, List<PersonInfo> item1People, List<PersonInfo> allPeople, BaseItem item2)
-        {
-            var points = SimilarItemsHelper.GetSimiliarityScore(item1, item1People, allPeople, item2);
-
-            var album1 = (MusicAlbum)item1;
-            var album2 = (MusicAlbum)item2;
-
-            var artists1 = album1
-                .GetAllArtists()
-                .DistinctNames()
-                .ToList();
-
-            var artists2 = new HashSet<string>(
-                album2.GetAllArtists().DistinctNames(),
-                StringComparer.OrdinalIgnoreCase);
-
-            return points + artists1.Where(artists2.Contains).Sum(i => 5);
-        }
-    }
-}