瀏覽代碼

#712 - group multiple versions

Luke Pulverenti 11 年之前
父節點
當前提交
fbfcfdcf07

+ 65 - 59
MediaBrowser.Api/VideosService.cs

@@ -1,13 +1,12 @@
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using ServiceStack;
 using ServiceStack;
 using System;
 using System;
 using System.Linq;
 using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Api
 namespace MediaBrowser.Api
 {
 {
@@ -41,37 +40,20 @@ namespace MediaBrowser.Api
         public string Id { get; set; }
         public string Id { get; set; }
     }
     }
 
 
-    [Route("/Videos/{Id}/AlternateVersions", "POST")]
-    [Api(Description = "Assigns videos as alternates of antoher.")]
-    public class PostAlternateVersions : IReturnVoid
-    {
-        [ApiMember(Name = "AlternateVersionIds", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
-        public string AlternateVersionIds { get; set; }
-
-        /// <summary>
-        /// Gets or sets the id.
-        /// </summary>
-        /// <value>The id.</value>
-        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Id { get; set; }
-    }
-
     [Route("/Videos/{Id}/AlternateVersions", "DELETE")]
     [Route("/Videos/{Id}/AlternateVersions", "DELETE")]
     [Api(Description = "Assigns videos as alternates of antoher.")]
     [Api(Description = "Assigns videos as alternates of antoher.")]
     public class DeleteAlternateVersions : IReturnVoid
     public class DeleteAlternateVersions : IReturnVoid
     {
     {
-        [ApiMember(Name = "AlternateVersionIds", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
-        public string AlternateVersionIds { get; set; }
-
-        /// <summary>
-        /// Gets or sets the id.
-        /// </summary>
-        /// <value>The id.</value>
-        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
         public string Id { get; set; }
         public string Id { get; set; }
+    }
 
 
-        [ApiMember(Name = "IsAlternateEncoding", Description = "Filter by versions that are considered alternate encodings of the original.", IsRequired = true, DataType = "bool", ParameterType = "path", Verb = "GET")]
-        public bool? IsAlternateEncoding { get; set; }
+    [Route("/Videos/MergeVersions", "POST")]
+    [Api(Description = "Merges videos into a single record")]
+    public class MergeVersions : IReturnVoid
+    {
+        [ApiMember(Name = "Ids", Description = "Item id list. This allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)]
+        public string Ids { get; set; }
     }
     }
 
 
     public class VideosService : BaseApiService
     public class VideosService : BaseApiService
@@ -152,60 +134,84 @@ namespace MediaBrowser.Api
             return ToOptimizedSerializedResultUsingCache(result);
             return ToOptimizedSerializedResultUsingCache(result);
         }
         }
 
 
-        public void Post(PostAlternateVersions request)
+        public void Delete(DeleteAlternateVersions request)
         {
         {
-            var task = AddAlternateVersions(request);
+            var task = RemoveAlternateVersions(request);
 
 
             Task.WaitAll(task);
             Task.WaitAll(task);
         }
         }
 
 
-        public void Delete(DeleteAlternateVersions request)
+        private async Task RemoveAlternateVersions(DeleteAlternateVersions request)
         {
         {
-            var task = RemoveAlternateVersions(request);
+            var video = (Video)_dtoService.GetItemByDtoId(request.Id);
+
+            foreach (var link in video.GetLinkedAlternateVersions())
+            {
+                link.PrimaryVersionId = null;
+
+                await link.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+            }
+
+            video.LinkedAlternateVersions.Clear();
+            await video.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+        }
+
+        public void Post(MergeVersions request)
+        {
+            var task = MergeVersions(request);
 
 
             Task.WaitAll(task);
             Task.WaitAll(task);
         }
         }
 
 
-        private async Task AddAlternateVersions(PostAlternateVersions request)
+        private async Task MergeVersions(MergeVersions request)
         {
         {
-            var video = (Video)_dtoService.GetItemByDtoId(request.Id);
+            var items = request.Ids.Split(',')
+                .Select(i => new Guid(i))
+                .Select(i => _libraryManager.GetItemById(i))
+                .Cast<Video>()
+                .ToList();
 
 
-            var list = new List<LinkedChild>();
-            var currentAlternateVersions = video.GetAlternateVersions().ToList();
+            if (items.Count < 2)
+            {
+                throw new ArgumentException("Please supply at least two videos to merge.");
+            }
 
 
-            foreach (var itemId in request.AlternateVersionIds.Split(',').Select(i => new Guid(i)))
+            var videosWithVersions = items.Where(i => i.AlternateVersionCount > 0)
+                .ToList();
+
+            if (videosWithVersions.Count > 1)
             {
             {
-                var item = _libraryManager.GetItemById(itemId) as Video;
+                throw new ArgumentException("Videos with sub-versions cannot be merged.");
+            }
 
 
-                if (item == null)
-                {
-                    throw new ArgumentException("No item exists with the supplied Id");
-                }
+            var primaryVersion = videosWithVersions.FirstOrDefault();
 
 
-                if (currentAlternateVersions.Any(i => i.Id == itemId))
+            if (primaryVersion == null)
+            {
+                primaryVersion = items.OrderByDescending(i =>
                 {
                 {
-                    throw new ArgumentException("Item already exists.");
-                }
+                    var stream = i.GetDefaultVideoStream();
 
 
-                list.Add(new LinkedChild
-                {
-                    Path = item.Path,
-                    Type = LinkedChildType.Manual
-                });
+                    return stream == null || stream.Width == null ? 0 : stream.Width.Value;
 
 
-                item.PrimaryVersionId = video.Id;
+                }).ThenBy(i => i.Name.Length)
+                    .First();
             }
             }
 
 
-            video.LinkedAlternateVersions.AddRange(list);
+            foreach (var item in items.Where(i => i.Id != primaryVersion.Id))
+            {
+                item.PrimaryVersionId = primaryVersion.Id;
 
 
-            await video.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+                await item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
 
 
-            await video.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
-        }
+                primaryVersion.LinkedAlternateVersions.Add(new LinkedChild
+                {
+                    Path = item.Path,
+                    ItemId = item.Id
+                });
+            }
 
 
-        private async Task RemoveAlternateVersions(DeleteAlternateVersions request)
-        {
-            var video = (Video)_dtoService.GetItemByDtoId(request.Id);
+            await primaryVersion.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
         }
         }
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.Controller/Channels/ChannelAudioItem.cs

@@ -2,7 +2,7 @@
 
 
 namespace MediaBrowser.Controller.Channels
 namespace MediaBrowser.Controller.Channels
 {
 {
-    public class ChannelAudioItem : Audio, IChannelItem
+    public class ChannelAudioItem : Audio, IChannelMediaItem
     {
     {
         public string ExternalId { get; set; }
         public string ExternalId { get; set; }
 
 

+ 6 - 1
MediaBrowser.Controller/Channels/ChannelCategoryItem.cs

@@ -2,7 +2,12 @@
 
 
 namespace MediaBrowser.Controller.Channels
 namespace MediaBrowser.Controller.Channels
 {
 {
-    public class ChannelCategoryItem : Folder
+    public class ChannelCategoryItem : Folder, IChannelItem
     {
     {
+        public string ExternalId { get; set; }
+
+        public ChannelItemType ChannelItemType { get; set; }
+
+        public string OriginalImageUrl { get; set; }
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.Controller/Channels/ChannelVideoItem.cs

@@ -2,7 +2,7 @@
 
 
 namespace MediaBrowser.Controller.Channels
 namespace MediaBrowser.Controller.Channels
 {
 {
-    public class ChannelVideoItem : Video, IChannelItem
+    public class ChannelVideoItem : Video, IChannelMediaItem
     {
     {
         public string ExternalId { get; set; }
         public string ExternalId { get; set; }
 
 

+ 5 - 2
MediaBrowser.Controller/Channels/IChannelItem.cs

@@ -8,10 +8,13 @@ namespace MediaBrowser.Controller.Channels
 
 
         ChannelItemType ChannelItemType { get; set; }
         ChannelItemType ChannelItemType { get; set; }
 
 
+        string OriginalImageUrl { get; set; }
+    }
+
+    public interface IChannelMediaItem : IChannelItem
+    {
         bool IsInfiniteStream { get; set; }
         bool IsInfiniteStream { get; set; }
 
 
         ChannelMediaContentType ContentType { get; set; }
         ChannelMediaContentType ContentType { get; set; }
-
-        string OriginalImageUrl { get; set; }
     }
     }
 }
 }

+ 8 - 2
MediaBrowser.Controller/Entities/Video.cs

@@ -51,19 +51,25 @@ namespace MediaBrowser.Controller.Entities
         /// Gets the linked children.
         /// Gets the linked children.
         /// </summary>
         /// </summary>
         /// <returns>IEnumerable{BaseItem}.</returns>
         /// <returns>IEnumerable{BaseItem}.</returns>
-        public IEnumerable<BaseItem> GetAlternateVersions()
+        public IEnumerable<Video> GetAlternateVersions()
         {
         {
             var filesWithinSameDirectory = LocalAlternateVersionIds
             var filesWithinSameDirectory = LocalAlternateVersionIds
                 .Select(i => LibraryManager.GetItemById(i))
                 .Select(i => LibraryManager.GetItemById(i))
                 .Where(i => i != null)
                 .Where(i => i != null)
                 .OfType<Video>();
                 .OfType<Video>();
 
 
+            return filesWithinSameDirectory.Concat(GetLinkedAlternateVersions())
+                .OrderBy(i => i.SortName);
+        }
+
+        public IEnumerable<Video> GetLinkedAlternateVersions()
+        {
             var linkedVersions = LinkedAlternateVersions
             var linkedVersions = LinkedAlternateVersions
                 .Select(GetLinkedChild)
                 .Select(GetLinkedChild)
                 .Where(i => i != null)
                 .Where(i => i != null)
                 .OfType<Video>();
                 .OfType<Video>();
 
 
-            return filesWithinSameDirectory.Concat(linkedVersions)
+            return linkedVersions
                 .OrderBy(i => i.SortName);
                 .OrderBy(i => i.SortName);
         }
         }
 
 

+ 0 - 1
MediaBrowser.Model/Dto/BaseItemDto.cs

@@ -495,7 +495,6 @@ namespace MediaBrowser.Model.Dto
         /// <value>The part count.</value>
         /// <value>The part count.</value>
         public int? PartCount { get; set; }
         public int? PartCount { get; set; }
         public int? AlternateVersionCount { get; set; }
         public int? AlternateVersionCount { get; set; }
-        public string PrimaryVersionId { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Determines whether the specified type is type.
         /// Determines whether the specified type is type.

+ 9 - 3
MediaBrowser.Server.Implementations/Channels/ChannelManager.cs

@@ -208,8 +208,8 @@ namespace MediaBrowser.Server.Implementations.Channels
 
 
             var query = new InternalChannelItemQuery
             var query = new InternalChannelItemQuery
             {
             {
-                 User = user,
-                 CategoryId = categoryId
+                User = user,
+                CategoryId = categoryId
             };
             };
 
 
             var result = await channel.GetChannelItems(query, cancellationToken).ConfigureAwait(false);
             var result = await channel.GetChannelItems(query, cancellationToken).ConfigureAwait(false);
@@ -236,7 +236,7 @@ namespace MediaBrowser.Server.Implementations.Channels
             var tasks = items.Select(GetChannelItemEntity);
             var tasks = items.Select(GetChannelItemEntity);
 
 
             var returnItems = await Task.WhenAll(tasks).ConfigureAwait(false);
             var returnItems = await Task.WhenAll(tasks).ConfigureAwait(false);
-
+            returnItems = new BaseItem[] {};
             var returnItemArray = returnItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
             var returnItemArray = returnItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
                 .ToArray();
                 .ToArray();
 
 
@@ -251,19 +251,25 @@ namespace MediaBrowser.Server.Implementations.Channels
         {
         {
             BaseItem item;
             BaseItem item;
 
 
+            Guid id;
+
             if (info.Type == ChannelItemType.Category)
             if (info.Type == ChannelItemType.Category)
             {
             {
+                id = info.Id.GetMBId(typeof(ChannelCategoryItem));
                 item = new ChannelCategoryItem();
                 item = new ChannelCategoryItem();
             }
             }
             else if (info.MediaType == ChannelMediaType.Audio)
             else if (info.MediaType == ChannelMediaType.Audio)
             {
             {
+                id = info.Id.GetMBId(typeof(ChannelCategoryItem));
                 item = new ChannelAudioItem();
                 item = new ChannelAudioItem();
             }
             }
             else
             else
             {
             {
+                id = info.Id.GetMBId(typeof(ChannelVideoItem));
                 item = new ChannelVideoItem();
                 item = new ChannelVideoItem();
             }
             }
 
 
+            item.Id = id;
             item.Name = info.Name;
             item.Name = info.Name;
             item.Genres = info.Genres;
             item.Genres = info.Genres;
             item.CommunityRating = info.CommunityRating;
             item.CommunityRating = info.CommunityRating;

+ 0 - 5
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -1084,11 +1084,6 @@ namespace MediaBrowser.Server.Implementations.Dto
                 dto.PartCount = video.AdditionalPartIds.Count + 1;
                 dto.PartCount = video.AdditionalPartIds.Count + 1;
                 dto.AlternateVersionCount = video.AlternateVersionCount;
                 dto.AlternateVersionCount = video.AlternateVersionCount;
 
 
-                if (video.PrimaryVersionId.HasValue)
-                {
-                    dto.PrimaryVersionId = video.PrimaryVersionId.Value.ToString("N");
-                }
-
                 if (fields.Contains(ItemFields.Chapters))
                 if (fields.Contains(ItemFields.Chapters))
                 {
                 {
                     dto.Chapters = _itemRepo.GetChapters(video.Id).Select(c => GetChapterInfoDto(c, item)).ToList();
                     dto.Chapters = _itemRepo.GetChapters(video.Id).Select(c => GetChapterInfoDto(c, item)).ToList();