Luke Pulverenti преди 10 години
родител
ревизия
5965afecde

+ 0 - 23
MediaBrowser.Api/Playback/MediaInfoService.cs

@@ -39,29 +39,6 @@ namespace MediaBrowser.Api.Playback
     [Route("/Items/{Id}/PlaybackInfo", "POST", Summary = "Gets live playback media info for an item")]
     public class GetPostedPlaybackInfo : PlaybackInfoRequest, IReturn<PlaybackInfoResponse>
     {
-        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
-        public string Id { get; set; }
-
-        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
-        public string UserId { get; set; }
-
-        [ApiMember(Name = "MaxStreamingBitrate", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
-        public int? MaxStreamingBitrate { get; set; }
-
-        [ApiMember(Name = "StartTimeTicks", Description = "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
-        public long? StartTimeTicks { get; set; }
-
-        [ApiMember(Name = "AudioStreamIndex", Description = "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
-        public int? AudioStreamIndex { get; set; }
-
-        [ApiMember(Name = "SubtitleStreamIndex", Description = "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
-        public int? SubtitleStreamIndex { get; set; }
-
-        [ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
-        public string MediaSourceId { get; set; }
-
-        [ApiMember(Name = "LiveStreamId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
-        public string LiveStreamId { get; set; }
     }
 
     [Route("/LiveStreams/Open", "POST", Summary = "Opens a media source")]

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

@@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback
 
             var options = GetOptions();
 
-            if (/*options.EnableThrottling &&*/ IsThrottleAllowed(_job, options.ThrottleThresholdSeconds))
+            if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdSeconds))
             {
                 PauseTranscoding();
             }

+ 21 - 11
MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs

@@ -107,30 +107,40 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
 
         private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression)
         {
-            var request = (HttpWebRequest)WebRequest.Create(options.Url);
+            var request = WebRequest.Create(options.Url);
+            var httpWebRequest = request as HttpWebRequest;
 
-            AddRequestHeaders(request, options);
+            if (httpWebRequest != null)
+            {
+                AddRequestHeaders(httpWebRequest, options);
 
-            request.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;
+                httpWebRequest.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None;
+            }
 
             request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
 
-            if (options.EnableKeepAlive)
+            if (httpWebRequest != null)
             {
-                request.KeepAlive = true;
+                if (options.EnableKeepAlive)
+                {
+                    httpWebRequest.KeepAlive = true;
+                }
             }
 
             request.Method = method;
             request.Timeout = options.TimeoutMs;
 
-            if (!string.IsNullOrEmpty(options.Host))
+            if (httpWebRequest != null)
             {
-                request.Host = options.Host;
-            }
+                if (!string.IsNullOrEmpty(options.Host))
+                {
+                    httpWebRequest.Host = options.Host;
+                }
 
-            if (!string.IsNullOrEmpty(options.Referer))
-            {
-                request.Referer = options.Referer;
+                if (!string.IsNullOrEmpty(options.Referer))
+                {
+                    httpWebRequest.Referer = options.Referer;
+                }
             }
 
             //request.ServicePoint.BindIPEndPointDelegate = BindIPEndPointCallback;

+ 6 - 0
MediaBrowser.Controller/LiveTv/LiveTvProgram.cs

@@ -34,6 +34,12 @@ namespace MediaBrowser.Controller.LiveTv
         /// <value>The channel identifier.</value>
         public string ExternalChannelId { get; set; }
 
+        /// <summary>
+        /// Gets or sets the original air date.
+        /// </summary>
+        /// <value>The original air date.</value>
+        public DateTime? OriginalAirDate { get; set; }
+        
         /// <summary>
         /// Gets or sets the type of the channel.
         /// </summary>

+ 16 - 0
MediaBrowser.Controller/Sync/ISyncDataProvider.cs

@@ -14,6 +14,14 @@ namespace MediaBrowser.Controller.Sync
         /// <returns>Task&lt;List&lt;System.String&gt;&gt;.</returns>
         Task<List<string>> GetServerItemIds(SyncTarget target, string serverId);
 
+        /// <summary>
+        /// Gets the synchronize job item ids.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <param name="serverId">The server identifier.</param>
+        /// <returns>Task&lt;List&lt;System.String&gt;&gt;.</returns>
+        Task<List<string>> GetSyncJobItemIds(SyncTarget target, string serverId);
+        
         /// <summary>
         /// Adds the or update.
         /// </summary>
@@ -46,5 +54,13 @@ namespace MediaBrowser.Controller.Sync
         /// <param name="itemId">The item identifier.</param>
         /// <returns>Task&lt;LocalItem&gt;.</returns>
         Task<List<LocalItem>> GetCachedItems(SyncTarget target, string serverId, string itemId);
+        /// <summary>
+        /// Gets the cached items by synchronize job item identifier.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <param name="serverId">The server identifier.</param>
+        /// <param name="syncJobItemId">The synchronize job item identifier.</param>
+        /// <returns>Task&lt;List&lt;LocalItem&gt;&gt;.</returns>
+        Task<List<LocalItem>> GetCachedItemsBySyncJobItemId(SyncTarget target, string serverId, string syncJobItemId);
     }
 }

+ 2 - 3
MediaBrowser.Model/ApiClient/IApiClient.cs

@@ -248,10 +248,9 @@ namespace MediaBrowser.Model.ApiClient
         /// <summary>
         /// Gets the playback information.
         /// </summary>
-        /// <param name="itemId">The item identifier.</param>
-        /// <param name="userId">The user identifier.</param>
+        /// <param name="request">The request.</param>
         /// <returns>Task&lt;LiveMediaInfoResult&gt;.</returns>
-        Task<PlaybackInfoResponse> GetPlaybackInfo(string itemId, string userId);
+        Task<PlaybackInfoResponse> GetPlaybackInfo(PlaybackInfoRequest request);
 
         /// <summary>
         /// Gets the users async.

+ 16 - 0
MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs

@@ -4,6 +4,22 @@ namespace MediaBrowser.Model.MediaInfo
 {
     public class PlaybackInfoRequest
     {
+        public string Id { get; set; }
+
+        public string UserId { get; set; }
+
+        public int? MaxStreamingBitrate { get; set; }
+
+        public long? StartTimeTicks { get; set; }
+
+        public int? AudioStreamIndex { get; set; }
+
+        public int? SubtitleStreamIndex { get; set; }
+
+        public string MediaSourceId { get; set; }
+
+        public string LiveStreamId { get; set; }
+        
         public DeviceProfile DeviceProfile { get; set; }
     }
 }

+ 5 - 0
MediaBrowser.Model/Sync/LocalItem.cs

@@ -31,6 +31,11 @@ namespace MediaBrowser.Model.Sync
         /// <value>The item identifier.</value>
         public string ItemId { get; set; }
         /// <summary>
+        /// Gets or sets the synchronize job item identifier.
+        /// </summary>
+        /// <value>The synchronize job item identifier.</value>
+        public string SyncJobItemId { get; set; }
+        /// <summary>
         /// Gets or sets the user ids with access.
         /// </summary>
         /// <value>The user ids with access.</value>

+ 1 - 0
MediaBrowser.Model/Sync/SyncDataRequest.cs

@@ -6,6 +6,7 @@ namespace MediaBrowser.Model.Sync
     {
         public List<string> LocalItemIds { get; set; }
         public List<string> OfflineUserIds { get; set; }
+        public List<string> SyncJobItemIds { get; set; }
 
         public string TargetId { get; set; }
 

+ 0 - 1
MediaBrowser.Server.Implementations/Channels/ChannelImageProvider.cs

@@ -2,7 +2,6 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
-using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading;

+ 5 - 5
MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs

@@ -129,6 +129,11 @@ namespace MediaBrowser.Server.Implementations.Library
             return list;
         }
 
+        public Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken)
+        {
+            return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken);
+        }
+
         public async Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, CancellationToken cancellationToken)
         {
             var item = _libraryManager.GetItemById(id);
@@ -225,11 +230,6 @@ namespace MediaBrowser.Server.Implementations.Library
             }
         }
 
-        public Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken)
-        {
-            return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken);
-        }
-
         public MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution)
         {
             return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs

@@ -373,7 +373,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 StartDate = item.StartDate,
                 OfficialRating = item.OfficialRating,
                 IsHD = item.IsHD,
-                OriginalAirDate = item.PremiereDate,
+                OriginalAirDate = item.OriginalAirDate,
                 Audio = item.Audio,
                 CommunityRating = GetClientCommunityRating(item.CommunityRating),
                 IsRepeat = item.IsRepeat,

+ 4 - 2
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -589,13 +589,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             item.Name = info.Name;
             item.OfficialRating = info.OfficialRating;
             item.Overview = info.Overview;
-            item.PremiereDate = info.OriginalAirDate;
+            item.OriginalAirDate = info.OriginalAirDate;
             item.ProviderImagePath = info.ImagePath;
             item.ProviderImageUrl = info.ImageUrl;
             item.RunTimeTicks = (info.EndDate - info.StartDate).Ticks;
             item.StartDate = info.StartDate;
-            item.ProductionYear = info.ProductionYear;
 
+            item.ProductionYear = info.ProductionYear;
+            item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate;
+            
             await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
 
             return item;

+ 6 - 5
MediaBrowser.Server.Implementations/Sync/MediaSync.cs

@@ -67,12 +67,12 @@ namespace MediaBrowser.Server.Implementations.Sync
             SyncTarget target,
             CancellationToken cancellationToken)
         {
-            var localIds = await dataProvider.GetServerItemIds(target, serverId).ConfigureAwait(false);
+            var jobItemIds = await dataProvider.GetSyncJobItemIds(target, serverId).ConfigureAwait(false);
 
             var result = await _syncManager.SyncData(new SyncDataRequest
             {
                 TargetId = target.Id,
-                LocalItemIds = localIds
+                SyncJobItemIds = jobItemIds
 
             }).ConfigureAwait(false);
 
@@ -285,11 +285,11 @@ namespace MediaBrowser.Server.Implementations.Sync
         private async Task RemoveItem(IServerSyncProvider provider,
             ISyncDataProvider dataProvider,
             string serverId,
-            string itemId,
+            string syncJobItemId,
             SyncTarget target,
             CancellationToken cancellationToken)
         {
-            var localItems = await dataProvider.GetCachedItems(target, serverId, itemId);
+            var localItems = await dataProvider.GetCachedItemsBySyncJobItemId(target, serverId, syncJobItemId);
 
             foreach (var localItem in localItems)
             {
@@ -350,7 +350,8 @@ namespace MediaBrowser.Server.Implementations.Sync
                 ItemId = libraryItem.Id,
                 ServerId = serverId,
                 LocalPath = localPath,
-                Id = GetLocalId(syncedItem.SyncJobItemId, libraryItem.Id)
+                Id = GetLocalId(syncedItem.SyncJobItemId, libraryItem.Id),
+                SyncJobItemId = syncedItem.SyncJobItemId
             };
         }
 

+ 91 - 4
MediaBrowser.Server.Implementations/Sync/SyncManager.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
@@ -42,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Sync
         private readonly ILogger _logger;
         private readonly IUserManager _userManager;
         private readonly Func<IDtoService> _dtoService;
-        private readonly IApplicationHost _appHost;
+        private readonly IServerApplicationHost _appHost;
         private readonly ITVSeriesManager _tvSeriesManager;
         private readonly Func<IMediaEncoder> _mediaEncoder;
         private readonly IFileSystem _fileSystem;
@@ -60,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.Sync
         public event EventHandler<GenericEventArgs<SyncJobItem>> SyncJobItemUpdated;
         public event EventHandler<GenericEventArgs<SyncJobItem>> SyncJobItemCreated;
 
-        public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func<IDtoService> dtoService, IApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func<IMediaEncoder> mediaEncoder, IFileSystem fileSystem, Func<ISubtitleEncoder> subtitleEncoder, IConfigurationManager config, IUserDataManager userDataManager, Func<IMediaSourceManager> mediaSourceManager, IJsonSerializer json)
+        public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func<IDtoService> dtoService, IServerApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func<IMediaEncoder> mediaEncoder, IFileSystem fileSystem, Func<ISubtitleEncoder> subtitleEncoder, IConfigurationManager config, IUserDataManager userDataManager, Func<IMediaSourceManager> mediaSourceManager, IJsonSerializer json)
         {
             _libraryManager = libraryManager;
             _repo = repo;
@@ -94,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
         public ISyncDataProvider GetDataProvider(IServerSyncProvider provider, SyncTarget target)
         {
-            return _dataProviders.GetOrAdd(target.Id, key => new TargetDataProvider(provider, target, _appHost.SystemId, _logger, _json, _fileSystem, _config.CommonApplicationPaths));
+            return _dataProviders.GetOrAdd(target.Id, key => new TargetDataProvider(provider, target, _appHost, _logger, _json, _fileSystem, _config.CommonApplicationPaths));
         }
 
         public async Task<SyncJobCreationResult> CreateJob(SyncJobRequest request)
@@ -737,10 +738,15 @@ namespace MediaBrowser.Server.Implementations.Sync
 
         public async Task<SyncDataResponse> SyncData(SyncDataRequest request)
         {
+            if (request.SyncJobItemIds != null)
+            {
+                return await SyncDataUsingSyncJobItemIds(request).ConfigureAwait(false);
+            }
+
             var jobItemResult = GetJobItems(new SyncJobItemQuery
             {
                 TargetId = request.TargetId,
-                Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Synced }
+                Statuses = new[] { SyncJobItemStatus.Synced }
             });
 
             var response = new SyncDataResponse();
@@ -816,6 +822,87 @@ namespace MediaBrowser.Server.Implementations.Sync
             return response;
         }
 
+        private async Task<SyncDataResponse> SyncDataUsingSyncJobItemIds(SyncDataRequest request)
+        {
+            var jobItemResult = GetJobItems(new SyncJobItemQuery
+            {
+                TargetId = request.TargetId,
+                Statuses = new[] { SyncJobItemStatus.Synced }
+            });
+
+            var response = new SyncDataResponse();
+
+            foreach (var jobItem in jobItemResult.Items)
+            {
+                if (request.SyncJobItemIds.Contains(jobItem.Id, StringComparer.OrdinalIgnoreCase))
+                {
+                    var job = _repo.GetJob(jobItem.JobId);
+                    var user = _userManager.GetUserById(job.UserId);
+
+                    if (jobItem.IsMarkedForRemoval)
+                    {
+                        // Tell the device to remove it since it has been marked for removal
+                        response.ItemIdsToRemove.Add(jobItem.Id);
+                    }
+                    else if (user == null)
+                    {
+                        // Tell the device to remove it since the user is gone now
+                        response.ItemIdsToRemove.Add(jobItem.Id);
+                    }
+                    else if (job.UnwatchedOnly)
+                    {
+                        var libraryItem = _libraryManager.GetItemById(jobItem.ItemId);
+
+                        if (IsLibraryItemAvailable(libraryItem))
+                        {
+                            if (libraryItem.IsPlayed(user) && libraryItem is Video)
+                            {
+                                // Tell the device to remove it since it has been played
+                                response.ItemIdsToRemove.Add(jobItem.Id);
+                            }
+                        }
+                        else
+                        {
+                            // Tell the device to remove it since it's no longer available
+                            response.ItemIdsToRemove.Add(jobItem.Id);
+                        }
+                    }
+                }
+                else
+                {
+                    // Content is no longer on the device
+                    jobItem.Status = SyncJobItemStatus.RemovedFromDevice;
+                    await UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false);
+                }
+            }
+
+            // Now check each item that's on the device
+            foreach (var syncJobItemId in request.SyncJobItemIds)
+            {
+                // See if it's already marked for removal
+                if (response.ItemIdsToRemove.Contains(syncJobItemId, StringComparer.OrdinalIgnoreCase))
+                {
+                    continue;
+                }
+
+                // If there isn't a sync job for this item, mark it for removal
+                if (!jobItemResult.Items.Any(i => string.Equals(syncJobItemId, i.Id, StringComparison.OrdinalIgnoreCase)))
+                {
+                    response.ItemIdsToRemove.Add(syncJobItemId);
+                }
+            }
+
+            response.ItemIdsToRemove = response.ItemIdsToRemove.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
+
+            var itemsOnDevice = request.LocalItemIds
+                .Except(response.ItemIdsToRemove)
+                .ToList();
+
+            SetUserAccess(request, response, itemsOnDevice);
+
+            return response;
+        }
+
         private void SetUserAccess(SyncDataRequest request, SyncDataResponse response, List<string> itemIds)
         {
             var users = request.OfflineUserIds

+ 26 - 4
MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Sync;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
@@ -26,11 +27,11 @@ namespace MediaBrowser.Server.Implementations.Sync
         private readonly IJsonSerializer _json;
         private readonly IFileSystem _fileSystem;
         private readonly IApplicationPaths _appPaths;
-        private readonly string _serverId;
+        private readonly IServerApplicationHost _appHost;
 
         private readonly SemaphoreSlim _cacheFileLock = new SemaphoreSlim(1, 1);
 
-        public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, string serverId, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths)
+        public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, IServerApplicationHost appHost, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths)
         {
             _logger = logger;
             _json = json;
@@ -38,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             _target = target;
             _fileSystem = fileSystem;
             _appPaths = appPaths;
-            _serverId = serverId;
+            _appHost = appHost;
         }
 
         private string GetCachePath()
@@ -50,13 +51,21 @@ namespace MediaBrowser.Server.Implementations.Sync
         {
             var parts = new List<string>
             {
-                _serverId,
+                _appHost.FriendlyName,
                 "data.json"
             };
 
+            parts = parts.Select(i => GetValidFilename(_provider, i)).ToList();
+
             return _provider.GetFullPath(parts, _target);
         }
 
+        private string GetValidFilename(IServerSyncProvider provider, string filename)
+        {
+            // We can always add this method to the sync provider if it's really needed
+            return _fileSystem.GetValidFilename(filename);
+        }
+
         private async Task CacheData(Stream stream)
         {
             var cachePath = GetCachePath();
@@ -167,6 +176,11 @@ namespace MediaBrowser.Server.Implementations.Sync
             return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).Select(i => i.ItemId).ToList());
         }
 
+        public Task<List<string>> GetSyncJobItemIds(SyncTarget target, string serverId)
+        {
+            return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).Select(i => i.SyncJobItemId).Where(i => !string.IsNullOrWhiteSpace(i)).ToList());
+        }
+
         public Task AddOrUpdate(SyncTarget target, LocalItem item)
         {
             return UpdateData(items =>
@@ -239,5 +253,13 @@ namespace MediaBrowser.Server.Implementations.Sync
             return items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.ItemId, itemId, StringComparison.OrdinalIgnoreCase))
                     .ToList();
         }
+
+        public async Task<List<LocalItem>> GetCachedItemsBySyncJobItemId(SyncTarget target, string serverId, string syncJobItemId)
+        {
+            var items = await GetCachedData().ConfigureAwait(false);
+
+            return items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.SyncJobItemId, syncJobItemId, StringComparison.OrdinalIgnoreCase))
+                    .ToList();
+        }
     }
 }

+ 2 - 2
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.609</version>
+        <version>3.0.611</version>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Emby 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.609" />
+            <dependency id="MediaBrowser.Common" version="3.0.611" />
             <dependency id="NLog" version="3.2.0.0" />
             <dependency id="SimpleInjector" version="2.7.0" />
         </dependencies>

+ 1 - 1
Nuget/MediaBrowser.Common.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common</id>
-        <version>3.0.609</version>
+        <version>3.0.611</version>
         <title>MediaBrowser.Common</title>
         <authors>Emby Team</authors>
         <owners>ebr,Luke,scottisafool</owners>

+ 1 - 1
Nuget/MediaBrowser.Model.Signed.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Model.Signed</id>
-        <version>3.0.609</version>
+        <version>3.0.611</version>
         <title>MediaBrowser.Model - Signed Edition</title>
         <authors>Emby Team</authors>
         <owners>ebr,Luke,scottisafool</owners>

+ 2 - 2
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.609</version>
+        <version>3.0.611</version>
         <title>Media Browser.Server.Core</title>
         <authors>Emby Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Emby Server.</description>
         <copyright>Copyright © Emby 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.609" />
+            <dependency id="MediaBrowser.Common" version="3.0.611" />
         </dependencies>
     </metadata>
     <files>