浏览代码

live tv updates

Luke Pulverenti 11 年之前
父节点
当前提交
f20f3b4b68

+ 7 - 0
MediaBrowser.Api/LiveTv/LiveTvImageService.cs

@@ -152,6 +152,13 @@ namespace MediaBrowser.Api.LiveTv
             return GetImageService().GetImage(request, item);
         }
 
+        public object Get(GetProgramImage request)
+        {
+            var item = _liveTv.GetInternalProgram(request.Id);
+
+            return GetImageService().GetImage(request, item);
+        }
+
         public void Post(PostChannelImage request)
         {
             var pathInfo = PathInfo.Parse(Request.PathInfo);

+ 7 - 0
MediaBrowser.Controller/LiveTv/ChannelInfo.cs

@@ -42,5 +42,12 @@ namespace MediaBrowser.Controller.LiveTv
         /// </summary>
         /// <value>The image URL.</value>
         public string ImageUrl { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance has image.
+        /// </summary>
+        /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
+        public bool? HasImage { get; set; }
+
     }
 }

+ 7 - 7
MediaBrowser.Controller/LiveTv/ILiveTvManager.cs

@@ -24,13 +24,6 @@ namespace MediaBrowser.Controller.LiveTv
         /// <value>The services.</value>
         IReadOnlyList<ILiveTvService> Services { get; }
 
-        /// <summary>
-        /// Schedules the recording.
-        /// </summary>
-        /// <param name="programId">The program identifier.</param>
-        /// <returns>Task.</returns>
-        Task ScheduleRecording(string programId);
-
         /// <summary>
         /// Gets the new timer defaults asynchronous.
         /// </summary>
@@ -146,6 +139,13 @@ namespace MediaBrowser.Controller.LiveTv
         /// <returns>Channel.</returns>
         LiveTvChannel GetInternalChannel(string id);
 
+        /// <summary>
+        /// Gets the internal program.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <returns>LiveTvProgram.</returns>
+        LiveTvProgram GetInternalProgram(string id);
+        
         /// <summary>
         /// Gets the recording.
         /// </summary>

+ 17 - 0
MediaBrowser.Controller/LiveTv/ILiveTvService.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -138,5 +139,21 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{IEnumerable{ProgramInfo}}.</returns>
         Task<IEnumerable<ProgramInfo>> GetProgramsAsync(string channelId, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Gets the recording stream.
+        /// </summary>
+        /// <param name="recordingId">The recording identifier.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{Stream}.</returns>
+        Task<Stream> GetRecordingStream(string recordingId, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Gets the channel stream.
+        /// </summary>
+        /// <param name="recordingId">The recording identifier.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{Stream}.</returns>
+        Task<Stream> GetChannelStream(string recordingId, CancellationToken cancellationToken);
     }
 }

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

@@ -157,6 +157,12 @@ namespace MediaBrowser.Controller.LiveTv
         /// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
         public bool IsPremiere { get; set;  }
 
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance has image.
+        /// </summary>
+        /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
+        public bool? HasImage { get; set; }
+
         public ProgramInfo()
         {
             Genres = new List<string>();

+ 13 - 0
MediaBrowser.Controller/LiveTv/RecordingInfo.cs

@@ -11,6 +11,12 @@ namespace MediaBrowser.Controller.LiveTv
         /// </summary>
         public string Id { get; set; }
 
+        /// <summary>
+        /// Gets or sets the series timer identifier.
+        /// </summary>
+        /// <value>The series timer identifier.</value>
+        public string SeriesTimerId { get; set; }
+        
         /// <summary>
         /// ChannelId of the recording.
         /// </summary>
@@ -167,6 +173,13 @@ namespace MediaBrowser.Controller.LiveTv
         /// <value>The image URL.</value>
         public string ImageUrl { get; set; }
 
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance has image.
+        /// </summary>
+        /// <value><c>null</c> if [has image] contains no value, <c>true</c> if [has image]; otherwise, <c>false</c>.</value>
+        public bool? HasImage { get; set; }
+
+
         public RecordingInfo()
         {
             Genres = new List<string>();

+ 6 - 0
MediaBrowser.Model/LiveTv/RecordingInfoDto.cs

@@ -12,6 +12,12 @@ namespace MediaBrowser.Model.LiveTv
         /// </summary>
         public string Id { get; set; }
 
+        /// <summary>
+        /// Gets or sets the series timer identifier.
+        /// </summary>
+        /// <value>The series timer identifier.</value>
+        public string SeriesTimerId { get; set; }
+        
         /// <summary>
         /// Gets or sets the external identifier.
         /// </summary>

+ 6 - 0
MediaBrowser.Model/LiveTv/TimerInfoDto.cs

@@ -122,5 +122,11 @@ namespace MediaBrowser.Model.LiveTv
         /// </summary>
         /// <value>The priority.</value>
         public int Priority { get; set; }
+
+        /// <summary>
+        /// Gets or sets the program information.
+        /// </summary>
+        /// <value>The program information.</value>
+        public ProgramInfoDto ProgramInfo { get; set; }
     }
 }

+ 1 - 1
MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs

@@ -179,7 +179,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
         private void SetProviderIdFromPath(Video item)
         {
             //we need to only look at the name of this actual item (not parents)
-            var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path) : Path.GetFileName(Path.GetDirectoryName(item.Path));
+            var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path) : Path.GetFileName(item.MetaLocation);
 
             var id = justName.GetAttributeValue("tmdbid");
 

+ 30 - 10
MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs

@@ -51,9 +51,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 return true;
             }
 
+            var changed = true;
+
             try
             {
-                await DownloadImage((LiveTvChannel)item, cancellationToken).ConfigureAwait(false);
+                changed = await DownloadImage((LiveTvChannel)item, cancellationToken).ConfigureAwait(false);
             }
             catch (HttpException ex)
             {
@@ -64,11 +66,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 }
             }
 
-            SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
-            return true;
+            if (changed)
+            {
+                SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
+            }
+
+            return changed;
         }
 
-        private async Task DownloadImage(LiveTvChannel item, CancellationToken cancellationToken)
+        private async Task<bool> DownloadImage(LiveTvChannel item, CancellationToken cancellationToken)
         {
             var channelInfo = item.ChannelInfo;
 
@@ -92,22 +98,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
                 if (!response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
                 {
-                    throw new InvalidOperationException("Provider did not return an image content type.");
+                    Logger.Error("Provider did not return an image content type.");
+                    return false;
                 }
 
                 imageStream = response.Content;
                 contentType = response.ContentType;
             }
-            else
+            else if (channelInfo.HasImage ?? true)
             {
                 var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, item.ServiceName, StringComparison.OrdinalIgnoreCase));
 
                 if (service != null)
                 {
-                    var response = await service.GetChannelImageAsync(channelInfo.Id, cancellationToken).ConfigureAwait(false);
-
-                    imageStream = response.Stream;
-                    contentType = response.MimeType;
+                    try
+                    {
+                        var response = await service.GetChannelImageAsync(channelInfo.Id, cancellationToken).ConfigureAwait(false);
+
+                        if (response != null)
+                        {
+                            imageStream = response.Stream;
+                            contentType = response.MimeType;
+                        }
+                    }
+                    catch (NotImplementedException)
+                    {
+                        return false;
+                    }
                 }
             }
 
@@ -117,7 +134,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 var url = item.ServiceName + channelInfo.Id;
 
                 await _providerManager.SaveImage(item, imageStream, contentType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false);
+                return true;
             }
+
+            return false;
         }
 
         public override MetadataProviderPriority Priority

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

@@ -30,7 +30,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             _logger = logger;
         }
 
-        public TimerInfoDto GetTimerInfoDto(TimerInfo info, ILiveTvService service)
+        public TimerInfoDto GetTimerInfoDto(TimerInfo info, ILiveTvService service, LiveTvProgram program)
         {
             var dto = new TimerInfoDto
             {
@@ -61,6 +61,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 dto.ProgramId = GetInternalProgramId(service.Name, info.ProgramId).ToString("N");
             }
 
+            if (program != null)
+            {
+                dto.ProgramInfo = GetProgramInfoDto(program);
+
+                dto.ProgramInfo.TimerId = dto.Id;
+                dto.ProgramInfo.SeriesTimerId = dto.SeriesTimerId;
+            }
+
             return dto;
         }
 
@@ -155,6 +163,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             var dto = new RecordingInfoDto
             {
                 Id = GetInternalRecordingId(service.Name, info.Id).ToString("N"),
+                SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) ? null : GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N"),
                 Type = recording.GetClientTypeName(),
                 ChannelName = info.ChannelName,
                 Overview = info.Overview,

+ 39 - 33
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -36,8 +36,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         private readonly List<ILiveTvService> _services = new List<ILiveTvService>();
 
-        private List<LiveTvChannel> _channels = new List<LiveTvChannel>();
-        private List<LiveTvProgram> _programs = new List<LiveTvProgram>();
+        private Dictionary<Guid, LiveTvChannel> _channels = new Dictionary<Guid, LiveTvChannel>();
+        private Dictionary<Guid, LiveTvProgram> _programs = new Dictionary<Guid, LiveTvProgram>();
 
         public LiveTvManager(IServerApplicationPaths appPaths, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, ILocalizationManager localization, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager)
         {
@@ -77,7 +77,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(new Guid(query.UserId));
 
-            IEnumerable<LiveTvChannel> channels = _channels;
+            IEnumerable<LiveTvChannel> channels = _channels.Values;
 
             if (user != null)
             {
@@ -125,7 +125,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
             var guid = new Guid(id);
 
-            return _channels.FirstOrDefault(i => i.Id == guid);
+            LiveTvChannel channel = null;
+
+            _channels.TryGetValue(guid, out channel);
+            return channel;
+        }
+
+        public LiveTvProgram GetInternalProgram(string id)
+        {
+            var guid = new Guid(id);
+
+            LiveTvProgram obj = null;
+
+            _programs.TryGetValue(guid, out obj);
+            return obj;
         }
 
         public async Task<LiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken)
@@ -249,8 +262,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public async Task<ProgramInfoDto> GetProgram(string id, CancellationToken cancellationToken, User user = null)
         {
-            var guid = new Guid(id);
-            var program = _programs.FirstOrDefault(i => guid == i.Id);
+            var program = GetInternalProgram(id);
 
             var dto = _tvDtoService.GetProgramInfoDto(program, user);
 
@@ -261,7 +273,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public async Task<QueryResult<ProgramInfoDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken)
         {
-            IEnumerable<LiveTvProgram> programs = _programs;
+            IEnumerable<LiveTvProgram> programs = _programs.Values;
 
             if (query.ChannelIdList.Length > 0)
             {
@@ -377,8 +389,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 progress.Report(90 * percent + 10);
             }
 
-            _programs = programs;
-            _channels = list;
+            _programs = programs.ToDictionary(i => i.Id);
+            _channels = list.ToDictionary(i => i.Id);
         }
 
         private async Task<IEnumerable<Tuple<string, ChannelInfo>>> GetChannels(ILiveTvService service, CancellationToken cancellationToken)
@@ -445,11 +457,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             if (string.IsNullOrEmpty(serviceName) && !string.IsNullOrEmpty(channelId))
             {
-                var channelIdGuid = new Guid(channelId);
+                var channel = GetInternalChannel(channelId);
 
-                serviceName = _channels.Where(i => i.Id == channelIdGuid)
-                    .Select(i => i.ServiceName)
-                    .FirstOrDefault();
+                if (channel != null)
+                {
+                    serviceName = channel.ServiceName;
+                }
             }
 
             if (!string.IsNullOrEmpty(serviceName))
@@ -460,31 +473,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return services;
         }
 
-        public Task ScheduleRecording(string programId)
-        {
-            throw new NotImplementedException();
-        }
-
         public async Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken)
         {
-            var list = new List<TimerInfoDto>();
-
-            if (ActiveService != null)
-            {
-                var timers = await ActiveService.GetTimersAsync(cancellationToken).ConfigureAwait(false);
-
-                var dtos = timers.Select(i => _tvDtoService.GetTimerInfoDto(i, ActiveService));
-
-                list.AddRange(dtos);
-            }
+            var service = ActiveService;
+            var timers = await service.GetTimersAsync(cancellationToken).ConfigureAwait(false);
 
             if (!string.IsNullOrEmpty(query.ChannelId))
             {
-                list = list.Where(i => string.Equals(i.ChannelId, query.ChannelId))
-                    .ToList();
+                var guid = new Guid(query.ChannelId);
+                timers = timers.Where(i => guid == _tvDtoService.GetInternalChannelId(service.Name, i.ChannelId, i.ChannelName));
             }
 
-            var returnArray = list.OrderBy(i => i.StartDate)
+            var returnArray = timers
+                .Select(i =>
+                {
+                    var program = string.IsNullOrEmpty(i.ProgramId) ? null : GetInternalProgram(_tvDtoService.GetInternalProgramId(service.Name, i.ProgramId).ToString("N"));
+
+                    return _tvDtoService.GetTimerInfoDto(i, ActiveService, program);
+                })
+                .OrderBy(i => i.StartDate)
                 .ToArray();
 
             return new QueryResult<TimerInfoDto>
@@ -590,8 +597,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public Task<ChannelInfoDto> GetChannel(string id, CancellationToken cancellationToken, User user = null)
         {
-            var guid = new Guid(id);
-            var channel = _channels.FirstOrDefault(i => guid == i.Id);
+            var channel = GetInternalChannel(id);
 
             var dto = _tvDtoService.GetChannelInfoDto(channel, user);
 

+ 30 - 10
MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs

@@ -51,9 +51,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 return true;
             }
 
+            var changed = true;
+
             try
             {
-                await DownloadImage((LiveTvProgram)item, cancellationToken).ConfigureAwait(false);
+                changed = await DownloadImage((LiveTvProgram)item, cancellationToken).ConfigureAwait(false);
             }
             catch (HttpException ex)
             {
@@ -64,11 +66,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 }
             }
 
-            SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
-            return true;
+            if (changed)
+            {
+                SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
+            }
+
+            return changed;
         }
 
-        private async Task DownloadImage(LiveTvProgram item, CancellationToken cancellationToken)
+        private async Task<bool> DownloadImage(LiveTvProgram item, CancellationToken cancellationToken)
         {
             var programInfo = item.ProgramInfo;
 
@@ -92,22 +98,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
                 if (!response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
                 {
-                    throw new InvalidOperationException("Provider did not return an image content type.");
+                    Logger.Error("Provider did not return an image content type.");
+                    return false;
                 }
 
                 imageStream = response.Content;
                 contentType = response.ContentType;
             }
-            else
+            else if (programInfo.HasImage ?? true)
             {
                 var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, item.ServiceName, StringComparison.OrdinalIgnoreCase));
 
                 if (service != null)
                 {
-                    var response = await service.GetProgramImageAsync(programInfo.Id, programInfo.ChannelId, cancellationToken).ConfigureAwait(false);
-
-                    imageStream = response.Stream;
-                    contentType = response.MimeType;
+                    try
+                    {
+                        var response = await service.GetProgramImageAsync(programInfo.Id, programInfo.ChannelId, cancellationToken).ConfigureAwait(false);
+
+                        if (response != null)
+                        {
+                            imageStream = response.Stream;
+                            contentType = response.MimeType;
+                        }
+                    }
+                    catch (NotImplementedException)
+                    {
+                        return false;
+                    }
                 }
             }
 
@@ -117,7 +134,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 var url = item.ServiceName + programInfo.Id;
 
                 await _providerManager.SaveImage(item, imageStream, contentType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false);
+                return true;
             }
+
+            return false;
         }
 
         public override MetadataProviderPriority Priority

+ 30 - 10
MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs

@@ -51,9 +51,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 return true;
             }
 
+            var changed = true;
+
             try
             {
-                await DownloadImage((LiveTvRecording)item, cancellationToken).ConfigureAwait(false);
+                changed = await DownloadImage((LiveTvRecording)item, cancellationToken).ConfigureAwait(false);
             }
             catch (HttpException ex)
             {
@@ -64,11 +66,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 }
             }
 
-            SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
-            return true;
+            if (changed)
+            {
+                SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
+            }
+
+            return changed;
         }
 
-        private async Task DownloadImage(LiveTvRecording item, CancellationToken cancellationToken)
+        private async Task<bool> DownloadImage(LiveTvRecording item, CancellationToken cancellationToken)
         {
             var recordingInfo = item.RecordingInfo;
 
@@ -92,22 +98,33 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
                 if (!response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
                 {
-                    throw new InvalidOperationException("Provider did not return an image content type.");
+                    Logger.Error("Provider did not return an image content type.");
+                    return false;
                 }
 
                 imageStream = response.Content;
                 contentType = response.ContentType;
             }
-            else
+            else if (recordingInfo.HasImage ?? true)
             {
                 var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, item.ServiceName, StringComparison.OrdinalIgnoreCase));
 
                 if (service != null)
                 {
-                    var response = await service.GetRecordingImageAsync(recordingInfo.Id, cancellationToken).ConfigureAwait(false);
-
-                    imageStream = response.Stream;
-                    contentType = response.MimeType;
+                    try
+                    {
+                        var response = await service.GetRecordingImageAsync(recordingInfo.Id, cancellationToken).ConfigureAwait(false);
+
+                        if (response != null)
+                        {
+                            imageStream = response.Stream;
+                            contentType = response.MimeType;
+                        }
+                    }
+                    catch (NotImplementedException)
+                    {
+                        return false;
+                    }
                 }
             }
 
@@ -117,7 +134,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 var url = item.ServiceName + recordingInfo.Id;
 
                 await _providerManager.SaveImage(item, imageStream, contentType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false);
+                return true;
             }
+
+            return false;
         }
 
         public override MetadataProviderPriority Priority

+ 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.285</version>
+        <version>3.0.288</version>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.285" />
+            <dependency id="MediaBrowser.Common" version="3.0.288" />
             <dependency id="NLog" version="2.1.0" />
             <dependency id="SimpleInjector" version="2.4.0" />
             <dependency id="sharpcompress" version="0.10.2" />

+ 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.285</version>
+        <version>3.0.288</version>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser 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.285</version>
+        <version>3.0.288</version>
         <title>Media Browser.Server.Core</title>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.285" />
+            <dependency id="MediaBrowser.Common" version="3.0.288" />
         </dependencies>
     </metadata>
     <files>