Browse Source

Merge pull request #1127 from MediaBrowser/dev

3.0.5641.5
Luke 10 years ago
parent
commit
63f9abd4d6
100 changed files with 1318 additions and 431 deletions
  1. 5 8
      MediaBrowser.Api/BaseApiService.cs
  2. 5 5
      MediaBrowser.Api/ItemUpdateService.cs
  3. 1 0
      MediaBrowser.Api/MediaBrowser.Api.csproj
  4. 35 15
      MediaBrowser.Api/Movies/MoviesService.cs
  5. 5 2
      MediaBrowser.Api/Music/AlbumsService.cs
  6. 1 1
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  7. 20 15
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  8. 3 4
      MediaBrowser.Api/Reports/ReportsService.cs
  9. 1 1
      MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs
  10. 17 7
      MediaBrowser.Api/SimilarItemsHelper.cs
  11. 164 0
      MediaBrowser.Api/Social/SharingService.cs
  12. 3 4
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  13. 6 9
      MediaBrowser.Api/UserLibrary/PersonsService.cs
  14. 7 0
      MediaBrowser.Common.Implementations/Logging/NlogManager.cs
  15. 9 0
      MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
  16. 9 0
      MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
  17. 14 87
      MediaBrowser.Controller/Entities/BaseItem.cs
  18. 11 0
      MediaBrowser.Controller/Entities/BasePluginFolder.cs
  19. 9 0
      MediaBrowser.Controller/Entities/CollectionFolder.cs
  20. 4 4
      MediaBrowser.Controller/Entities/Folder.cs
  21. 9 0
      MediaBrowser.Controller/Entities/GameGenre.cs
  22. 9 0
      MediaBrowser.Controller/Entities/GameSystem.cs
  23. 9 0
      MediaBrowser.Controller/Entities/Genre.cs
  24. 6 0
      MediaBrowser.Controller/Entities/IHasMetadata.cs
  25. 1 1
      MediaBrowser.Controller/Entities/IItemByName.cs
  26. 21 0
      MediaBrowser.Controller/Entities/InternalPeopleQuery.cs
  27. 100 0
      MediaBrowser.Controller/Entities/PeopleHelper.cs
  28. 18 2
      MediaBrowser.Controller/Entities/Person.cs
  29. 9 0
      MediaBrowser.Controller/Entities/Studio.cs
  30. 9 0
      MediaBrowser.Controller/Entities/User.cs
  31. 11 1
      MediaBrowser.Controller/Entities/UserView.cs
  32. 3 5
      MediaBrowser.Controller/Entities/UserViewBuilder.cs
  33. 9 0
      MediaBrowser.Controller/Entities/Year.cs
  34. 49 0
      MediaBrowser.Controller/Library/ILibraryManager.cs
  35. 5 0
      MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
  36. 5 0
      MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
  37. 3 0
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  38. 22 0
      MediaBrowser.Controller/Persistence/IItemRepository.cs
  39. 14 12
      MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
  40. 2 8
      MediaBrowser.Controller/Providers/LocalMetadataResult.cs
  41. 10 0
      MediaBrowser.Controller/Providers/MetadataResult.cs
  42. 28 0
      MediaBrowser.Controller/Social/ISharingManager.cs
  43. 14 0
      MediaBrowser.Controller/Sync/IServerSyncProvider.cs
  44. 17 39
      MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
  45. 6 2
      MediaBrowser.Dlna/Didl/DidlBuilder.cs
  46. 1 0
      MediaBrowser.Dlna/DlnaManager.cs
  47. 4 0
      MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
  48. 1 1
      MediaBrowser.Dlna/PlayTo/PlayToController.cs
  49. 17 1
      MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
  50. 20 4
      MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
  51. 17 1
      MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs
  52. 17 1
      MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs
  53. 260 0
      MediaBrowser.Dlna/Profiles/SonyPs4Profile.cs
  54. 6 1
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
  55. 9 4
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
  56. 6 1
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml
  57. 6 1
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml
  58. 31 0
      MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml
  59. 3 3
      MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs
  60. 12 18
      MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs
  61. 6 4
      MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs
  62. 6 4
      MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs
  63. 25 27
      MediaBrowser.LocalMetadata/Parsers/MovieXmlParser.cs
  64. 6 4
      MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs
  65. 4 2
      MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs
  66. 5 3
      MediaBrowser.LocalMetadata/Parsers/SeasonXmlParser.cs
  67. 6 4
      MediaBrowser.LocalMetadata/Parsers/SeriesXmlParser.cs
  68. 1 1
      MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs
  69. 1 2
      MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs
  70. 1 1
      MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs
  71. 1 1
      MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs
  72. 1 1
      MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs
  73. 1 7
      MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs
  74. 1 1
      MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs
  75. 1 1
      MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs
  76. 1 1
      MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs
  77. 1 1
      MediaBrowser.LocalMetadata/Providers/SeasonXmlProvider.cs
  78. 1 1
      MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs
  79. 4 10
      MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs
  80. 4 2
      MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs
  81. 4 2
      MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs
  82. 4 2
      MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs
  83. 4 2
      MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs
  84. 5 3
      MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs
  85. 1 1
      MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs
  86. 4 2
      MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs
  87. 5 3
      MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs
  88. 5 3
      MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs
  89. 6 3
      MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
  90. 2 2
      MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
  91. 3 0
      MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
  92. 3 0
      MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
  93. 6 3
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  94. 18 11
      MediaBrowser.Model/Dlna/StreamBuilder.cs
  95. 1 2
      MediaBrowser.Model/Entities/MediaStream.cs
  96. 1 0
      MediaBrowser.Model/MediaBrowser.Model.csproj
  97. 16 0
      MediaBrowser.Model/Social/SocialShareInfo.cs
  98. 4 12
      MediaBrowser.Providers/Books/BookMetadataService.cs
  99. 19 24
      MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs
  100. 2 10
      MediaBrowser.Providers/Channels/AudioChannelItemMetadataService.cs

+ 5 - 8
MediaBrowser.Api/BaseApiService.cs

@@ -1,5 +1,4 @@
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
@@ -12,6 +11,7 @@ using ServiceStack.Web;
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Api
 {
@@ -344,11 +344,7 @@ namespace MediaBrowser.Api
                 return name;
             }
 
-            return libraryManager.RootFolder
-                .GetRecursiveChildren()
-                .SelectMany(i => i.People)
-                .Select(i => i.Name)
-                .DistinctNames()
+            return libraryManager.GetPeopleNames(new InternalPeopleQuery())
                 .FirstOrDefault(i =>
                 {
                     i = _dashReplaceChars.Aggregate(i, (current, c) => current.Replace(c, SlugChar));
@@ -364,7 +360,8 @@ namespace MediaBrowser.Api
             var first = pathInfo.GetArgumentValue<string>(0);
 
             // backwards compatibility
-            if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase))
+            if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase) ||
+                string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase))
             {
                 index++;
             }

+ 5 - 5
MediaBrowser.Api/ItemUpdateService.cs

@@ -218,6 +218,11 @@ namespace MediaBrowser.Api
 
             await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
 
+            if (request.People != null)
+            {
+                await _libraryManager.UpdatePeople(item, request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList());
+            }
+
             if (isLockedChanged && item.IsFolder)
             {
                 var folder = (Folder)item;
@@ -303,11 +308,6 @@ namespace MediaBrowser.Api
                 item.Studios = request.Studios.Select(x => x.Name).ToList();
             }
 
-            if (request.People != null)
-            {
-                item.People = request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList();
-            }
-
             if (request.DateCreated.HasValue)
             {
                 item.DateCreated = NormalizeDateTime(request.DateCreated.Value);

+ 1 - 0
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -106,6 +106,7 @@
     <Compile Include="Reports\Stat\ReportStatGroup.cs" />
     <Compile Include="Reports\Stat\ReportStatItem.cs" />
     <Compile Include="Reports\Stat\ReportStatResult.cs" />
+    <Compile Include="Social\SharingService.cs" />
     <Compile Include="StartupWizardService.cs" />
     <Compile Include="Subtitles\SubtitleService.cs" />
     <Compile Include="Movies\CollectionService.cs" />

+ 35 - 15
MediaBrowser.Api/Movies/MoviesService.cs

@@ -165,7 +165,7 @@ namespace MediaBrowser.Api.Movies
             return ToOptimizedResult(result);
         }
 
-        private async Task<ItemsResult> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, BaseItem, int> getSimilarityScore)
+        private async Task<ItemsResult> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
         {
             var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
 
@@ -214,7 +214,7 @@ namespace MediaBrowser.Api.Movies
                 }
             }
 
-            var items = SimilarItemsHelper.GetSimilaritems(item, list, getSimilarityScore).ToList();
+            var items = SimilarItemsHelper.GetSimilaritems(item, _libraryManager, list, getSimilarityScore).ToList();
 
             IEnumerable<BaseItem> returnItems = items;
 
@@ -339,7 +339,7 @@ namespace MediaBrowser.Api.Movies
             foreach (var director in directors)
             {
                 var items = allMovies
-                    .Where(i => i.People.Any(p => string.Equals(p.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) && string.Equals(p.Name, director, StringComparison.OrdinalIgnoreCase)))
+                    .Where(i => _libraryManager.GetPeople(i).Any(p => string.Equals(p.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) && string.Equals(p.Name, director, StringComparison.OrdinalIgnoreCase)))
                     .Take(itemLimit)
                     .ToList();
 
@@ -358,12 +358,15 @@ namespace MediaBrowser.Api.Movies
 
         private IEnumerable<RecommendationDto> GetWithActor(User user, List<BaseItem> allMovies, IEnumerable<string> names, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
         {
-            var userId = user.Id;
-
             foreach (var name in names)
             {
+                var itemsWithActor = _libraryManager.GetItemIds(new InternalItemsQuery
+                {
+                    Person = name
+                });
+
                 var items = allMovies
-                    .Where(i => i.People.Any(p => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase)))
+                    .Where(i => itemsWithActor.Contains(i.Id))
                     .Take(itemLimit)
                     .ToList();
 
@@ -382,12 +385,10 @@ namespace MediaBrowser.Api.Movies
 
         private IEnumerable<RecommendationDto> GetSimilarTo(User user, List<BaseItem> allMovies, IEnumerable<BaseItem> baselineItems, int itemLimit, DtoOptions dtoOptions, RecommendationType type)
         {
-            var userId = user.Id;
-
             foreach (var item in baselineItems)
             {
                 var similar = SimilarItemsHelper
-                    .GetSimilaritems(item, allMovies, SimilarItemsHelper.GetSimiliarityScore)
+                    .GetSimilaritems(item, _libraryManager, allMovies, SimilarItemsHelper.GetSimiliarityScore)
                     .Take(itemLimit)
                     .ToList();
 
@@ -406,18 +407,37 @@ namespace MediaBrowser.Api.Movies
 
         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))
+            var people = _libraryManager.GetPeople(new InternalPeopleQuery
+            {
+                ExcludePersonTypes = new List<string>
+                {
+                    PersonType.Director
+                },
+                MaxListOrder = 3
+            });
+
+            var itemIds = items.Select(i => i.Id).ToList();
+
+            return people
+                .Where(i => itemIds.Contains(i.ItemId))
                 .Select(i => i.Name)
                 .DistinctNames();
         }
 
         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)
+            var people = _libraryManager.GetPeople(new InternalPeopleQuery
+            {
+                PersonTypes = new List<string>
+                {
+                    PersonType.Director
+                }
+            });
+
+            var itemIds = items.Select(i => i.Id).ToList();
+
+            return people
+                .Where(i => itemIds.Contains(i.ItemId))
                 .Select(i => i.Name)
                 .DistinctNames();
         }

+ 5 - 2
MediaBrowser.Api/Music/AlbumsService.cs

@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Persistence;
 using ServiceStack;
 using System;
+using System.Collections.Generic;
 using System.Linq;
 
 namespace MediaBrowser.Api.Music
@@ -68,11 +69,13 @@ namespace MediaBrowser.Api.Music
         /// 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, BaseItem item2)
+        private int GetAlbumSimilarityScore(BaseItem item1, List<PersonInfo> item1People, List<PersonInfo> allPeople, BaseItem item2)
         {
-            var points = SimilarItemsHelper.GetSimiliarityScore(item1, item2);
+            var points = SimilarItemsHelper.GetSimiliarityScore(item1, item1People, allPeople, item2);
 
             var album1 = (MusicAlbum)item1;
             var album2 = (MusicAlbum)item2;

+ 1 - 1
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -632,7 +632,7 @@ namespace MediaBrowser.Api.Playback
             {
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
-                filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
+                filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(ih\\,{0})", maxHeightParam));
             }
 
             if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))

+ 20 - 15
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -313,16 +313,17 @@ namespace MediaBrowser.Api.Playback.Hls
             {
                 var segmentPath = GetSegmentPath(state, playlist, i);
 
-                double length;
-                if (SegmentLengths.TryGetValue(Path.GetFileName(segmentPath), out length))
-                {
-                    Logger.Debug("Found segment length of {0} for index {1}", length, i);
-                    startSeconds += length;
-                }
-                else
-                {
-                    startSeconds += state.SegmentLength;
-                }
+                //double length;
+                //if (SegmentLengths.TryGetValue(Path.GetFileName(segmentPath), out length))
+                //{
+                //    Logger.Debug("Found segment length of {0} for index {1}", length, i);
+                //    startSeconds += length;
+                //}
+                //else
+                //{
+                //    startSeconds += state.SegmentLength;
+                //}
+                startSeconds += state.SegmentLength;
             }
 
             var position = TimeSpan.FromSeconds(startSeconds).Ticks;
@@ -441,7 +442,7 @@ namespace MediaBrowser.Api.Playback.Hls
             CancellationToken cancellationToken)
         {
             // If all transcoding has completed, just return immediately
-            if (transcodingJob != null && transcodingJob.HasExited)
+            if (transcodingJob != null && transcodingJob.HasExited && File.Exists(segmentPath))
             {
                 return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
             }
@@ -463,7 +464,11 @@ namespace MediaBrowser.Api.Playback.Hls
                                 // If it appears in the playlist, it's done
                                 if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
                                 {
-                                    return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
+                                    if (File.Exists(segmentPath))
+                                    {
+                                        return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
+                                    }
+                                    break;
                                 }
                             }
                         }
@@ -564,11 +569,11 @@ namespace MediaBrowser.Api.Playback.Hls
 
             builder.AppendLine("#EXTM3U");
 
+            var isLiveStream = (state.RunTimeTicks ?? 0) == 0;
+
             var queryStringIndex = Request.RawUrl.IndexOf('?');
             var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);
 
-            var isLiveStream = (state.RunTimeTicks ?? 0) == 0;
-
             // Main stream
             var playlistUrl = isLiveStream ? "live.m3u8" : "main.m3u8";
             playlistUrl += queryString;
@@ -798,7 +803,7 @@ namespace MediaBrowser.Api.Playback.Hls
                 var audioTranscodeParams = new List<string>();
 
                 audioTranscodeParams.Add("-acodec " + codec);
-                
+
                 if (state.OutputAudioBitrate.HasValue)
                 {
                     audioTranscodeParams.Add("-ab " + state.OutputAudioBitrate.Value.ToString(UsCulture));

+ 3 - 4
MediaBrowser.Api/Reports/ReportsService.cs

@@ -779,7 +779,7 @@ namespace MediaBrowser.Api.Reports
 						.Select(p => p == null ? "-1" : p.Name)
 						.ToList();
 
-					if (!(names.Any(v => i.People.Select(p => p.Name).Contains(v, StringComparer.OrdinalIgnoreCase))))
+					if (!(names.Any(v => _libraryManager.GetPeople(i).Select(p => p.Name).Contains(v, StringComparer.OrdinalIgnoreCase))))
 					{
 						return false;
 					}
@@ -792,7 +792,7 @@ namespace MediaBrowser.Api.Reports
 
 					if (personTypes.Length == 0)
 					{
-						if (!(i.People.Any(p => string.Equals(p.Name, request.Person, StringComparison.OrdinalIgnoreCase))))
+                        if (!(_libraryManager.GetPeople(i).Any(p => string.Equals(p.Name, request.Person, StringComparison.OrdinalIgnoreCase))))
 						{
 							return false;
 						}
@@ -802,8 +802,7 @@ namespace MediaBrowser.Api.Reports
 						var types = personTypes;
 
 						var ok = new[] { i }.Any(item =>
-								item.People != null &&
-								item.People.Any(p =>
+                                _libraryManager.GetPeople(i).Any(p =>
 									p.Name.Equals(request.Person, StringComparison.OrdinalIgnoreCase) && (types.Contains(p.Type, StringComparer.OrdinalIgnoreCase) || types.Contains(p.Role, StringComparer.OrdinalIgnoreCase))));
 
 						if (!ok)

+ 1 - 1
MediaBrowser.Api/Reports/Stat/ReportStatBuilder.cs

@@ -107,7 +107,7 @@ namespace MediaBrowser.Api.Reports
 			foreach (var item in t)
 			{
 				this.GetGroups(result, ReportHelper.GetServerLocalizedString("Option" + item), topItem,
-						items.SelectMany(x => x.People)
+						items.SelectMany(x => _libraryManager.GetPeople(x))
 								.Where(n => n.Type == item)
 								.GroupBy(x => x.Name)
 								.OrderByDescending(x => x.Count())

+ 17 - 7
MediaBrowser.Api/SimilarItemsHelper.cs

@@ -68,7 +68,7 @@ namespace MediaBrowser.Api
         /// <param name="includeInSearch">The include in search.</param>
         /// <param name="getSimilarityScore">The get similarity score.</param>
         /// <returns>ItemsResult.</returns>
-        internal static ItemsResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, BaseItem, int> getSimilarityScore)
+        internal static ItemsResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, List<PersonInfo>, List<PersonInfo>, BaseItem, int> getSimilarityScore)
         {
             var user = !string.IsNullOrWhiteSpace(request.UserId) ? userManager.GetUserById(request.UserId) : null;
 
@@ -82,7 +82,7 @@ namespace MediaBrowser.Api
                                  ? libraryManager.RootFolder.GetRecursiveChildren(filter)
                                  : user.RootFolder.GetRecursiveChildren(user, filter);
 
-            var items = GetSimilaritems(item, inputItems, getSimilarityScore)
+            var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore)
                 .ToList();
 
             IEnumerable<BaseItem> returnItems = items;
@@ -106,15 +106,21 @@ namespace MediaBrowser.Api
         /// 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>
-        internal static IEnumerable<BaseItem> GetSimilaritems(BaseItem item, IEnumerable<BaseItem> inputItems, Func<BaseItem, BaseItem, int> getSimilarityScore)
+        internal 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, i)))
+            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);
@@ -146,9 +152,11 @@ namespace MediaBrowser.Api
         /// 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, BaseItem item2)
+        internal static int GetSimiliarityScore(BaseItem item1, List<PersonInfo> item1People, List<PersonInfo> allPeople, BaseItem item2)
         {
             var points = 0;
 
@@ -169,11 +177,13 @@ namespace MediaBrowser.Api
             // Find common studios
             points += item1.Studios.Where(i => item2.Studios.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 3);
 
-            var item2PeopleNames = item2.People.Select(i => i.Name)
+            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 += item1.People.Where(i => item2PeopleNames.ContainsKey(i.Name)).Sum(i =>
+            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))
                 {

+ 164 - 0
MediaBrowser.Api/Social/SharingService.cs

@@ -0,0 +1,164 @@
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Social;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Social;
+using ServiceStack;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api.Social
+{
+    [Route("/Social/Shares/{Id}", "GET", Summary = "Gets a share")]
+    [Authenticated]
+    public class GetSocialShareInfo : IReturn<SocialShareInfo>
+    {
+        [ApiMember(Name = "Id", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Id { get; set; }
+    }
+
+    [Route("/Social/Shares/Public/{Id}", "GET", Summary = "Gets a share")]
+    public class GetPublicSocialShareInfo : IReturn<SocialShareInfo>
+    {
+        [ApiMember(Name = "Id", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Id { get; set; }
+    }
+
+    [Route("/Social/Shares/Public/{Id}/Image", "GET", Summary = "Gets a share")]
+    public class GetShareImage
+    {
+        [ApiMember(Name = "Id", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Id { get; set; }
+    }
+
+    [Route("/Social/Shares", "POST", Summary = "Creates a share")]
+    [Authenticated]
+    public class CreateShare : IReturn<SocialShareInfo>
+    {
+        [ApiMember(Name = "ItemId", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+        public string ItemId { get; set; }
+
+        [ApiMember(Name = "UserId", Description = "The user id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+        public string UserId { get; set; }
+    }
+
+    [Route("/Social/Shares/{Id}", "DELETE", Summary = "Deletes a share")]
+    [Authenticated]
+    public class DeleteShare : IReturnVoid
+    {
+        [ApiMember(Name = "Id", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+        public string Id { get; set; }
+    }
+
+    [Route("/Social/Shares/Public/{Id}/Item", "GET", Summary = "Gets a share")]
+    public class GetSharedLibraryItem
+    {
+        [ApiMember(Name = "Id", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Id { get; set; }
+    }
+
+    public class SharingService : BaseApiService
+    {
+        private readonly ISharingManager _sharingManager;
+        private readonly ILibraryManager _libraryManager;
+        private readonly IDlnaManager _dlnaManager;
+        private readonly IDtoService _dtoService;
+
+        public SharingService(ISharingManager sharingManager, IDlnaManager dlnaManager, ILibraryManager libraryManager, IDtoService dtoService)
+        {
+            _sharingManager = sharingManager;
+            _dlnaManager = dlnaManager;
+            _libraryManager = libraryManager;
+            _dtoService = dtoService;
+        }
+
+        public object Get(GetSocialShareInfo request)
+        {
+            var info = _sharingManager.GetShareInfo(request.Id);
+
+            return ToOptimizedResult(info);
+        }
+
+        public object Get(GetSharedLibraryItem request)
+        {
+            var info = _sharingManager.GetShareInfo(request.Id);
+
+            if (info.ExpirationDate <= DateTime.UtcNow)
+            {
+                throw new ResourceNotFoundException();
+            }
+
+            var item = _libraryManager.GetItemById(info.ItemId);
+
+            var dto = _dtoService.GetBaseItemDto(item, new DtoOptions());
+
+            return ToOptimizedResult(dto);
+        }
+
+        public object Get(GetPublicSocialShareInfo request)
+        {
+            var info = _sharingManager.GetShareInfo(request.Id);
+
+            if (info.ExpirationDate <= DateTime.UtcNow)
+            {
+                throw new ResourceNotFoundException();
+            }
+
+            return ToOptimizedResult(info);
+        }
+
+        public async Task<object> Post(CreateShare request)
+        {
+            var info = await _sharingManager.CreateShare(request.ItemId, request.UserId).ConfigureAwait(false);
+
+            return ToOptimizedResult(info);
+        }
+
+        public void Delete(DeleteShare request)
+        {
+            var task = _sharingManager.DeleteShare(request.Id);
+            Task.WaitAll(task);
+        }
+
+        public object Get(GetShareImage request)
+        {
+            var share = _sharingManager.GetShareInfo(request.Id);
+
+            if (share == null)
+            {
+                throw new ResourceNotFoundException();
+            }
+            if (share.ExpirationDate <= DateTime.UtcNow)
+            {
+                throw new ResourceNotFoundException();
+            }
+
+            var item = _libraryManager.GetItemById(share.ItemId);
+
+            var image = item.GetImageInfo(ImageType.Primary, 0);
+
+            if (image != null)
+            {
+                return ToStaticFileResult(image.Path);
+            }
+
+            // Grab a dlna icon if nothing else is available
+            using (var response = _dlnaManager.GetIcon("logo240.jpg"))
+            {
+                using (var ms = new MemoryStream())
+                {
+                    response.Stream.CopyTo(ms);
+
+                    ms.Position = 0;
+                    var bytes = ms.ToArray();
+                    return ResultFactory.GetResult(bytes, "image/" + response.Format.ToString().ToLower());
+                }
+            }
+
+        }
+    }
+}

+ 3 - 4
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -990,7 +990,7 @@ namespace MediaBrowser.Api.UserLibrary
                         .Select(p => p == null ? "-1" : p.Name)
                         .ToList();
 
-                    if (!(names.Any(v => i.People.Select(p => p.Name).Contains(v, StringComparer.OrdinalIgnoreCase))))
+                    if (!(names.Any(v => libraryManager.GetPeople(i).Select(p => p.Name).Contains(v, StringComparer.OrdinalIgnoreCase))))
                     {
                         return false;
                     }
@@ -1003,7 +1003,7 @@ namespace MediaBrowser.Api.UserLibrary
 
                     if (personTypes.Length == 0)
                     {
-                        if (!(i.People.Any(p => string.Equals(p.Name, request.Person, StringComparison.OrdinalIgnoreCase))))
+                        if (!(libraryManager.GetPeople(i).Any(p => string.Equals(p.Name, request.Person, StringComparison.OrdinalIgnoreCase))))
                         {
                             return false;
                         }
@@ -1013,8 +1013,7 @@ namespace MediaBrowser.Api.UserLibrary
                         var types = personTypes;
 
                         var ok = new[] { i }.Any(item =>
-                                item.People != null &&
-                                item.People.Any(p =>
+                                libraryManager.GetPeople(item).Any(p =>
                                     p.Name.Equals(request.Person, StringComparison.OrdinalIgnoreCase) && (types.Contains(p.Type, StringComparer.OrdinalIgnoreCase) || types.Contains(p.Role, StringComparer.OrdinalIgnoreCase))));
 
                         if (!ok)

+ 6 - 9
MediaBrowser.Api/UserLibrary/PersonsService.cs

@@ -5,7 +5,6 @@ using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
 using ServiceStack;
-using System;
 using System.Collections.Generic;
 using System.Linq;
 
@@ -151,18 +150,16 @@ namespace MediaBrowser.Api.UserLibrary
         /// <param name="itemsList">The items list.</param>
         /// <param name="personTypes">The person types.</param>
         /// <returns>IEnumerable{PersonInfo}.</returns>
-        private IEnumerable<PersonInfo> GetAllPeople(IEnumerable<BaseItem> itemsList, string[] personTypes)
+        private IEnumerable<PersonInfo> GetAllPeople(IEnumerable<BaseItem> itemsList, IEnumerable<string> personTypes)
         {
-            var people = itemsList.SelectMany(i => i.People.OrderBy(p => p.SortOrder ?? int.MaxValue).ThenBy(p => p.Type));
+            var allIds = itemsList.Select(i => i.Id).ToList();
 
-            if (personTypes.Length > 0)
+            var allPeople = LibraryManager.GetPeople(new InternalPeopleQuery
             {
-                people = people.Where(p =>
-                            personTypes.Contains(p.Type ?? string.Empty, StringComparer.OrdinalIgnoreCase) ||
-                            personTypes.Contains(p.Role ?? string.Empty, StringComparer.OrdinalIgnoreCase));
-            }
+                PersonTypes = personTypes.ToList()
+            });
 
-            return people;
+            return allPeople.Where(i => allIds.Contains(i.ItemId)).OrderBy(p => p.SortOrder ?? int.MaxValue).ThenBy(p => p.Type);
         }
     }
 }

+ 7 - 0
MediaBrowser.Common.Implementations/Logging/NlogManager.cs

@@ -85,6 +85,13 @@ namespace MediaBrowser.Common.Implementations.Logging
                 {
                     rule.EnableLoggingForLevel(level);
                 }
+                foreach (var lev in rule.Levels.ToArray())
+                {
+                    if (lev < level)
+                    {
+                        rule.DisableLoggingForLevel(lev);
+                    }
+                }
             }
         }
 

+ 9 - 0
MediaBrowser.Controller/Entities/Audio/MusicArtist.cs

@@ -216,5 +216,14 @@ namespace MediaBrowser.Controller.Entities.Audio
                 return hasArtist != null && hasArtist.HasAnyArtist(Name);
             };
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 9 - 0
MediaBrowser.Controller/Entities/Audio/MusicGenre.cs

@@ -71,5 +71,14 @@ namespace MediaBrowser.Controller.Entities.Audio
         {
             return i => (i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase);
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 14 - 87
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -35,7 +35,6 @@ namespace MediaBrowser.Controller.Entities
         {
             Genres = new List<string>();
             Studios = new List<string>();
-            People = new List<PersonInfo>();
             ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
             LockedFields = new List<MetadataFields>();
             ImageInfos = new List<ItemImageInfo>();
@@ -413,15 +412,6 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        public bool ContainsPerson(string name)
-        {
-            if (string.IsNullOrWhiteSpace(name))
-            {
-                throw new ArgumentNullException("name");
-            }
-            return People.Any(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
-        }
-
         public string GetInternalMetadataPath()
         {
             var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath;
@@ -474,6 +464,8 @@ namespace MediaBrowser.Controller.Entities
             return sortable;
         }
 
+        public Guid ParentId { get; set; }
+
         /// <summary>
         /// Gets or sets the parent.
         /// </summary>
@@ -481,6 +473,12 @@ namespace MediaBrowser.Controller.Entities
         [IgnoreDataMember]
         public Folder Parent { get; set; }
 
+        public void SetParent(Folder parent)
+        {
+            Parent = parent;
+            ParentId = parent == null ? Guid.Empty : parent.Id;
+        }
+
         [IgnoreDataMember]
         public IEnumerable<Folder> Parents
         {
@@ -785,6 +783,12 @@ namespace MediaBrowser.Controller.Entities
             get { return IsFolder || Parent != null; }
         }
 
+        [IgnoreDataMember]
+        public virtual bool SupportsPeople
+        {
+            get { return true; }
+        }
+
         /// <summary>
         /// Refreshes owned items such as trailers, theme videos, special features, etc.
         /// Returns true or false indicating if changes were found.
@@ -1248,83 +1252,6 @@ namespace MediaBrowser.Controller.Entities
         /// <exception cref="System.ArgumentNullException"></exception>
         public void AddPerson(PersonInfo person)
         {
-            if (person == null)
-            {
-                throw new ArgumentNullException("person");
-            }
-
-            if (string.IsNullOrWhiteSpace(person.Name))
-            {
-                throw new ArgumentNullException();
-            }
-
-            // Normalize
-            if (string.Equals(person.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
-            {
-                person.Type = PersonType.GuestStar;
-            }
-            else if (string.Equals(person.Role, PersonType.Director, StringComparison.OrdinalIgnoreCase))
-            {
-                person.Type = PersonType.Director;
-            }
-            else if (string.Equals(person.Role, PersonType.Producer, StringComparison.OrdinalIgnoreCase))
-            {
-                person.Type = PersonType.Producer;
-            }
-            else if (string.Equals(person.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase))
-            {
-                person.Type = PersonType.Writer;
-            }
-
-            // If the type is GuestStar and there's already an Actor entry, then update it to avoid dupes
-            if (string.Equals(person.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
-            {
-                var existing = People.FirstOrDefault(p => p.Name.Equals(person.Name, StringComparison.OrdinalIgnoreCase) && p.Type.Equals(PersonType.Actor, StringComparison.OrdinalIgnoreCase));
-
-                if (existing != null)
-                {
-                    existing.Type = PersonType.GuestStar;
-                    existing.SortOrder = person.SortOrder ?? existing.SortOrder;
-                    return;
-                }
-            }
-
-            if (string.Equals(person.Type, PersonType.Actor, StringComparison.OrdinalIgnoreCase))
-            {
-                // If the actor already exists without a role and we have one, fill it in
-                var existing = People.FirstOrDefault(p => p.Name.Equals(person.Name, StringComparison.OrdinalIgnoreCase) && (p.Type.Equals(PersonType.Actor, StringComparison.OrdinalIgnoreCase) || p.Type.Equals(PersonType.GuestStar, StringComparison.OrdinalIgnoreCase)));
-                if (existing == null)
-                {
-                    // Wasn't there - add it
-                    People.Add(person);
-                }
-                else
-                {
-                    // Was there, if no role and we have one - fill it in
-                    if (string.IsNullOrWhiteSpace(existing.Role) && !string.IsNullOrWhiteSpace(person.Role))
-                    {
-                        existing.Role = person.Role;
-                    }
-
-                    existing.SortOrder = person.SortOrder ?? existing.SortOrder;
-                }
-            }
-            else
-            {
-                var existing = People.FirstOrDefault(p =>
-                            string.Equals(p.Name, person.Name, StringComparison.OrdinalIgnoreCase) &&
-                            string.Equals(p.Type, person.Type, StringComparison.OrdinalIgnoreCase));
-
-                // Check for dupes based on the combination of Name and Type
-                if (existing == null)
-                {
-                    People.Add(person);
-                }
-                else
-                {
-                    existing.SortOrder = person.SortOrder ?? existing.SortOrder;
-                }
-            }
         }
 
         /// <summary>

+ 11 - 0
MediaBrowser.Controller/Entities/BasePluginFolder.cs

@@ -1,4 +1,6 @@
 
+using System.Runtime.Serialization;
+
 namespace MediaBrowser.Controller.Entities
 {
     /// <summary>
@@ -21,5 +23,14 @@ namespace MediaBrowser.Controller.Entities
         {
             return true;
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 9 - 0
MediaBrowser.Controller/Entities/CollectionFolder.cs

@@ -194,5 +194,14 @@ namespace MediaBrowser.Controller.Entities
                 .Where(i => i.Path != null && PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase))
                 .SelectMany(c => c.Children);
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 4 - 4
MediaBrowser.Controller/Entities/Folder.cs

@@ -134,7 +134,7 @@ namespace MediaBrowser.Controller.Entities
         /// <exception cref="System.InvalidOperationException">Unable to add  + item.Name</exception>
         public async Task AddChild(BaseItem item, CancellationToken cancellationToken)
         {
-            item.Parent = this;
+            item.SetParent(this);
 
             if (item.Id == Guid.Empty)
             {
@@ -230,7 +230,7 @@ namespace MediaBrowser.Controller.Entities
         {
             RemoveChildrenInternal(new[] { item });
 
-            item.Parent = null;
+            item.SetParent(null);
 
             return ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken);
         }
@@ -783,11 +783,11 @@ namespace MediaBrowser.Controller.Entities
                     return LibraryManager.GetOrAddByReferenceItem(item);
                 }
 
-                item.Parent = this;
+                item.SetParent(this);
             }
             else
             {
-                child.Parent = this;
+                child.SetParent(this);
                 LibraryManager.RegisterItem(child);
                 item = child;
             }

+ 9 - 0
MediaBrowser.Controller/Entities/GameGenre.cs

@@ -62,5 +62,14 @@ namespace MediaBrowser.Controller.Entities
         {
             return i => (i is Game) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase);
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 9 - 0
MediaBrowser.Controller/Entities/GameSystem.cs

@@ -58,5 +58,14 @@ namespace MediaBrowser.Controller.Entities
 
             return id;
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 9 - 0
MediaBrowser.Controller/Entities/Genre.cs

@@ -66,5 +66,14 @@ namespace MediaBrowser.Controller.Entities
         {
             return i => !(i is Game) && !(i is IHasMusicGenres) && i.Genres.Contains(Name, StringComparer.OrdinalIgnoreCase);
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 6 - 0
MediaBrowser.Controller/Entities/IHasMetadata.cs

@@ -59,5 +59,11 @@ namespace MediaBrowser.Controller.Entities
         /// Afters the metadata refresh.
         /// </summary>
         void AfterMetadataRefresh();
+
+        /// <summary>
+        /// Gets a value indicating whether [supports people].
+        /// </summary>
+        /// <value><c>true</c> if [supports people]; otherwise, <c>false</c>.</value>
+        bool SupportsPeople { get; }
     }
 }

+ 1 - 1
MediaBrowser.Controller/Entities/IItemByName.cs

@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Entities
     /// <summary>
     /// Marker interface
     /// </summary>
-    public interface IItemByName
+    public interface IItemByName : IHasMetadata
     {
         /// <summary>
         /// Gets the tagged items.

+ 21 - 0
MediaBrowser.Controller/Entities/InternalPeopleQuery.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Entities
+{
+    public class InternalPeopleQuery
+    {
+        public Guid ItemId { get; set; }
+        public List<string> PersonTypes { get; set; }
+        public List<string> ExcludePersonTypes { get; set; }
+        public int? MaxListOrder { get; set; }
+        public Guid AppearsInItemId { get; set; }
+        public string NameContains { get; set; }
+
+        public InternalPeopleQuery()
+        {
+            PersonTypes = new List<string>();
+            ExcludePersonTypes = new List<string>();
+        }
+    }
+}

+ 100 - 0
MediaBrowser.Controller/Entities/PeopleHelper.cs

@@ -0,0 +1,100 @@
+using MediaBrowser.Model.Entities;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MediaBrowser.Controller.Entities
+{
+    public static class PeopleHelper
+    {
+        public static void AddPerson(List<PersonInfo> people, PersonInfo person)
+        {
+            if (person == null)
+            {
+                throw new ArgumentNullException("person");
+            }
+
+            if (string.IsNullOrWhiteSpace(person.Name))
+            {
+                throw new ArgumentNullException();
+            }
+
+            // Normalize
+            if (string.Equals(person.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
+            {
+                person.Type = PersonType.GuestStar;
+            }
+            else if (string.Equals(person.Role, PersonType.Director, StringComparison.OrdinalIgnoreCase))
+            {
+                person.Type = PersonType.Director;
+            }
+            else if (string.Equals(person.Role, PersonType.Producer, StringComparison.OrdinalIgnoreCase))
+            {
+                person.Type = PersonType.Producer;
+            }
+            else if (string.Equals(person.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase))
+            {
+                person.Type = PersonType.Writer;
+            }
+
+            // If the type is GuestStar and there's already an Actor entry, then update it to avoid dupes
+            if (string.Equals(person.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
+            {
+                var existing = people.FirstOrDefault(p => p.Name.Equals(person.Name, StringComparison.OrdinalIgnoreCase) && p.Type.Equals(PersonType.Actor, StringComparison.OrdinalIgnoreCase));
+
+                if (existing != null)
+                {
+                    existing.Type = PersonType.GuestStar;
+                    existing.SortOrder = person.SortOrder ?? existing.SortOrder;
+                    return;
+                }
+            }
+
+            if (string.Equals(person.Type, PersonType.Actor, StringComparison.OrdinalIgnoreCase))
+            {
+                // If the actor already exists without a role and we have one, fill it in
+                var existing = people.FirstOrDefault(p => p.Name.Equals(person.Name, StringComparison.OrdinalIgnoreCase) && (p.Type.Equals(PersonType.Actor, StringComparison.OrdinalIgnoreCase) || p.Type.Equals(PersonType.GuestStar, StringComparison.OrdinalIgnoreCase)));
+                if (existing == null)
+                {
+                    // Wasn't there - add it
+                    people.Add(person);
+                }
+                else
+                {
+                    // Was there, if no role and we have one - fill it in
+                    if (string.IsNullOrWhiteSpace(existing.Role) && !string.IsNullOrWhiteSpace(person.Role))
+                    {
+                        existing.Role = person.Role;
+                    }
+
+                    existing.SortOrder = person.SortOrder ?? existing.SortOrder;
+                }
+            }
+            else
+            {
+                var existing = people.FirstOrDefault(p =>
+                            string.Equals(p.Name, person.Name, StringComparison.OrdinalIgnoreCase) &&
+                            string.Equals(p.Type, person.Type, StringComparison.OrdinalIgnoreCase));
+
+                // Check for dupes based on the combination of Name and Type
+                if (existing == null)
+                {
+                    people.Add(person);
+                }
+                else
+                {
+                    existing.SortOrder = person.SortOrder ?? existing.SortOrder;
+                }
+            }
+        }
+
+        public static bool ContainsPerson(List<PersonInfo> people, string name)
+        {
+            if (string.IsNullOrWhiteSpace(name))
+            {
+                throw new ArgumentNullException("name");
+            }
+            return people.Any(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
+        }
+    }
+}

+ 18 - 2
MediaBrowser.Controller/Entities/Person.cs

@@ -70,13 +70,27 @@ namespace MediaBrowser.Controller.Entities
 
         public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
         {
-            return inputItems.Where(GetItemFilter());
+            var itemsWithPerson = LibraryManager.GetItemIds(new InternalItemsQuery
+            {
+                Person = Name
+            });
+
+            return inputItems.Where(i => itemsWithPerson.Contains(i.Id));
         }
 
 
         public Func<BaseItem, bool> GetItemFilter()
         {
-            return i => i.People.Any(p => string.Equals(p.Name, Name, StringComparison.OrdinalIgnoreCase));
+            return i => LibraryManager.GetPeople(i).Any(p => string.Equals(p.Name, Name, StringComparison.OrdinalIgnoreCase));
+        }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
         }
     }
 
@@ -85,6 +99,8 @@ namespace MediaBrowser.Controller.Entities
     /// </summary>
     public class PersonInfo
     {
+        public Guid ItemId { get; set; }
+
         /// <summary>
         /// Gets or sets the name.
         /// </summary>

+ 9 - 0
MediaBrowser.Controller/Entities/Studio.cs

@@ -72,5 +72,14 @@ namespace MediaBrowser.Controller.Entities
         {
             return i => i.Studios.Contains(Name, StringComparer.OrdinalIgnoreCase);
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 9 - 0
MediaBrowser.Controller/Entities/User.cs

@@ -295,5 +295,14 @@ namespace MediaBrowser.Controller.Entities
 
             return config.GroupedFolders.Select(i => new Guid(i)).Contains(id);
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 11 - 1
MediaBrowser.Controller/Entities/UserView.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Playlists;
+using System.Runtime.Serialization;
+using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Controller.TV;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
@@ -93,5 +94,14 @@ namespace MediaBrowser.Controller.Entities
 
             return standaloneTypes.Contains(collectionFolder.CollectionType ?? string.Empty);
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 3 - 5
MediaBrowser.Controller/Entities/UserViewBuilder.cs

@@ -1699,8 +1699,7 @@ namespace MediaBrowser.Controller.Entities
                     .Select(i => i == null ? "-1" : i.Name)
                     .ToList();
 
-                if (!(names.Any(
-                        v => item.People.Select(i => i.Name).Contains(v, StringComparer.OrdinalIgnoreCase))))
+                if (!(names.Any(v => libraryManager.GetPeople(item).Select(i => i.Name).Contains(v, StringComparer.OrdinalIgnoreCase))))
                 {
                     return false;
                 }
@@ -1713,7 +1712,7 @@ namespace MediaBrowser.Controller.Entities
 
                 if (personTypes.Length == 0)
                 {
-                    if (!(item.People.Any(p => string.Equals(p.Name, query.Person, StringComparison.OrdinalIgnoreCase))))
+                    if (!(libraryManager.GetPeople(item).Any(p => string.Equals(p.Name, query.Person, StringComparison.OrdinalIgnoreCase))))
                     {
                         return false;
                     }
@@ -1723,8 +1722,7 @@ namespace MediaBrowser.Controller.Entities
                     var types = personTypes;
 
                     var ok = new[] { item }.Any(i =>
-                            i.People != null &&
-                            i.People.Any(p =>
+                            libraryManager.GetPeople(i).Any(p =>
                                 string.Equals(p.Name, query.Person, StringComparison.OrdinalIgnoreCase) && (types.Contains(p.Type ?? string.Empty, StringComparer.OrdinalIgnoreCase) || types.Contains(p.Role ?? string.Empty, StringComparer.OrdinalIgnoreCase))));
 
                     if (!ok)

+ 9 - 0
MediaBrowser.Controller/Entities/Year.cs

@@ -88,5 +88,14 @@ namespace MediaBrowser.Controller.Entities
             var val = GetYearValue();
             return i => i.ProductionYear.HasValue && val.HasValue && i.ProductionYear.Value == val.Value;
         }
+
+        [IgnoreDataMember]
+        public override bool SupportsPeople
+        {
+            get
+            {
+                return false;
+            }
+        }
     }
 }

+ 49 - 0
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -412,5 +412,54 @@ namespace MediaBrowser.Controller.Library
         /// <param name="item">The item.</param>
         /// <returns>IEnumerable&lt;Folder&gt;.</returns>
         IEnumerable<Folder> GetCollectionFolders(BaseItem item);
+
+        /// <summary>
+        /// Gets the people.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns>List&lt;PersonInfo&gt;.</returns>
+        List<PersonInfo> GetPeople(BaseItem item);
+
+        /// <summary>
+        /// Gets the people.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>List&lt;PersonInfo&gt;.</returns>
+        List<PersonInfo> GetPeople(InternalPeopleQuery query);
+        
+        /// <summary>
+        /// Gets the people items.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>List&lt;Person&gt;.</returns>
+        List<Person> GetPeopleItems(InternalPeopleQuery query);
+        
+        /// <summary>
+        /// Gets all people names.
+        /// </summary>
+        /// <returns>List&lt;System.String&gt;.</returns>
+        List<PersonInfo> GetAllPeople();
+
+        /// <summary>
+        /// Updates the people.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="people">The people.</param>
+        /// <returns>Task.</returns>
+        Task UpdatePeople(BaseItem item, List<PersonInfo> people);
+
+        /// <summary>
+        /// Gets the item ids.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>List&lt;Guid&gt;.</returns>
+        List<Guid> GetItemIds(InternalItemsQuery query);
+
+        /// <summary>
+        /// Gets the people names.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>List&lt;System.String&gt;.</returns>
+        List<string> GetPeopleNames(InternalPeopleQuery query);
     }
 }

+ 5 - 0
MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs

@@ -118,6 +118,11 @@ namespace MediaBrowser.Controller.LiveTv
             return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
         }
 
+        public override bool CanDelete()
+        {
+            return true;
+        }
+
         public override bool IsAuthorizedToDelete(User user)
         {
             return user.Policy.EnableLiveTvManagement;

+ 5 - 0
MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs

@@ -116,6 +116,11 @@ namespace MediaBrowser.Controller.LiveTv
             return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
         }
 
+        public override bool CanDelete()
+        {
+            return true;
+        }
+
         public override bool IsAuthorizedToDelete(User user)
         {
             return user.Policy.EnableLiveTvManagement;

+ 3 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -166,6 +166,7 @@
     <Compile Include="Entities\ImageSourceInfo.cs" />
     <Compile Include="Entities\IMetadataContainer.cs" />
     <Compile Include="Entities\InternalItemsQuery.cs" />
+    <Compile Include="Entities\InternalPeopleQuery.cs" />
     <Compile Include="Entities\ISupportsBoxSetGrouping.cs" />
     <Compile Include="Entities\ISupportsPlaceHolders.cs" />
     <Compile Include="Entities\ItemImageInfo.cs" />
@@ -173,6 +174,7 @@
     <Compile Include="Entities\LinkedChild.cs" />
     <Compile Include="Entities\MusicVideo.cs" />
     <Compile Include="Entities\IHasAwards.cs" />
+    <Compile Include="Entities\PeopleHelper.cs" />
     <Compile Include="Entities\Photo.cs" />
     <Compile Include="Entities\PhotoAlbum.cs" />
     <Compile Include="Entities\Share.cs" />
@@ -328,6 +330,7 @@
     <Compile Include="Security\IAuthenticationRepository.cs" />
     <Compile Include="Security\IEncryptionManager.cs" />
     <Compile Include="Session\AuthenticationRequest.cs" />
+    <Compile Include="Social\ISharingManager.cs" />
     <Compile Include="Subtitles\ISubtitleManager.cs" />
     <Compile Include="Subtitles\ISubtitleProvider.cs" />
     <Compile Include="Providers\ItemIdentifier.cs" />

+ 22 - 0
MediaBrowser.Controller/Persistence/IItemRepository.cs

@@ -147,6 +147,28 @@ namespace MediaBrowser.Controller.Persistence
         /// <param name="query">The query.</param>
         /// <returns>List&lt;Guid&gt;.</returns>
         List<Guid> GetItemIdsList(InternalItemsQuery query);
+
+        /// <summary>
+        /// Gets the people.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>List&lt;PersonInfo&gt;.</returns>
+        List<PersonInfo> GetPeople(InternalPeopleQuery query);
+
+        /// <summary>
+        /// Updates the people.
+        /// </summary>
+        /// <param name="itemId">The item identifier.</param>
+        /// <param name="people">The people.</param>
+        /// <returns>Task.</returns>
+        Task UpdatePeople(Guid itemId, List<PersonInfo> people);
+
+        /// <summary>
+        /// Gets the people names.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>List&lt;System.String&gt;.</returns>
+        List<string> GetPeopleNames(InternalPeopleQuery query);
     }
 }
 

+ 14 - 12
MediaBrowser.Controller/Providers/BaseItemXmlParser.cs

@@ -40,7 +40,7 @@ namespace MediaBrowser.Controller.Providers
         /// <param name="metadataFile">The metadata file.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <exception cref="System.ArgumentNullException"></exception>
-        public void Fetch(T item, string metadataFile, CancellationToken cancellationToken)
+        public void Fetch(MetadataResult<T> item, string metadataFile, CancellationToken cancellationToken)
         {
             if (item == null)
             {
@@ -72,7 +72,7 @@ namespace MediaBrowser.Controller.Providers
         /// <param name="settings">The settings.</param>
         /// <param name="encoding">The encoding.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
-        private void Fetch(T item, string metadataFile, XmlReaderSettings settings, Encoding encoding, CancellationToken cancellationToken)
+        private void Fetch(MetadataResult<T> item, string metadataFile, XmlReaderSettings settings, Encoding encoding, CancellationToken cancellationToken)
         {
             using (var streamReader = new StreamReader(metadataFile, encoding))
             {
@@ -101,9 +101,11 @@ namespace MediaBrowser.Controller.Providers
         /// Fetches metadata from one Xml Element
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <param name="item">The item.</param>
-        protected virtual void FetchDataFromXmlNode(XmlReader reader, T item)
+        /// <param name="itemResult">The item result.</param>
+        protected virtual void FetchDataFromXmlNode(XmlReader reader, MetadataResult<T> itemResult)
         {
+            var item = itemResult.Item;
+
             switch (reader.Name)
             {
                 // DateCreated
@@ -490,7 +492,7 @@ namespace MediaBrowser.Controller.Providers
                             {
                                 continue;
                             }
-                            item.AddPerson(p);
+                            PeopleHelper.AddPerson(itemResult.People, p);
                         }
                         break;
                     }
@@ -502,7 +504,7 @@ namespace MediaBrowser.Controller.Providers
                             {
                                 continue;
                             }
-                            item.AddPerson(p);
+                            PeopleHelper.AddPerson(itemResult.People, p);
                         }
                         break;
                     }
@@ -516,7 +518,7 @@ namespace MediaBrowser.Controller.Providers
                         {
                             // This is one of the mis-named "Actors" full nodes created by MB2
                             // Create a reader and pass it to the persons node processor
-                            FetchDataFromPersonsNode(new XmlTextReader(new StringReader("<Persons>" + actors + "</Persons>")), item);
+                            FetchDataFromPersonsNode(new XmlTextReader(new StringReader("<Persons>" + actors + "</Persons>")), itemResult);
                         }
                         else
                         {
@@ -527,7 +529,7 @@ namespace MediaBrowser.Controller.Providers
                                 {
                                     continue;
                                 }
-                                item.AddPerson(p);
+                                PeopleHelper.AddPerson(itemResult.People, p);
                             }
                         }
                         break;
@@ -541,7 +543,7 @@ namespace MediaBrowser.Controller.Providers
                             {
                                 continue;
                             }
-                            item.AddPerson(p);
+                            PeopleHelper.AddPerson(itemResult.People, p);
                         }
                         break;
                     }
@@ -833,7 +835,7 @@ namespace MediaBrowser.Controller.Providers
                     {
                         using (var subtree = reader.ReadSubtree())
                         {
-                            FetchDataFromPersonsNode(subtree, item);
+                            FetchDataFromPersonsNode(subtree, itemResult);
                         }
                         break;
                     }
@@ -1133,7 +1135,7 @@ namespace MediaBrowser.Controller.Providers
         /// </summary>
         /// <param name="reader">The reader.</param>
         /// <param name="item">The item.</param>
-        private void FetchDataFromPersonsNode(XmlReader reader, T item)
+        private void FetchDataFromPersonsNode(XmlReader reader, MetadataResult<T> item)
         {
             reader.MoveToContent();
 
@@ -1154,7 +1156,7 @@ namespace MediaBrowser.Controller.Providers
                                         {
                                             continue;
                                         }
-                                        item.AddPerson(person);
+                                        PeopleHelper.AddPerson(item.People, person);
                                     }
                                 }
                                 break;

+ 2 - 8
MediaBrowser.Controller/Providers/LocalMetadataResult.cs

@@ -1,23 +1,17 @@
-using System.Collections.Generic;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
+using System.Collections.Generic;
 
 namespace MediaBrowser.Controller.Providers
 {
-    public class LocalMetadataResult<T>
+    public class LocalMetadataResult<T> : MetadataResult<T>
         where T : IHasMetadata
     {
-        public bool HasMetadata { get; set; }
-        public T Item { get; set; }
-        
         public List<LocalImageInfo> Images { get; set; }
-        public List<ChapterInfo> Chapters { get; set; }
         public List<UserItemData> UserDataLIst { get; set; }
 
         public LocalMetadataResult()
         {
             Images = new List<LocalImageInfo>();
-            Chapters = new List<ChapterInfo>();
             UserDataLIst = new List<UserItemData>();
         }
     }

+ 10 - 0
MediaBrowser.Controller/Providers/MetadataResult.cs

@@ -1,8 +1,18 @@
+using MediaBrowser.Controller.Entities;
+using System.Collections.Generic;
+
 namespace MediaBrowser.Controller.Providers
 {
     public class MetadataResult<T>
     {
+        public List<PersonInfo> People { get; set; }
+
         public bool HasMetadata { get; set; }
         public T Item { get; set; }
+
+        public MetadataResult()
+        {
+            People = new List<PersonInfo>();
+        }
     }
 }

+ 28 - 0
MediaBrowser.Controller/Social/ISharingManager.cs

@@ -0,0 +1,28 @@
+using MediaBrowser.Model.Social;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Social
+{
+    public interface ISharingManager
+    {
+        /// <summary>
+        /// Creates the share.
+        /// </summary>
+        /// <param name="itemId">The item identifier.</param>
+        /// <param name="userId">The user identifier.</param>
+        /// <returns>Task&lt;SocialShareInfo&gt;.</returns>
+        Task<SocialShareInfo> CreateShare(string itemId, string userId);
+        /// <summary>
+        /// Gets the share information.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <returns>SocialShareInfo.</returns>
+        SocialShareInfo GetShareInfo(string id);
+        /// <summary>
+        /// Deletes the share.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <returns>Task.</returns>
+        Task DeleteShare(string id);
+    }
+}

+ 14 - 0
MediaBrowser.Controller/Sync/IServerSyncProvider.cs

@@ -49,4 +49,18 @@ namespace MediaBrowser.Controller.Sync
         /// <returns>Task&lt;QueryResult&lt;FileMetadata&gt;&gt;.</returns>
         Task<QueryResult<FileMetadata>> GetFiles(FileQuery query, SyncTarget target, CancellationToken cancellationToken);
     }
+
+    public interface ISupportsDirectCopy
+    {
+        /// <summary>
+        /// Sends the file.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="pathParts">The path parts.</param>
+        /// <param name="target">The target.</param>
+        /// <param name="progress">The progress.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task&lt;SyncedFileInfo&gt;.</returns>
+        Task<SyncedFileInfo> SendFile(string path, string[] pathParts, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken);
+    }
 }

+ 17 - 39
MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs

@@ -58,7 +58,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
             _profile = profile;
             _config = config;
 
-            _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger);
+            _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager);
         }
 
         protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
@@ -410,18 +410,11 @@ namespace MediaBrowser.Dlna.ContentDirectory
             {
                 if (stubType.Value == StubType.People)
                 {
-                    var items = item.People.Select(i =>
+                    var items = _libraryManager.GetPeopleItems(new InternalPeopleQuery
                     {
-                        try
-                        {
-                            return _libraryManager.GetPerson(i.Name);
-                        }
-                        catch
-                        {
-                            return null;
-                        }
+                        ItemId = item.Id
 
-                    }).Where(i => i != null).ToArray();
+                    }).ToArray();
 
                     var result = new QueryResult<ServerItem>
                     {
@@ -443,7 +436,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
                 var person = item as Person;
                 if (person != null)
                 {
-                    return await GetItemsFromPerson(person, user, startIndex, limit).ConfigureAwait(false);
+                    return GetItemsFromPerson(person, user, startIndex, limit);
                 }
 
                 return ApplyPaging(new QueryResult<ServerItem>(), startIndex, limit);
@@ -486,38 +479,19 @@ namespace MediaBrowser.Dlna.ContentDirectory
             };
         }
 
-        private async Task<QueryResult<ServerItem>> GetItemsFromPerson(Person person, User user, int? startIndex, int? limit)
+        private QueryResult<ServerItem> GetItemsFromPerson(Person person, User user, int? startIndex, int? limit)
         {
-            var items = user.RootFolder.GetRecursiveChildren(user, i => i is Movie || i is Series && i.ContainsPerson(person.Name))
-                .ToList();
-
-            var trailerResult = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery
+            var itemsWithPerson = _libraryManager.GetItems(new InternalItemsQuery
             {
-                ContentTypes = new[] { ChannelMediaContentType.MovieExtra },
-                ExtraTypes = new[] { ExtraType.Trailer },
-                UserId = user.Id.ToString("N")
+                Person = person.Name
 
-            }, CancellationToken.None).ConfigureAwait(false);
+            }).Items;
 
-            var currentIds = items.Select(i => i.GetProviderId(MetadataProviders.Imdb))
+            var items = itemsWithPerson
+                .Where(i => i is Movie || i is Series || i is IChannelItem)
+                .Where(i => i.IsVisibleStandalone(user))
                 .ToList();
 
-            var trailersToAdd = trailerResult.Items
-                .Where(i => i.ContainsPerson(person.Name))
-                .Where(i =>
-                {
-                    // Try to filter out dupes using imdb id
-                    var imdb = i.GetProviderId(MetadataProviders.Imdb);
-                    if (!string.IsNullOrWhiteSpace(imdb) &&
-                        currentIds.Contains(imdb, StringComparer.OrdinalIgnoreCase))
-                    {
-                        return false;
-                    }
-                    return true;
-                });
-
-            items.AddRange(trailersToAdd);
-
             items = _libraryManager.Sort(items, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending)
                 .Skip(startIndex ?? 0)
                 .Take(limit ?? int.MaxValue)
@@ -569,7 +543,11 @@ namespace MediaBrowser.Dlna.ContentDirectory
 
         private bool EnablePeopleDisplay(BaseItem item)
         {
-            if (item.People.Count > 0)
+            if (_libraryManager.GetPeopleNames(new InternalPeopleQuery
+            {
+                ItemId = item.Id
+
+            }).Count > 0)
             {
                 return item is Movie;
             }

+ 6 - 2
MediaBrowser.Dlna/Didl/DidlBuilder.cs

@@ -40,8 +40,9 @@ namespace MediaBrowser.Dlna.Didl
         private readonly ILocalizationManager _localization;
         private readonly IMediaSourceManager _mediaSourceManager;
         private readonly ILogger _logger;
+        private readonly ILibraryManager _libraryManager;
 
-        public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger)
+        public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager)
         {
             _profile = profile;
             _imageProcessor = imageProcessor;
@@ -50,6 +51,7 @@ namespace MediaBrowser.Dlna.Didl
             _localization = localization;
             _mediaSourceManager = mediaSourceManager;
             _logger = logger;
+            _libraryManager = libraryManager;
             _accessToken = accessToken;
             _user = user;
         }
@@ -654,7 +656,9 @@ namespace MediaBrowser.Dlna.Didl
         {
             var types = new[] { PersonType.Director, PersonType.Writer, PersonType.Producer, PersonType.Composer, "Creator" };
 
-            foreach (var actor in item.People)
+            var people = _libraryManager.GetPeople(item);
+
+            foreach (var actor in people)
             {
                 var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
                     ?? PersonType.Actor;

+ 1 - 0
MediaBrowser.Dlna/DlnaManager.cs

@@ -525,6 +525,7 @@ namespace MediaBrowser.Dlna
                 new Xbox360Profile(),
                 new XboxOneProfile(),
                 new SonyPs3Profile(),
+                new SonyPs4Profile(),
                 new SonyBravia2010Profile(),
                 new SonyBravia2011Profile(),
                 new SonyBravia2012Profile(),

+ 4 - 0
MediaBrowser.Dlna/MediaBrowser.Dlna.csproj

@@ -82,6 +82,7 @@
     <Compile Include="Profiles\DirectTvProfile.cs" />
     <Compile Include="Profiles\DishHopperJoeyProfile.cs" />
     <Compile Include="Profiles\PopcornHourProfile.cs" />
+    <Compile Include="Profiles\SonyPs4Profile.cs" />
     <Compile Include="Profiles\VlcProfile.cs" />
     <Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
     <Compile Include="Ssdp\Extensions.cs" />
@@ -210,6 +211,9 @@
     <EmbeddedResource Include="Profiles\Xml\BubbleUPnp.xml" />
     <EmbeddedResource Include="Profiles\Xml\Vlc.xml" />
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Profiles\Xml\Sony PlayStation 4.xml" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

+ 1 - 1
MediaBrowser.Dlna/PlayTo/PlayToController.cs

@@ -478,7 +478,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
             playlistItem.StreamUrl = playlistItem.StreamInfo.ToDlnaUrl(_serverAddress, _accessToken);
 
-            var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger)
+            var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager)
                 .GetItemDidl(item, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
 
             playlistItem.Didl = itemXml;

+ 17 - 1
MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs

@@ -54,7 +54,7 @@ namespace MediaBrowser.Dlna.Profiles
                 {
                     Container = "ts",
                     VideoCodec = "h264",
-                    AudioCodec = "aac",
+                    AudioCodec = "ac3",
                     Type = DlnaProfileType.Video,
                     EnableMpegtsM2TsMode = true
                 },
@@ -333,6 +333,22 @@ namespace MediaBrowser.Dlna.Profiles
                             Value = "he-aac"
                         }
                     }
+                },
+
+                new CodecProfile
+                {
+                    Type = CodecType.VideoAudio,
+                    Codec = "mp3,mp2",
+
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.AudioChannels,
+                            Value = "2"
+                        }
+                    }
                 }
             };
         }

+ 20 - 4
MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs

@@ -51,7 +51,7 @@ namespace MediaBrowser.Dlna.Profiles
                 {
                     Container = "ts",
                     VideoCodec = "h264",
-                    AudioCodec = "aac",
+                    AudioCodec = "ac3",
                     Type = DlnaProfileType.Video,
                     EnableMpegtsM2TsMode = true
                 },
@@ -75,21 +75,21 @@ namespace MediaBrowser.Dlna.Profiles
                 {
                     Container = "ts",
                     VideoCodec = "mpeg2video",
-                    AudioCodec = "mp3,mp2",
+                    AudioCodec = "mp3",
                     Type = DlnaProfileType.Video
                 },
                 new DirectPlayProfile
                 {
                     Container = "mp4",
                     VideoCodec = "h264,mpeg4",
-                    AudioCodec = "ac3,aac,mp3,mp2",
+                    AudioCodec = "ac3,aac,mp3",
                     Type = DlnaProfileType.Video
                 },
                 new DirectPlayProfile
                 {
                     Container = "mpeg",
                     VideoCodec = "mpeg2video,mpeg1video",
-                    AudioCodec = "mp3,mp2",
+                    AudioCodec = "mp3",
                     Type = DlnaProfileType.Video
                 },
                 new DirectPlayProfile
@@ -350,6 +350,22 @@ namespace MediaBrowser.Dlna.Profiles
                             Value = "he-aac"
                         }
                     }
+                },
+
+                new CodecProfile
+                {
+                    Type = CodecType.VideoAudio,
+                    Codec = "mp3,mp2",
+
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.AudioChannels,
+                            Value = "2"
+                        }
+                    }
                 }
             };
         }

+ 17 - 1
MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs

@@ -51,7 +51,7 @@ namespace MediaBrowser.Dlna.Profiles
                 {
                     Container = "ts",
                     VideoCodec = "h264",
-                    AudioCodec = "aac",
+                    AudioCodec = "ac3",
                     Type = DlnaProfileType.Video,
                     EnableMpegtsM2TsMode = true
                 },
@@ -268,6 +268,22 @@ namespace MediaBrowser.Dlna.Profiles
                             Value = "6"
                         }
                     }
+                },
+
+                new CodecProfile
+                {
+                    Type = CodecType.VideoAudio,
+                    Codec = "mp3,mp2",
+
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.AudioChannels,
+                            Value = "2"
+                        }
+                    }
                 }
             };
         }

+ 17 - 1
MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs

@@ -50,7 +50,7 @@ namespace MediaBrowser.Dlna.Profiles
                 {
                     Container = "ts",
                     VideoCodec = "h264",
-                    AudioCodec = "aac",
+                    AudioCodec = "ac3",
                     Type = DlnaProfileType.Video,
                     EnableMpegtsM2TsMode = true
                 },
@@ -286,6 +286,22 @@ namespace MediaBrowser.Dlna.Profiles
                             Value = "30"
                         }
                     }
+                },
+
+                new CodecProfile
+                {
+                    Type = CodecType.VideoAudio,
+                    Codec = "mp3,mp2",
+
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.AudioChannels,
+                            Value = "2"
+                        }
+                    }
                 }
             };
         }

+ 260 - 0
MediaBrowser.Dlna/Profiles/SonyPs4Profile.cs

@@ -0,0 +1,260 @@
+using MediaBrowser.Model.Dlna;
+using System.Xml.Serialization;
+
+namespace MediaBrowser.Dlna.Profiles
+{
+    [XmlRoot("Profile")]
+    public class SonyPs4Profile : DefaultProfile
+    {
+        public SonyPs4Profile()
+        {
+            Name = "Sony PlayStation 4";
+
+            Identification = new DeviceIdentification
+            {
+                FriendlyName = "PLAYSTATION 4",
+
+                Headers = new[]
+                {
+                    new HttpHeaderInfo
+                    {
+                        Name = "User-Agent",
+                        Value = @"PLAYSTATION 4",
+                        Match = HeaderMatchType.Substring
+                    },
+
+                    new HttpHeaderInfo
+                    {
+                        Name = "X-AV-Client-Info",
+                        Value = @"PLAYSTATION 4",
+                        Match = HeaderMatchType.Substring
+                    }
+                }
+            };
+
+            AlbumArtPn = "JPEG_TN";
+
+            SonyAggregationFlags = "10";
+            XDlnaDoc = "DMS-1.50";
+            EnableSingleAlbumArtLimit = true;
+
+            DirectPlayProfiles = new[]
+            {
+                new DirectPlayProfile
+                {
+                    Container = "avi",
+                    Type = DlnaProfileType.Video,
+                    VideoCodec = "mpeg4",
+                    AudioCodec = "mp2,mp3"
+                },
+                new DirectPlayProfile
+                {
+                    Container = "ts",
+                    Type = DlnaProfileType.Video,
+                    VideoCodec = "mpeg1video,mpeg2video,h264",
+                    AudioCodec = "ac3,mp2,mp3,aac"
+                },
+                new DirectPlayProfile
+                {
+                    Container = "mpeg",
+                    Type = DlnaProfileType.Video,
+                    VideoCodec = "mpeg1video,mpeg2video",
+                    AudioCodec = "mp2"
+                },
+                new DirectPlayProfile
+                {
+                    Container = "mp4,mkv",
+                    Type = DlnaProfileType.Video,
+                    VideoCodec = "h264,mpeg4",
+                    AudioCodec = "aac,ac3"
+                },
+                new DirectPlayProfile
+                {
+                    Container = "aac,mp3,wav",
+                    Type = DlnaProfileType.Audio
+                },
+                new DirectPlayProfile
+                {
+                    Container = "jpeg,png,gif,bmp,tiff",
+                    Type = DlnaProfileType.Photo
+                }
+            };
+
+            TranscodingProfiles = new[]
+            {
+                new TranscodingProfile
+                {
+                    Container = "mp3",
+                    AudioCodec = "mp3",
+                    Type = DlnaProfileType.Audio
+                },
+                new TranscodingProfile
+                {
+                    Container = "ts",
+                    VideoCodec = "h264",
+                    AudioCodec = "mp3",
+                    Type = DlnaProfileType.Video
+                },
+                new TranscodingProfile
+                {
+                    Container = "jpeg",
+                    Type = DlnaProfileType.Photo
+                }
+            };
+
+            ContainerProfiles = new[]
+            {
+                new ContainerProfile
+                {
+                    Type = DlnaProfileType.Photo,
+
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.Width,
+                            Value = "1920"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.Height,
+                            Value = "1080"
+                        }
+                    }
+                }
+            };
+
+            CodecProfiles = new[]
+            {
+                new CodecProfile
+                {
+                    Type = CodecType.Video,
+                    Codec = "h264",
+
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.Width,
+                            Value = "1920"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.Height,
+                            Value = "1080"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoFramerate,
+                            Value = "30",
+                            IsRequired = false
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoBitrate,
+                            Value = "15360000",
+                            IsRequired = false
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoLevel,
+                            Value = "41",
+                            IsRequired = false
+                        }
+                    }
+                },
+
+                new CodecProfile
+                {
+                    Type = CodecType.VideoAudio,
+                    Codec = "ac3",
+
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.AudioChannels,
+                            Value = "6",
+                            IsRequired = false
+                        },
+
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.AudioBitrate,
+                            Value = "640000",
+                            IsRequired = false
+                        }
+                    }
+                },
+
+                new CodecProfile
+                {
+                    Type = CodecType.VideoAudio,
+                    Codec = "wmapro",
+
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.AudioChannels,
+                            Value = "2"
+                        }
+                    }
+                },
+
+                new CodecProfile
+                {
+                    Type = CodecType.VideoAudio,
+                    Codec = "aac",
+
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.NotEquals,
+                            Property = ProfileConditionValue.AudioProfile,
+                            Value = "he-aac",
+                            IsRequired = false
+                        }
+                    }
+                }
+            };
+
+            ResponseProfiles = new[]
+            {
+                new ResponseProfile
+                {
+                    Container = "mp4,mov",
+                    AudioCodec="aac",
+                    MimeType = "video/mp4",
+                    Type = DlnaProfileType.Video
+                },
+
+                new ResponseProfile
+                {
+                    Container = "avi",
+                    MimeType = "video/divx",
+                    OrgPn="AVI",
+                    Type = DlnaProfileType.Video
+                },
+
+                new ResponseProfile
+                {
+                    Container = "wav",
+                    MimeType = "audio/wav",
+                    Type = DlnaProfileType.Audio
+                }
+            };
+        }
+    }
+}

+ 6 - 1
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml

@@ -47,7 +47,7 @@
   </DirectPlayProfiles>
   <TranscodingProfiles>
     <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
-    <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" context="Streaming" />
+    <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" context="Streaming" />
     <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
   </TranscodingProfiles>
   <ContainerProfiles>
@@ -94,6 +94,11 @@
         <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="true" />
       </Conditions>
     </CodecProfile>
+    <CodecProfile type="VideoAudio" codec="mp3,mp2">
+      <Conditions>
+        <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" />
+      </Conditions>
+    </CodecProfile>
   </CodecProfiles>
   <ResponseProfiles>
     <ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">

+ 9 - 4
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml

@@ -41,16 +41,16 @@
   </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
-    <DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
-    <DirectPlayProfile container="mp4" audioCodec="ac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" />
-    <DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" />
+    <DirectPlayProfile container="ts" audioCodec="mp3" videoCodec="mpeg2video" type="Video" />
+    <DirectPlayProfile container="mp4" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg4" type="Video" />
+    <DirectPlayProfile container="mpeg" audioCodec="mp3" videoCodec="mpeg2video,mpeg1video" type="Video" />
     <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" videoCodec="wmv2,wmv3,vc1" type="Video" />
     <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
     <DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
   </DirectPlayProfiles>
   <TranscodingProfiles>
     <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
-    <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" context="Streaming" />
+    <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" context="Streaming" />
     <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
   </TranscodingProfiles>
   <ContainerProfiles>
@@ -97,6 +97,11 @@
         <ProfileCondition condition="NotEquals" property="AudioProfile" value="he-aac" isRequired="true" />
       </Conditions>
     </CodecProfile>
+    <CodecProfile type="VideoAudio" codec="mp3,mp2">
+      <Conditions>
+        <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" />
+      </Conditions>
+    </CodecProfile>
   </CodecProfiles>
   <ResponseProfiles>
     <ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">

+ 6 - 1
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml

@@ -52,7 +52,7 @@
   </DirectPlayProfiles>
   <TranscodingProfiles>
     <TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
-    <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" context="Streaming" />
+    <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" context="Streaming" />
     <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
   </TranscodingProfiles>
   <ContainerProfiles>
@@ -76,6 +76,11 @@
         <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
       </Conditions>
     </CodecProfile>
+    <CodecProfile type="VideoAudio" codec="mp3,mp2">
+      <Conditions>
+        <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" />
+      </Conditions>
+    </CodecProfile>
   </CodecProfiles>
   <ResponseProfiles>
     <ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">

+ 6 - 1
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml

@@ -57,7 +57,7 @@
   </DirectPlayProfiles>
   <TranscodingProfiles>
     <TranscodingProfile container="mp3" type="Audio" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
-    <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="aac" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" context="Streaming" />
+    <TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="true" transcodeSeekInfo="Auto" context="Streaming" />
     <TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" context="Streaming" />
   </TranscodingProfiles>
   <ContainerProfiles>
@@ -76,6 +76,11 @@
         <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
       </Conditions>
     </CodecProfile>
+    <CodecProfile type="VideoAudio" codec="mp3,mp2">
+      <Conditions>
+        <ProfileCondition condition="LessThanEqual" property="AudioChannels" value="2" isRequired="true" />
+      </Conditions>
+    </CodecProfile>
   </CodecProfiles>
   <ResponseProfiles>
     <ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">

File diff suppressed because it is too large
+ 31 - 0
MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 4.xml


+ 3 - 3
MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs

@@ -14,7 +14,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
         {
         }
 
-        protected override void FetchDataFromXmlNode(XmlReader reader, BoxSet item)
+        protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<BoxSet> item)
         {
             switch (reader.Name)
             {
@@ -32,7 +32,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
             }
         }
 
-        private void FetchFromCollectionItemsNode(XmlReader reader, BoxSet item)
+        private void FetchFromCollectionItemsNode(XmlReader reader, MetadataResult<BoxSet> item)
         {
             reader.MoveToContent();
 
@@ -66,7 +66,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
                 }
             }
 
-            item.LinkedChildren = list;
+            item.Item.LinkedChildren = list;
         }
     }
 }

+ 12 - 18
MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs

@@ -1,13 +1,13 @@
-using System;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using System;
 using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
 using System.Threading;
 using System.Xml;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
 
 namespace MediaBrowser.LocalMetadata.Parsers
 {
@@ -17,7 +17,6 @@ namespace MediaBrowser.LocalMetadata.Parsers
     public class EpisodeXmlParser : BaseItemXmlParser<Episode>
     {
         private List<LocalImageInfo> _imagesFound;
-        private List<ChapterInfo> _chaptersFound;
 
         public EpisodeXmlParser(ILogger logger)
             : base(logger)
@@ -26,14 +25,12 @@ namespace MediaBrowser.LocalMetadata.Parsers
 
         private string _xmlPath;
 
-        public void Fetch(Episode item, 
+        public void Fetch(MetadataResult<Episode> item, 
             List<LocalImageInfo> images,
-            List<ChapterInfo> chapters, 
             string metadataFile, 
             CancellationToken cancellationToken)
         {
             _imagesFound = images;
-            _chaptersFound = chapters;
             _xmlPath = metadataFile;
 
             Fetch(item, metadataFile, cancellationToken);
@@ -45,16 +42,13 @@ namespace MediaBrowser.LocalMetadata.Parsers
         /// Fetches the data from XML node.
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <param name="item">The item.</param>
-        protected override void FetchDataFromXmlNode(XmlReader reader, Episode item)
+        /// <param name="result">The result.</param>
+        protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Episode> result)
         {
+            var item = result.Item;
+
             switch (reader.Name)
             {
-                case "Chapters":
-
-                    _chaptersFound.AddRange(FetchChaptersFromXmlNode(item, reader.ReadSubtree()));
-                    break;
-
                 case "Episode":
 
                     //MB generated metadata is within an "Episode" node
@@ -67,7 +61,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
                         {
                             if (subTree.NodeType == XmlNodeType.Element)
                             {
-                                FetchDataFromXmlNode(subTree, item);
+                                FetchDataFromXmlNode(subTree, result);
                             }
                         }
 
@@ -263,7 +257,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
 
 
                 default:
-                    base.FetchDataFromXmlNode(reader, item);
+                    base.FetchDataFromXmlNode(reader, result);
                     break;
             }
         }

+ 6 - 4
MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs

@@ -16,7 +16,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
         }
 
         private readonly Task _cachedTask = Task.FromResult(true);
-        public Task FetchAsync(GameSystem item, string metadataFile, CancellationToken cancellationToken)
+        public Task FetchAsync(MetadataResult<GameSystem> item, string metadataFile, CancellationToken cancellationToken)
         {
             Fetch(item, metadataFile, cancellationToken);
 
@@ -29,9 +29,11 @@ namespace MediaBrowser.LocalMetadata.Parsers
         /// Fetches the data from XML node.
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <param name="item">The item.</param>
-        protected override void FetchDataFromXmlNode(XmlReader reader, GameSystem item)
+        /// <param name="result">The result.</param>
+        protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<GameSystem> result)
         {
+            var item = result.Item;
+
             switch (reader.Name)
             {
                 case "GameSystem":
@@ -56,7 +58,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
 
 
                 default:
-                    base.FetchDataFromXmlNode(reader, item);
+                    base.FetchDataFromXmlNode(reader, result);
                     break;
             }
         }

+ 6 - 4
MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs

@@ -22,7 +22,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
         }
 
         private readonly Task _cachedTask = Task.FromResult(true);
-        public Task FetchAsync(Game item, string metadataFile, CancellationToken cancellationToken)
+        public Task FetchAsync(MetadataResult<Game> item, string metadataFile, CancellationToken cancellationToken)
         {
             Fetch(item, metadataFile, cancellationToken);
 
@@ -35,9 +35,11 @@ namespace MediaBrowser.LocalMetadata.Parsers
         /// Fetches the data from XML node.
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <param name="item">The item.</param>
-        protected override void FetchDataFromXmlNode(XmlReader reader, Game item)
+        /// <param name="result">The result.</param>
+        protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Game> result)
         {
+            var item = result.Item;
+
             switch (reader.Name)
             {
                 case "GameSystem":
@@ -97,7 +99,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
 
 
                 default:
-                    base.FetchDataFromXmlNode(reader, item);
+                    base.FetchDataFromXmlNode(reader, result);
                     break;
             }
         }

+ 25 - 27
MediaBrowser.LocalMetadata/Parsers/MovieXmlParser.cs

@@ -1,43 +1,31 @@
-using System.Collections.Generic;
-using System.Threading;
-using System.Xml;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using System.Xml;
 
 namespace MediaBrowser.LocalMetadata.Parsers
 {
     /// <summary>
     /// Class EpisodeXmlParser
     /// </summary>
-    public class MovieXmlParser : BaseItemXmlParser<Video>
+    public class BaseVideoXmlParser<T> : BaseItemXmlParser<T>
+        where T : Video
     {
-        private List<ChapterInfo> _chaptersFound;
-
-        public MovieXmlParser(ILogger logger)
+        public BaseVideoXmlParser(ILogger logger)
             : base(logger)
         {
         }
 
-        public void Fetch(Video item, 
-            List<ChapterInfo> chapters, 
-            string metadataFile, 
-            CancellationToken cancellationToken)
-        {
-            _chaptersFound = chapters;
-
-            Fetch(item, metadataFile, cancellationToken);
-        }
-
         /// <summary>
         /// Fetches the data from XML node.
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <param name="item">The item.</param>
-        protected override void FetchDataFromXmlNode(XmlReader reader, Video item)
+        /// <param name="result">The result.</param>
+        protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<T> result)
         {
+            var item = result.Item;
+
             switch (reader.Name)
             {
                 case "TmdbCollectionName":
@@ -53,15 +41,25 @@ namespace MediaBrowser.LocalMetadata.Parsers
                         break;
                     }
 
-                case "Chapters":
-
-                    _chaptersFound.AddRange(FetchChaptersFromXmlNode(item, reader.ReadSubtree()));
-                    break;
-
                 default:
-                    base.FetchDataFromXmlNode(reader, item);
+                    base.FetchDataFromXmlNode(reader, result);
                     break;
             }
         }
     }
+
+    public class MovieXmlParser : BaseVideoXmlParser<Movie>
+    {
+        public MovieXmlParser(ILogger logger) : base(logger)
+        {
+        }
+    }
+
+    public class VideoXmlParser : BaseVideoXmlParser<Video>
+    {
+        public VideoXmlParser(ILogger logger)
+            : base(logger)
+        {
+        }
+    }
 }

+ 6 - 4
MediaBrowser.LocalMetadata/Parsers/MusicVideoXmlParser.cs

@@ -6,7 +6,7 @@ using System.Xml;
 
 namespace MediaBrowser.LocalMetadata.Parsers
 {
-    public class MusicVideoXmlParser : BaseItemXmlParser<MusicVideo>
+    public class MusicVideoXmlParser : BaseVideoXmlParser<MusicVideo>
     {
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseItemXmlParser{T}" /> class.
@@ -21,9 +21,11 @@ namespace MediaBrowser.LocalMetadata.Parsers
         /// Fetches the data from XML node.
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <param name="item">The item.</param>
-        protected override void FetchDataFromXmlNode(XmlReader reader, MusicVideo item)
+        /// <param name="result">The result.</param>
+        protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<MusicVideo> result)
         {
+            var item = result.Item;
+
             switch (reader.Name)
             {
                 case "Artist":
@@ -44,7 +46,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
                     break;
 
                 default:
-                    base.FetchDataFromXmlNode(reader, item);
+                    base.FetchDataFromXmlNode(reader, result);
                     break;
             }
         }

+ 4 - 2
MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs

@@ -16,8 +16,10 @@ namespace MediaBrowser.LocalMetadata.Parsers
         {
         }
 
-        protected override void FetchDataFromXmlNode(XmlReader reader, Playlist item)
+        protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Playlist> result)
         {
+            var item = result.Item;
+
             switch (reader.Name)
             {
                 case "OwnerUserId":
@@ -59,7 +61,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
                     break;
 
                 default:
-                    base.FetchDataFromXmlNode(reader, item);
+                    base.FetchDataFromXmlNode(reader, result);
                     break;
             }
         }

+ 5 - 3
MediaBrowser.LocalMetadata/Parsers/SeasonXmlParser.cs

@@ -16,9 +16,11 @@ namespace MediaBrowser.LocalMetadata.Parsers
         /// Fetches the data from XML node.
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <param name="item">The item.</param>
-        protected override void FetchDataFromXmlNode(XmlReader reader, Season item)
+        /// <param name="result">The result.</param>
+        protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Season> result)
         {
+            var item = result.Item;
+
             switch (reader.Name)
             {
                 case "SeasonNumber":
@@ -38,7 +40,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
                     }
 
                 default:
-                    base.FetchDataFromXmlNode(reader, item);
+                    base.FetchDataFromXmlNode(reader, result);
                     break;
             }
         }

+ 6 - 4
MediaBrowser.LocalMetadata/Parsers/SeriesXmlParser.cs

@@ -26,9 +26,11 @@ namespace MediaBrowser.LocalMetadata.Parsers
         /// Fetches the data from XML node.
         /// </summary>
         /// <param name="reader">The reader.</param>
-        /// <param name="item">The item.</param>
-        protected override void FetchDataFromXmlNode(XmlReader reader, Series item)
+        /// <param name="result">The result.</param>
+        protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Series> result)
         {
+            var item = result.Item;
+
             switch (reader.Name)
             {
                 case "Series":
@@ -42,7 +44,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
                         {
                             if (subTree.NodeType == XmlNodeType.Element)
                             {
-                                FetchDataFromXmlNode(subTree, item);
+                                FetchDataFromXmlNode(subTree, result);
                             }
                         }
 
@@ -110,7 +112,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
                     }
 
                 default:
-                    base.FetchDataFromXmlNode(reader, item);
+                    base.FetchDataFromXmlNode(reader, result);
                     break;
             }
         }

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs

@@ -23,7 +23,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<BoxSet> result, string path, CancellationToken cancellationToken)
         {
-            new BoxSetXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
+            new BoxSetXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 2
MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs

@@ -25,10 +25,9 @@ namespace MediaBrowser.LocalMetadata.Providers
             var images = new List<LocalImageInfo>();
             var chapters = new List<ChapterInfo>();
 
-            new EpisodeXmlParser(_logger).Fetch(result.Item, images, chapters, path, cancellationToken);
+            new EpisodeXmlParser(_logger).Fetch(result, images, path, cancellationToken);
 
             result.Images = images;
-            result.Chapters = chapters;
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs

@@ -22,7 +22,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<Folder> result, string path, CancellationToken cancellationToken)
         {
-            new BaseItemXmlParser<Folder>(_logger).Fetch(result.Item, path, cancellationToken);
+            new BaseItemXmlParser<Folder>(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs

@@ -20,7 +20,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<GameSystem> result, string path, CancellationToken cancellationToken)
         {
-            new GameSystemXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
+            new GameSystemXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs

@@ -20,7 +20,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<Game> result, string path, CancellationToken cancellationToken)
         {
-            new GameXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
+            new GameXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 7
MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs

@@ -2,9 +2,7 @@
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.LocalMetadata.Parsers;
-using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
-using System.Collections.Generic;
 using System.IO;
 using System.Threading;
 
@@ -22,11 +20,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<Movie> result, string path, CancellationToken cancellationToken)
         {
-            var chapters = new List<ChapterInfo>();
-
-            new MovieXmlParser(_logger).Fetch(result.Item, chapters, path, cancellationToken);
-
-            result.Chapters = chapters;
+            new MovieXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs

@@ -20,7 +20,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<MusicVideo> result, string path, CancellationToken cancellationToken)
         {
-            new MusicVideoXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
+            new MusicVideoXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/PersonXmlProvider.cs

@@ -19,7 +19,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<Person> result, string path, CancellationToken cancellationToken)
         {
-            new BaseItemXmlParser<Person>(_logger).Fetch(result.Item, path, cancellationToken);
+            new BaseItemXmlParser<Person>(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs

@@ -20,7 +20,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<Playlist> result, string path, CancellationToken cancellationToken)
         {
-            new PlaylistXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
+            new PlaylistXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/SeasonXmlProvider.cs

@@ -23,7 +23,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<Season> result, string path, CancellationToken cancellationToken)
         {
-            new SeasonXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
+            new SeasonXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs

@@ -23,7 +23,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<Series> result, string path, CancellationToken cancellationToken)
         {
-            new SeriesXmlParser(_logger).Fetch(result.Item, path, cancellationToken);
+            new SeriesXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 4 - 10
MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs

@@ -1,12 +1,10 @@
-using System.Collections.Generic;
-using System.IO;
-using System.Threading;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.LocalMetadata.Parsers;
-using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using System.IO;
+using System.Threading;
 
 namespace MediaBrowser.LocalMetadata.Providers
 {
@@ -22,11 +20,7 @@ namespace MediaBrowser.LocalMetadata.Providers
 
         protected override void Fetch(LocalMetadataResult<Video> result, string path, CancellationToken cancellationToken)
         {
-            var chapters = new List<ChapterInfo>();
-
-            new MovieXmlParser(_logger).Fetch(result.Item, chapters, path, cancellationToken);
-
-            result.Chapters = chapters;
+            new VideoXmlParser(_logger).Fetch(result, path, cancellationToken);
         }
 
         protected override FileSystemInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService)

+ 4 - 2
MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs

@@ -20,10 +20,12 @@ namespace MediaBrowser.LocalMetadata.Savers
         }
 
         private readonly IServerConfigurationManager _config;
+        private readonly ILibraryManager _libraryManager;
 
-        public BoxSetXmlSaver(IServerConfigurationManager config)
+        public BoxSetXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
         {
             _config = config;
+            _libraryManager = libraryManager;
         }
 
         /// <summary>
@@ -54,7 +56,7 @@ namespace MediaBrowser.LocalMetadata.Savers
 
             builder.Append("<Item>");
 
-            XmlSaverHelpers.AddCommonNodes((BoxSet)item, builder);
+            XmlSaverHelpers.AddCommonNodes((BoxSet)item, _libraryManager, builder);
 
             builder.Append("</Item>");
 

+ 4 - 2
MediaBrowser.LocalMetadata/Savers/EpisodeXmlSaver.cs

@@ -18,11 +18,13 @@ namespace MediaBrowser.LocalMetadata.Savers
 
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
         private readonly IServerConfigurationManager _config;
+        private readonly ILibraryManager _libraryManager;
 
-        public EpisodeXmlSaver(IItemRepository itemRepository, IServerConfigurationManager config)
+        public EpisodeXmlSaver(IItemRepository itemRepository, IServerConfigurationManager config, ILibraryManager libraryManager)
         {
             _itemRepository = itemRepository;
             _config = config;
+            _libraryManager = libraryManager;
         }
 
         /// <summary>
@@ -116,7 +118,7 @@ namespace MediaBrowser.LocalMetadata.Savers
                 builder.Append("<FirstAired>" + SecurityElement.Escape(episode.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + "</FirstAired>");
             }
 
-            XmlSaverHelpers.AddCommonNodes(episode, builder);
+            XmlSaverHelpers.AddCommonNodes(episode, _libraryManager, builder);
             XmlSaverHelpers.AddMediaInfo(episode, builder, _itemRepository);
 
             builder.Append("</Item>");

+ 4 - 2
MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs

@@ -23,10 +23,12 @@ namespace MediaBrowser.LocalMetadata.Savers
         }
 
         private readonly IServerConfigurationManager _config;
+        private readonly ILibraryManager _libraryManager;
 
-        public FolderXmlSaver(IServerConfigurationManager config)
+        public FolderXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
         {
             _config = config;
+            _libraryManager = libraryManager;
         }
 
         /// <summary>
@@ -68,7 +70,7 @@ namespace MediaBrowser.LocalMetadata.Savers
 
             builder.Append("<Item>");
 
-            XmlSaverHelpers.AddCommonNodes((Folder)item, builder);
+            XmlSaverHelpers.AddCommonNodes((Folder)item, _libraryManager, builder);
 
             builder.Append("</Item>");
 

+ 4 - 2
MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs

@@ -20,10 +20,12 @@ namespace MediaBrowser.LocalMetadata.Savers
         }
 
         private readonly IServerConfigurationManager _config;
+        private readonly ILibraryManager _libraryManager;
 
-        public GameSystemXmlSaver(IServerConfigurationManager config)
+        public GameSystemXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
         {
             _config = config;
+            _libraryManager = libraryManager;
         }
 
         /// <summary>
@@ -61,7 +63,7 @@ namespace MediaBrowser.LocalMetadata.Savers
                 builder.Append("<GameSystem>" + SecurityElement.Escape(gameSystem.GameSystemName) + "</GameSystem>");
             }
 
-            XmlSaverHelpers.AddCommonNodes(gameSystem, builder);
+            XmlSaverHelpers.AddCommonNodes(gameSystem, _libraryManager, builder);
 
             builder.Append("</Item>");
 

+ 5 - 3
MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs

@@ -25,12 +25,14 @@ namespace MediaBrowser.LocalMetadata.Savers
         }
 
         private readonly IServerConfigurationManager _config;
+        private readonly ILibraryManager _libraryManager;
 
-        public GameXmlSaver(IServerConfigurationManager config)
+        public GameXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
         {
             _config = config;
+            _libraryManager = libraryManager;
         }
-        
+
         /// <summary>
         /// Determines whether [is enabled for] [the specified item].
         /// </summary>
@@ -87,7 +89,7 @@ namespace MediaBrowser.LocalMetadata.Savers
                 builder.Append("<NesBoxRom>" + SecurityElement.Escape(val) + "</NesBoxRom>");
             }
 
-            XmlSaverHelpers.AddCommonNodes(game, builder);
+            XmlSaverHelpers.AddCommonNodes(game, _libraryManager, builder);
 
             builder.Append("</Item>");
 

+ 1 - 1
MediaBrowser.LocalMetadata/Savers/MovieXmlSaver.cs

@@ -74,7 +74,7 @@ namespace MediaBrowser.LocalMetadata.Savers
 
             builder.Append("<Title>");
 
-            XmlSaverHelpers.AddCommonNodes(video, builder);
+            XmlSaverHelpers.AddCommonNodes(video, _libraryManager, builder);
 
             var musicVideo = item as MusicVideo;
 

+ 4 - 2
MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs

@@ -23,10 +23,12 @@ namespace MediaBrowser.LocalMetadata.Savers
         }
 
         private readonly IServerConfigurationManager _config;
+        private readonly ILibraryManager _libraryManager;
 
-        public PersonXmlSaver(IServerConfigurationManager config)
+        public PersonXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
         {
             _config = config;
+            _libraryManager = libraryManager;
         }
 
         /// <summary>
@@ -59,7 +61,7 @@ namespace MediaBrowser.LocalMetadata.Savers
 
             builder.Append("<Item>");
 
-            XmlSaverHelpers.AddCommonNodes(person, builder);
+            XmlSaverHelpers.AddCommonNodes(person, _libraryManager, builder);
 
             if (!string.IsNullOrEmpty(person.PlaceOfBirth))
             {

+ 5 - 3
MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs

@@ -21,10 +21,12 @@ namespace MediaBrowser.LocalMetadata.Savers
         }
 
         private readonly IServerConfigurationManager _config;
+        private readonly ILibraryManager _libraryManager;
 
-        public PlaylistXmlSaver(IServerConfigurationManager config)
+        public PlaylistXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
         {
             _config = config;
+            _libraryManager = libraryManager;
         }
 
         /// <summary>
@@ -61,8 +63,8 @@ namespace MediaBrowser.LocalMetadata.Savers
             {
                 builder.Append("<PlaylistMediaType>" + SecurityElement.Escape(playlist.PlaylistMediaType) + "</PlaylistMediaType>");
             }
-            
-            XmlSaverHelpers.AddCommonNodes(playlist, builder);
+
+            XmlSaverHelpers.AddCommonNodes(playlist, _libraryManager, builder);
 
             builder.Append("</Item>");
 

+ 5 - 3
MediaBrowser.LocalMetadata/Savers/SeriesXmlSaver.cs

@@ -15,12 +15,14 @@ namespace MediaBrowser.LocalMetadata.Savers
     public class SeriesXmlSaver : IMetadataFileSaver
     {
         private readonly IServerConfigurationManager _config;
+        private readonly ILibraryManager _libraryManager;
 
-        public SeriesXmlSaver(IServerConfigurationManager config)
+        public SeriesXmlSaver(IServerConfigurationManager config, ILibraryManager libraryManager)
         {
             _config = config;
+            _libraryManager = libraryManager;
         }
-        
+
         public string Name
         {
             get
@@ -105,7 +107,7 @@ namespace MediaBrowser.LocalMetadata.Savers
                 builder.Append("<AnimeSeriesIndex>" + SecurityElement.Escape(series.AnimeSeriesIndex.Value.ToString(UsCulture)) + "</AnimeSeriesIndex>");
             }
 
-            XmlSaverHelpers.AddCommonNodes(series, builder);
+            XmlSaverHelpers.AddCommonNodes(series, _libraryManager, builder);
 
             builder.Append("</Series>");
 

+ 6 - 3
MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Model.Entities;
@@ -230,7 +231,7 @@ namespace MediaBrowser.LocalMetadata.Savers
         /// </summary>
         /// <param name="item">The item.</param>
         /// <param name="builder">The builder.</param>
-        public static void AddCommonNodes(BaseItem item, StringBuilder builder)
+        public static void AddCommonNodes(BaseItem item, ILibraryManager libraryManager, StringBuilder builder)
         {
             if (!string.IsNullOrEmpty(item.OfficialRating))
             {
@@ -627,11 +628,13 @@ namespace MediaBrowser.LocalMetadata.Savers
                 }
             }
 
-            if (item.People.Count > 0)
+            var people = libraryManager.GetPeople(item);
+
+            if (people.Count > 0)
             {
                 builder.Append("<Persons>");
 
-                foreach (var person in item.People)
+                foreach (var person in people)
                 {
                     builder.Append("<Person>");
                     builder.Append("<Name>" + SecurityElement.Escape(person.Name) + "</Name>");

+ 2 - 2
MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs

@@ -834,7 +834,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             {
                 var heightParam = request.Height.Value.ToString(UsCulture);
 
-                filters.Add(string.Format("scale=trunc(oh*a*2)/2:{0}", heightParam));
+                filters.Add(string.Format("scale=trunc(oh*a/2)*2:{0}", heightParam));
             }
 
             // If a max width was requested
@@ -850,7 +850,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             {
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
-                filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
+                filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(ih\\,{0})", maxHeightParam));
             }
 
             var output = string.Empty;

+ 3 - 0
MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj

@@ -1076,6 +1076,9 @@
     <Compile Include="..\MediaBrowser.Model\Session\UserDataChangeInfo.cs">
       <Link>Session\UserDataChangeInfo.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Social\SocialShareInfo.cs">
+      <Link>Social\SocialShareInfo.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Sync\CompleteSyncJobInfo.cs">
       <Link>Sync\CompleteSyncJobInfo.cs</Link>
     </Compile>

+ 3 - 0
MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj

@@ -1032,6 +1032,9 @@
     <Compile Include="..\MediaBrowser.Model\Session\UserDataChangeInfo.cs">
       <Link>Session\UserDataChangeInfo.cs</Link>
     </Compile>
+    <Compile Include="..\mediabrowser.model\social\SocialShareInfo.cs">
+      <Link>Social\SocialShareInfo.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Sync\CompleteSyncJobInfo.cs">
       <Link>Sync\CompleteSyncJobInfo.cs</Link>
     </Compile>

+ 6 - 3
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -25,7 +25,7 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// <value>The public HTTPS port.</value>
         public int PublicHttpsPort { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the HTTP server port number.
         /// </summary>
@@ -49,7 +49,7 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// <value><c>true</c> if [enable user specific user views]; otherwise, <c>false</c>.</value>
         public bool EnableUserSpecificUserViews { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the value pointing to the file system where the ssl certiifcate is located..
         /// </summary>
@@ -103,7 +103,7 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// <value><c>true</c> if [enable library metadata sub folder]; otherwise, <c>false</c>.</value>
         public bool EnableLibraryMetadataSubFolder { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the preferred metadata language.
         /// </summary>
@@ -211,6 +211,8 @@ namespace MediaBrowser.Model.Configuration
 
         public AutoOnOff EnableLibraryMonitor { get; set; }
 
+        public int SharingExpirationDays { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// </summary>
@@ -231,6 +233,7 @@ namespace MediaBrowser.Model.Configuration
 
             EnableUPnP = true;
 
+            SharingExpirationDays = 30;
             MinResumePct = 5;
             MaxResumePct = 90;
 

+ 18 - 11
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -148,6 +148,7 @@ namespace MediaBrowser.Model.Dlna
                     {
                         if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate))
                         {
+                            LogConditionFailure(options.Profile, "AudioCodecProfile", c, item);
                             all = false;
                             break;
                         }
@@ -274,14 +275,21 @@ namespace MediaBrowser.Model.Dlna
                 {
                     playMethods.Add(PlayMethod.DirectStream);
                 }
-                
+
                 // The profile describes what the device supports
                 // If device requirements are satisfied then allow both direct stream and direct play
-                if (item.SupportsDirectPlay && IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options)))
+                if (item.SupportsDirectPlay &&
+                    IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options)))
                 {
                     playMethods.Add(PlayMethod.DirectPlay);
                 }
             }
+            else
+            {
+                _logger.Debug("Profile: {0}, No direct play profiles found for Path: {1}",
+                    options.Profile.Name ?? "Unknown Profile",
+                    item.Path ?? "Unknown path"); 
+            }
 
             return playMethods;
         }
@@ -745,10 +753,9 @@ namespace MediaBrowser.Model.Dlna
                 }
             }
 
+            // Look for supported embedded subs that we can just mux into the output
             foreach (SubtitleProfile profile in subtitleProfiles)
             {
-                bool requiresConversion = !StringHelper.EqualsIgnoreCase(subtitleStream.Codec, profile.Format);
-
                 if (!profile.SupportsLanguage(subtitleStream.Language))
                 {
                     continue;
@@ -756,11 +763,6 @@ namespace MediaBrowser.Model.Dlna
 
                 if (profile.Method == SubtitleDeliveryMethod.Embed && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
                 {
-                    if (!requiresConversion)
-                    {
-                        return profile;
-                    }
-
                     return profile;
                 }
             }
@@ -774,8 +776,13 @@ namespace MediaBrowser.Model.Dlna
 
         private bool IsAudioEligibleForDirectPlay(MediaSourceInfo item, int? maxBitrate)
         {
-            // Honor the max bitrate setting
-            return !maxBitrate.HasValue || (item.Bitrate.HasValue && item.Bitrate.Value <= maxBitrate.Value);
+            if (!maxBitrate.HasValue || (item.Bitrate.HasValue && item.Bitrate.Value <= maxBitrate.Value))
+            {
+                return true;
+            }
+
+            _logger.Debug("Audio Bitrate exceeds DirectPlay limit");
+            return false;
         }
 
         private void ValidateInput(VideoOptions options)

+ 1 - 2
MediaBrowser.Model/Entities/MediaStream.cs

@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Extensions;
 using System.Diagnostics;
 

+ 1 - 0
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -379,6 +379,7 @@
     <Compile Include="Session\TranscodingInfo.cs" />
     <Compile Include="Session\UserDataChangeInfo.cs" />
     <Compile Include="Devices\ContentUploadHistory.cs" />
+    <Compile Include="Social\SocialShareInfo.cs" />
     <Compile Include="Sync\CompleteSyncJobInfo.cs" />
     <Compile Include="Sync\DeviceFileInfo.cs" />
     <Compile Include="Sync\ItemFIleInfo.cs" />

+ 16 - 0
MediaBrowser.Model/Social/SocialShareInfo.cs

@@ -0,0 +1,16 @@
+using System;
+
+namespace MediaBrowser.Model.Social
+{
+    public class SocialShareInfo
+    {
+        public string Id { get; set; }
+        public string Url { get; set; }
+        public string ItemId { get; set; }
+        public string UserId { get; set; }
+        public DateTime ExpirationDate { get; set; }
+        public string Name { get; set; }
+        public string ImageUrl { get; set; }
+        public string Overview { get; set; }
+    }
+}

+ 4 - 12
MediaBrowser.Providers/Books/BookMetadataService.cs

@@ -12,25 +12,17 @@ namespace MediaBrowser.Providers.Books
 {
     public class BookMetadataService : MetadataService<Book, BookInfo>
     {
-        public BookMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager)
+        public BookMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
         {
         }
 
-        /// <summary>
-        /// Merges the specified source.
-        /// </summary>
-        /// <param name="source">The source.</param>
-        /// <param name="target">The target.</param>
-        /// <param name="lockedFields">The locked fields.</param>
-        /// <param name="replaceData">if set to <c>true</c> [replace data].</param>
-        /// <param name="mergeMetadataSettings">if set to <c>true</c> [merge metadata settings].</param>
-        protected override void MergeData(Book source, Book target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+        protected override void MergeData(MetadataResult<Book> source, MetadataResult<Book> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
         {
             ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
 
-            if (replaceData || string.IsNullOrEmpty(target.SeriesName))
+            if (replaceData || string.IsNullOrEmpty(target.Item.SeriesName))
             {
-                target.SeriesName = source.SeriesName;
+                target.Item.SeriesName = source.Item.SeriesName;
             }
         }
     }

+ 19 - 24
MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs

@@ -15,33 +15,10 @@ namespace MediaBrowser.Providers.BoxSets
 {
     public class BoxSetMetadataService : MetadataService<BoxSet, BoxSetInfo>
     {
-        public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager)
+        public BoxSetMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
         {
         }
 
-        /// <summary>
-        /// Merges the specified source.
-        /// </summary>
-        /// <param name="source">The source.</param>
-        /// <param name="target">The target.</param>
-        /// <param name="lockedFields">The locked fields.</param>
-        /// <param name="replaceData">if set to <c>true</c> [replace data].</param>
-        /// <param name="mergeMetadataSettings">if set to <c>true</c> [merge metadata settings].</param>
-        protected override void MergeData(BoxSet source, BoxSet target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
-        {
-            ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
-
-            if (mergeMetadataSettings)
-            {
-                var list = source.LinkedChildren.Where(i => i.Type != LinkedChildType.Manual).ToList();
-
-                list.AddRange(target.LinkedChildren.Where(i => i.Type == LinkedChildType.Manual));
-
-                target.LinkedChildren = list;
-                target.Shares = source.Shares;
-            }
-        }
-
         protected override async Task<ItemUpdateType> BeforeSave(BoxSet item, bool isFullRefresh, ItemUpdateType currentUpdateType)
         {
             var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false);
@@ -59,5 +36,23 @@ namespace MediaBrowser.Providers.BoxSets
 
             return updateType;
         }
+
+        protected override void MergeData(MetadataResult<BoxSet> source, MetadataResult<BoxSet> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+        {
+            ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
+
+            var sourceItem = source.Item;
+            var targetItem = target.Item;
+
+            if (mergeMetadataSettings)
+            {
+                var list = sourceItem.LinkedChildren.Where(i => i.Type != LinkedChildType.Manual).ToList();
+
+                list.AddRange(targetItem.LinkedChildren.Where(i => i.Type == LinkedChildType.Manual));
+
+                targetItem.LinkedChildren = list;
+                targetItem.Shares = sourceItem.Shares;
+            }
+        }
     }
 }

+ 2 - 10
MediaBrowser.Providers/Channels/AudioChannelItemMetadataService.cs

@@ -12,19 +12,11 @@ namespace MediaBrowser.Providers.Channels
 {
     public class AudioChannelItemMetadataService : MetadataService<ChannelAudioItem, ItemLookupInfo>
     {
-        public AudioChannelItemMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager)
+        public AudioChannelItemMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager)
         {
         }
 
-        /// <summary>
-        /// Merges the specified source.
-        /// </summary>
-        /// <param name="source">The source.</param>
-        /// <param name="target">The target.</param>
-        /// <param name="lockedFields">The locked fields.</param>
-        /// <param name="replaceData">if set to <c>true</c> [replace data].</param>
-        /// <param name="mergeMetadataSettings">if set to <c>true</c> [merge metadata settings].</param>
-        protected override void MergeData(ChannelAudioItem source, ChannelAudioItem target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+        protected override void MergeData(MetadataResult<ChannelAudioItem> source, MetadataResult<ChannelAudioItem> target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
         {
             ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
         }

Some files were not shown because too many files changed in this diff