#712 - Support grouping multiple versions of a movie
This commit is contained in:
parent
4e6d306d00
commit
b36aea4ff7
|
@ -1,4 +1,7 @@
|
||||||
using MediaBrowser.Controller.Dto;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
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;
|
||||||
|
@ -38,13 +41,43 @@ 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")]
|
||||||
|
[Api(Description = "Assigns videos as alternates of antoher.")]
|
||||||
|
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")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class VideosService : BaseApiService
|
public class VideosService : BaseApiService
|
||||||
{
|
{
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly IDtoService _dtoService;
|
private readonly IDtoService _dtoService;
|
||||||
|
|
||||||
public VideosService( ILibraryManager libraryManager, IUserManager userManager, IDtoService dtoService)
|
public VideosService(ILibraryManager libraryManager, IUserManager userManager, IDtoService dtoService)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
|
@ -115,5 +148,61 @@ namespace MediaBrowser.Api
|
||||||
|
|
||||||
return ToOptimizedSerializedResultUsingCache(result);
|
return ToOptimizedSerializedResultUsingCache(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Post(PostAlternateVersions request)
|
||||||
|
{
|
||||||
|
var task = AddAlternateVersions(request);
|
||||||
|
|
||||||
|
Task.WaitAll(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(DeleteAlternateVersions request)
|
||||||
|
{
|
||||||
|
var task = RemoveAlternateVersions(request);
|
||||||
|
|
||||||
|
Task.WaitAll(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddAlternateVersions(PostAlternateVersions request)
|
||||||
|
{
|
||||||
|
var video = (Video)_dtoService.GetItemByDtoId(request.Id);
|
||||||
|
|
||||||
|
var list = new List<LinkedChild>();
|
||||||
|
var currentAlternateVersions = video.GetAlternateVersions().ToList();
|
||||||
|
|
||||||
|
foreach (var itemId in request.AlternateVersionIds.Split(',').Select(i => new Guid(i)))
|
||||||
|
{
|
||||||
|
var item = _libraryManager.GetItemById(itemId) as Video;
|
||||||
|
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("No item exists with the supplied Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentAlternateVersions.Any(i => i.Id == itemId))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Item already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Add(new LinkedChild
|
||||||
|
{
|
||||||
|
Path = item.Path,
|
||||||
|
Type = LinkedChildType.Manual
|
||||||
|
});
|
||||||
|
|
||||||
|
item.PrimaryVersionId = video.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
video.LinkedAlternateVersions.AddRange(list);
|
||||||
|
|
||||||
|
await video.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await video.RefreshMetadata(CancellationToken.None).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RemoveAlternateVersions(DeleteAlternateVersions request)
|
||||||
|
{
|
||||||
|
var video = (Video)_dtoService.GetItemByDtoId(request.Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Controller.Resolvers;
|
using MediaBrowser.Controller.Resolvers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
@ -20,26 +21,27 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
public bool IsMultiPart { get; set; }
|
public bool IsMultiPart { get; set; }
|
||||||
public bool HasLocalAlternateVersions { get; set; }
|
public bool HasLocalAlternateVersions { get; set; }
|
||||||
|
public Guid? PrimaryVersionId { get; set; }
|
||||||
|
|
||||||
public List<Guid> AdditionalPartIds { get; set; }
|
public List<Guid> AdditionalPartIds { get; set; }
|
||||||
public List<Guid> AlternateVersionIds { get; set; }
|
public List<Guid> LocalAlternateVersionIds { get; set; }
|
||||||
|
|
||||||
public Video()
|
public Video()
|
||||||
{
|
{
|
||||||
PlayableStreamFileNames = new List<string>();
|
PlayableStreamFileNames = new List<string>();
|
||||||
AdditionalPartIds = new List<Guid>();
|
AdditionalPartIds = new List<Guid>();
|
||||||
AlternateVersionIds = new List<Guid>();
|
LocalAlternateVersionIds = new List<Guid>();
|
||||||
Tags = new List<string>();
|
Tags = new List<string>();
|
||||||
SubtitleFiles = new List<string>();
|
SubtitleFiles = new List<string>();
|
||||||
LinkedAlternateVersions = new List<LinkedChild>();
|
LinkedAlternateVersions = new List<LinkedChild>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public bool HasAlternateVersions
|
public int AlternateVersionCount
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return HasLocalAlternateVersions || LinkedAlternateVersions.Count > 0;
|
return LinkedAlternateVersions.Count + LocalAlternateVersionIds.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +53,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||||
public IEnumerable<BaseItem> GetAlternateVersions()
|
public IEnumerable<BaseItem> GetAlternateVersions()
|
||||||
{
|
{
|
||||||
var filesWithinSameDirectory = AlternateVersionIds
|
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>();
|
||||||
|
@ -233,14 +235,11 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
RefreshLinkedAlternateVersions();
|
RefreshLinkedAlternateVersions();
|
||||||
|
|
||||||
if (HasLocalAlternateVersions)
|
var additionalPartsChanged = await RefreshAlternateVersionsWithinSameDirectory(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
||||||
{
|
|
||||||
var additionalPartsChanged = await RefreshAlternateVersionsWithinSameDirectory(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (additionalPartsChanged)
|
if (additionalPartsChanged)
|
||||||
{
|
{
|
||||||
hasChanges = true;
|
hasChanges = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,21 +338,72 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
private async Task<bool> RefreshAlternateVersionsWithinSameDirectory(MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
|
private async Task<bool> RefreshAlternateVersionsWithinSameDirectory(MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var newItems = LoadAlternateVersionsWithinSameDirectory(fileSystemChildren, options.DirectoryService).ToList();
|
var newItems = HasLocalAlternateVersions ?
|
||||||
|
LoadAlternateVersionsWithinSameDirectory(fileSystemChildren, options.DirectoryService).ToList() :
|
||||||
|
new List<Video>();
|
||||||
|
|
||||||
var newItemIds = newItems.Select(i => i.Id).ToList();
|
var newItemIds = newItems.Select(i => i.Id).ToList();
|
||||||
|
|
||||||
var itemsChanged = !AlternateVersionIds.SequenceEqual(newItemIds);
|
var itemsChanged = !LocalAlternateVersionIds.SequenceEqual(newItemIds);
|
||||||
|
|
||||||
var tasks = newItems.Select(i => i.RefreshMetadata(options, cancellationToken));
|
var tasks = newItems.Select(i => RefreshAlternateVersion(options, i, cancellationToken));
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||||
|
|
||||||
AlternateVersionIds = newItemIds;
|
LocalAlternateVersionIds = newItemIds;
|
||||||
|
|
||||||
return itemsChanged;
|
return itemsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task RefreshAlternateVersion(MetadataRefreshOptions options, Video video, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var currentImagePath = video.GetImagePath(ImageType.Primary);
|
||||||
|
var ownerImagePath = this.GetImagePath(ImageType.Primary);
|
||||||
|
|
||||||
|
var newOptions = new MetadataRefreshOptions
|
||||||
|
{
|
||||||
|
DirectoryService = options.DirectoryService,
|
||||||
|
ImageRefreshMode = options.ImageRefreshMode,
|
||||||
|
MetadataRefreshMode = options.MetadataRefreshMode,
|
||||||
|
ReplaceAllMetadata = options.ReplaceAllMetadata
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.Equals(currentImagePath, ownerImagePath, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
newOptions.ForceSave = true;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(ownerImagePath))
|
||||||
|
{
|
||||||
|
video.ImageInfos.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
video.SetImagePath(ImageType.Primary, ownerImagePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return video.RefreshMetadata(newOptions, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task UpdateToRepository(ItemUpdateType updateReason, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await base.UpdateToRepository(updateReason, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
foreach (var item in LocalAlternateVersionIds.Select(i => LibraryManager.GetItemById(i)))
|
||||||
|
{
|
||||||
|
item.ImageInfos = ImageInfos;
|
||||||
|
item.Overview = Overview;
|
||||||
|
item.ProductionYear = ProductionYear;
|
||||||
|
item.PremiereDate = PremiereDate;
|
||||||
|
item.CommunityRating = CommunityRating;
|
||||||
|
item.OfficialRating = OfficialRating;
|
||||||
|
item.Genres = Genres;
|
||||||
|
item.ProviderIds = ProviderIds;
|
||||||
|
|
||||||
|
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads the additional parts.
|
/// Loads the additional parts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -395,7 +445,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
video = dbItem;
|
video = dbItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
video.ImageInfos = ImageInfos;
|
video.PrimaryVersionId = Id;
|
||||||
|
|
||||||
return video;
|
return video;
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
private readonly INetworkManager _networkManager;
|
private readonly INetworkManager _networkManager;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IDlnaManager _dlnaManager;
|
private readonly IDlnaManager _dlnaManager;
|
||||||
|
private readonly IUserManager _userManager;
|
||||||
private bool _playbackStarted = false;
|
private bool _playbackStarted = false;
|
||||||
|
|
||||||
public bool SupportsMediaRemoteControl
|
public bool SupportsMediaRemoteControl
|
||||||
|
@ -46,7 +47,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, INetworkManager networkManager, IDlnaManager dlnaManager)
|
public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, INetworkManager networkManager, IDlnaManager dlnaManager, IUserManager userManager)
|
||||||
{
|
{
|
||||||
_session = session;
|
_session = session;
|
||||||
_itemRepository = itemRepository;
|
_itemRepository = itemRepository;
|
||||||
|
@ -54,6 +55,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
_dlnaManager = dlnaManager;
|
_dlnaManager = dlnaManager;
|
||||||
|
_userManager = userManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +196,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
#region SendCommands
|
#region SendCommands
|
||||||
|
|
||||||
public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
|
public async Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
_logger.Debug("{0} - Received PlayRequest: {1}", this._session.DeviceName, command.PlayCommand);
|
_logger.Debug("{0} - Received PlayRequest: {1}", this._session.DeviceName, command.PlayCommand);
|
||||||
|
|
||||||
|
@ -227,16 +229,25 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
if (command.PlayCommand == PlayCommand.PlayLast)
|
if (command.PlayCommand == PlayCommand.PlayLast)
|
||||||
{
|
{
|
||||||
AddItemsToPlaylist(playlist);
|
AddItemsToPlaylist(playlist);
|
||||||
return Task.FromResult(true);
|
|
||||||
}
|
}
|
||||||
if (command.PlayCommand == PlayCommand.PlayNext)
|
if (command.PlayCommand == PlayCommand.PlayNext)
|
||||||
{
|
{
|
||||||
AddItemsToPlaylist(playlist);
|
AddItemsToPlaylist(playlist);
|
||||||
return Task.FromResult(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("{0} - Playing {1} items", _session.DeviceName, playlist.Count);
|
_logger.Debug("{0} - Playing {1} items", _session.DeviceName, playlist.Count);
|
||||||
return PlayItems(playlist);
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(command.ControllingUserId))
|
||||||
|
{
|
||||||
|
var userId = new Guid(command.ControllingUserId);
|
||||||
|
|
||||||
|
var user = _userManager.GetUserById(userId);
|
||||||
|
|
||||||
|
await _sessionManager.LogSessionActivity(_session.Client, _session.ApplicationVersion, _session.DeviceId,
|
||||||
|
_session.DeviceName, _session.RemoteEndPoint, user).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
await PlayItems(playlist).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
|
public Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
|
||||||
|
|
|
@ -227,7 +227,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
if (controller == null)
|
if (controller == null)
|
||||||
{
|
{
|
||||||
sessionInfo.SessionController = controller = new PlayToController(sessionInfo, _sessionManager, _itemRepository, _libraryManager, _logger, _networkManager, _dlnaManager);
|
sessionInfo.SessionController = controller = new PlayToController(sessionInfo, _sessionManager, _itemRepository, _libraryManager, _logger, _networkManager, _dlnaManager, _userManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.Init(device);
|
controller.Init(device);
|
||||||
|
|
|
@ -494,7 +494,8 @@ namespace MediaBrowser.Model.Dto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The part count.</value>
|
/// <value>The part count.</value>
|
||||||
public int? PartCount { get; set; }
|
public int? PartCount { get; set; }
|
||||||
public bool? HasAlternateVersions { 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.
|
||||||
|
|
|
@ -23,6 +23,12 @@ namespace MediaBrowser.Model.Session
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The play command.</value>
|
/// <value>The play command.</value>
|
||||||
public PlayCommand PlayCommand { get; set; }
|
public PlayCommand PlayCommand { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the controlling user identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The controlling user identifier.</value>
|
||||||
|
public string ControllingUserId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -37,5 +37,11 @@ namespace MediaBrowser.Model.Session
|
||||||
public PlaystateCommand Command { get; set; }
|
public PlaystateCommand Command { get; set; }
|
||||||
|
|
||||||
public long? SeekPositionTicks { get; set; }
|
public long? SeekPositionTicks { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the controlling user identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The controlling user identifier.</value>
|
||||||
|
public string ControllingUserId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -94,14 +94,13 @@ namespace MediaBrowser.Providers.All
|
||||||
public List<LocalImageInfo> GetImages(IHasImages item, IEnumerable<string> paths, IDirectoryService directoryService)
|
public List<LocalImageInfo> GetImages(IHasImages item, IEnumerable<string> paths, IDirectoryService directoryService)
|
||||||
{
|
{
|
||||||
var files = paths.SelectMany(directoryService.GetFiles)
|
var files = paths.SelectMany(directoryService.GetFiles)
|
||||||
.Where(i =>
|
.Where(i =>
|
||||||
{
|
{
|
||||||
var ext = i.Extension;
|
var ext = i.Extension;
|
||||||
|
|
||||||
return !string.IsNullOrEmpty(ext) &&
|
return !string.IsNullOrEmpty(ext) &&
|
||||||
BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
|
BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
|
||||||
})
|
})
|
||||||
.Cast<FileSystemInfo>()
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var list = new List<LocalImageInfo>();
|
var list = new List<LocalImageInfo>();
|
||||||
|
|
|
@ -111,6 +111,7 @@ namespace MediaBrowser.Server.Implementations.Collections
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<LinkedChild>();
|
var list = new List<LinkedChild>();
|
||||||
|
var currentLinkedChildren = collection.GetLinkedChildren().ToList();
|
||||||
|
|
||||||
foreach (var itemId in ids)
|
foreach (var itemId in ids)
|
||||||
{
|
{
|
||||||
|
@ -121,7 +122,7 @@ namespace MediaBrowser.Server.Implementations.Collections
|
||||||
throw new ArgumentException("No item exists with the supplied Id");
|
throw new ArgumentException("No item exists with the supplied Id");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collection.LinkedChildren.Any(i => i.ItemId.HasValue && i.ItemId == itemId))
|
if (currentLinkedChildren.Any(i => i.Id == itemId))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Item already exists in collection");
|
throw new ArgumentException("Item already exists in collection");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1082,7 +1082,12 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
dto.IsHD = video.IsHD;
|
dto.IsHD = video.IsHD;
|
||||||
|
|
||||||
dto.PartCount = video.AdditionalPartIds.Count + 1;
|
dto.PartCount = video.AdditionalPartIds.Count + 1;
|
||||||
dto.HasAlternateVersions = video.HasAlternateVersions;
|
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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -410,7 +410,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(filenamePrefix))
|
if (!string.IsNullOrWhiteSpace(filenamePrefix))
|
||||||
{
|
{
|
||||||
if (sortedMovies.All(i => Path.GetFileNameWithoutExtension(i.Path).StartsWith(filenamePrefix, StringComparison.OrdinalIgnoreCase)))
|
if (sortedMovies.Skip(1).All(i => Path.GetFileNameWithoutExtension(i.Path).StartsWith(filenamePrefix + " - ", StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
firstMovie.HasLocalAlternateVersions = true;
|
firstMovie.HasLocalAlternateVersions = true;
|
||||||
|
|
||||||
|
|
|
@ -690,6 +690,11 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session.UserId.HasValue)
|
||||||
|
{
|
||||||
|
command.ControllingUserId = session.UserId.Value.ToString("N");
|
||||||
|
}
|
||||||
|
|
||||||
return session.SessionController.SendPlayCommand(command, cancellationToken);
|
return session.SessionController.SendPlayCommand(command, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,6 +728,11 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
throw new ArgumentException(string.Format("Session {0} is unable to seek.", session.Id));
|
throw new ArgumentException(string.Format("Session {0} is unable to seek.", session.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session.UserId.HasValue)
|
||||||
|
{
|
||||||
|
command.ControllingUserId = session.UserId.Value.ToString("N");
|
||||||
|
}
|
||||||
|
|
||||||
return session.SessionController.SendPlaystateCommand(command, cancellationToken);
|
return session.SessionController.SendPlaystateCommand(command, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user