diff --git a/MediaBrowser.Api/LiveTv/LiveTvImageService.cs b/MediaBrowser.Api/LiveTv/LiveTvImageService.cs index f58d4a533..65c4e5e23 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvImageService.cs +++ b/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); diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs index 9bc37fcc0..cdc9c76c8 100644 --- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs @@ -42,5 +42,12 @@ namespace MediaBrowser.Controller.LiveTv /// /// The image URL. public string ImageUrl { get; set; } + + /// + /// Gets or sets a value indicating whether this instance has image. + /// + /// null if [has image] contains no value, true if [has image]; otherwise, false. + public bool? HasImage { get; set; } + } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index e7226e9b5..40cc4bae5 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -24,13 +24,6 @@ namespace MediaBrowser.Controller.LiveTv /// The services. IReadOnlyList Services { get; } - /// - /// Schedules the recording. - /// - /// The program identifier. - /// Task. - Task ScheduleRecording(string programId); - /// /// Gets the new timer defaults asynchronous. /// @@ -146,6 +139,13 @@ namespace MediaBrowser.Controller.LiveTv /// Channel. LiveTvChannel GetInternalChannel(string id); + /// + /// Gets the internal program. + /// + /// The identifier. + /// LiveTvProgram. + LiveTvProgram GetInternalProgram(string id); + /// /// Gets the recording. /// diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs index 1c88629f0..3a6cbf583 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs +++ b/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 /// The cancellation token. /// Task{IEnumerable{ProgramInfo}}. Task> GetProgramsAsync(string channelId, CancellationToken cancellationToken); + + /// + /// Gets the recording stream. + /// + /// The recording identifier. + /// The cancellation token. + /// Task{Stream}. + Task GetRecordingStream(string recordingId, CancellationToken cancellationToken); + + /// + /// Gets the channel stream. + /// + /// The recording identifier. + /// The cancellation token. + /// Task{Stream}. + Task GetChannelStream(string recordingId, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs index e1382657d..671c4b591 100644 --- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs +++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs @@ -157,6 +157,12 @@ namespace MediaBrowser.Controller.LiveTv /// true if this instance is premiere; otherwise, false. public bool IsPremiere { get; set; } + /// + /// Gets or sets a value indicating whether this instance has image. + /// + /// null if [has image] contains no value, true if [has image]; otherwise, false. + public bool? HasImage { get; set; } + public ProgramInfo() { Genres = new List(); diff --git a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs index afdcec1f9..2004536af 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingInfo.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingInfo.cs @@ -11,6 +11,12 @@ namespace MediaBrowser.Controller.LiveTv /// public string Id { get; set; } + /// + /// Gets or sets the series timer identifier. + /// + /// The series timer identifier. + public string SeriesTimerId { get; set; } + /// /// ChannelId of the recording. /// @@ -167,6 +173,13 @@ namespace MediaBrowser.Controller.LiveTv /// The image URL. public string ImageUrl { get; set; } + /// + /// Gets or sets a value indicating whether this instance has image. + /// + /// null if [has image] contains no value, true if [has image]; otherwise, false. + public bool? HasImage { get; set; } + + public RecordingInfo() { Genres = new List(); diff --git a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs index e686fd9c4..3cf44f5c4 100644 --- a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs @@ -12,6 +12,12 @@ namespace MediaBrowser.Model.LiveTv /// public string Id { get; set; } + /// + /// Gets or sets the series timer identifier. + /// + /// The series timer identifier. + public string SeriesTimerId { get; set; } + /// /// Gets or sets the external identifier. /// diff --git a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs index dfca78e79..507ba0947 100644 --- a/MediaBrowser.Model/LiveTv/TimerInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/TimerInfoDto.cs @@ -122,5 +122,11 @@ namespace MediaBrowser.Model.LiveTv /// /// The priority. public int Priority { get; set; } + + /// + /// Gets or sets the program information. + /// + /// The program information. + public ProgramInfoDto ProgramInfo { get; set; } } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 589f8c9f0..e54c0af55 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/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"); diff --git a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs index 3d0cdd33f..d04ebe32d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs +++ b/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 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); + try + { + var response = await service.GetChannelImageAsync(channelInfo.Id, cancellationToken).ConfigureAwait(false); - imageStream = response.Stream; - contentType = response.MimeType; + 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 diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 5465b70da..b493fd15a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/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, diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 25b0bb222..c8067beae 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -36,8 +36,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly List _services = new List(); - private List _channels = new List(); - private List _programs = new List(); + private Dictionary _channels = new Dictionary(); + private Dictionary _programs = new Dictionary(); 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 channels = _channels; + IEnumerable 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 GetInternalRecording(string id, CancellationToken cancellationToken) @@ -249,8 +262,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task 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> GetPrograms(ProgramQuery query, CancellationToken cancellationToken) { - IEnumerable programs = _programs; + IEnumerable 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>> 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> GetTimers(TimerQuery query, CancellationToken cancellationToken) { - var list = new List(); - - 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 @@ -590,8 +597,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv public Task 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); diff --git a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs index 2286e3ac5..7c343f77c 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs +++ b/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 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); + try + { + var response = await service.GetProgramImageAsync(programInfo.Id, programInfo.ChannelId, cancellationToken).ConfigureAwait(false); - imageStream = response.Stream; - contentType = response.MimeType; + 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 diff --git a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs index a25dfe538..0b5ec285e 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs +++ b/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 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); + try + { + var response = await service.GetRecordingImageAsync(recordingInfo.Id, cancellationToken).ConfigureAwait(false); - imageStream = response.Stream; - contentType = response.MimeType; + 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 diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 084a9da1f..057fcc92e 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.285 + 3.0.288 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index e9eb11a92..00f1fc20f 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.285 + 3.0.288 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 423091830..f624c3e03 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.285 + 3.0.288 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - +