diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2013-12-19 16:51:32 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2013-12-19 16:51:32 -0500 |
| commit | cd859ac2e6d499ce2cdf531058e64a4c3402910f (patch) | |
| tree | e453d21e99ef2d6aee7f5e4af668a69147b31dfd /MediaBrowser.Server.Implementations | |
| parent | e1e5d354345008e8d4ddc2dbbb99a68df4133280 (diff) | |
added IHasImages and IHasUserData
Diffstat (limited to 'MediaBrowser.Server.Implementations')
11 files changed, 516 insertions, 121 deletions
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs index 36b6e5a90..fbe78e938 100644 --- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs +++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs @@ -594,7 +594,7 @@ namespace MediaBrowser.Server.Implementations.Drawing /// <param name="imagePath">The image path.</param> /// <returns>Guid.</returns> /// <exception cref="System.ArgumentNullException">item</exception> - public Guid GetImageCacheTag(BaseItem item, ImageType imageType, string imagePath) + public Guid GetImageCacheTag(IHasImages item, ImageType imageType, string imagePath) { if (item == null) { @@ -623,7 +623,7 @@ namespace MediaBrowser.Server.Implementations.Drawing /// <param name="imageEnhancers">The image enhancers.</param> /// <returns>Guid.</returns> /// <exception cref="System.ArgumentNullException">item</exception> - public Guid GetImageCacheTag(BaseItem item, ImageType imageType, string originalImagePath, DateTime dateModified, List<IImageEnhancer> imageEnhancers) + public Guid GetImageCacheTag(IHasImages item, ImageType imageType, string originalImagePath, DateTime dateModified, List<IImageEnhancer> imageEnhancers) { if (item == null) { @@ -660,7 +660,7 @@ namespace MediaBrowser.Server.Implementations.Drawing /// <param name="imageType">Type of the image.</param> /// <param name="imageIndex">Index of the image.</param> /// <returns>Task{System.String}.</returns> - public async Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex) + public async Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex) { var enhancers = GetSupportedEnhancers(item, imageType).ToList(); @@ -673,7 +673,7 @@ namespace MediaBrowser.Server.Implementations.Drawing return result.Item1; } - private async Task<Tuple<string, DateTime>> GetEnhancedImage(string originalImagePath, DateTime dateModified, BaseItem item, + private async Task<Tuple<string, DateTime>> GetEnhancedImage(string originalImagePath, DateTime dateModified, IHasImages item, ImageType imageType, int imageIndex, List<IImageEnhancer> enhancers) { @@ -709,7 +709,7 @@ namespace MediaBrowser.Server.Implementations.Drawing /// <param name="supportedEnhancers">The supported enhancers.</param> /// <returns>System.String.</returns> /// <exception cref="System.ArgumentNullException">originalImagePath</exception> - private async Task<string> GetEnhancedImageInternal(string originalImagePath, DateTime dateModified, BaseItem item, ImageType imageType, int imageIndex, List<IImageEnhancer> supportedEnhancers) + private async Task<string> GetEnhancedImageInternal(string originalImagePath, DateTime dateModified, IHasImages item, ImageType imageType, int imageIndex, List<IImageEnhancer> supportedEnhancers) { if (string.IsNullOrEmpty(originalImagePath)) { @@ -782,7 +782,7 @@ namespace MediaBrowser.Server.Implementations.Drawing /// <param name="imageType">Type of the image.</param> /// <param name="imageIndex">Index of the image.</param> /// <returns>Task{EnhancedImage}.</returns> - private async Task<Image> ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, Image originalImage, BaseItem item, ImageType imageType, int imageIndex) + private async Task<Image> ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, Image originalImage, IHasImages item, ImageType imageType, int imageIndex) { var result = originalImage; @@ -900,7 +900,7 @@ namespace MediaBrowser.Server.Implementations.Drawing return Path.Combine(path, filename); } - public IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType) + public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType) { return ImageEnhancers.Where(i => { diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 14496d362..1060886a8 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -818,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.ParentLogoItemId = GetDtoId(parentWithLogo); - dto.ParentLogoImageTag = GetImageCacheTag(parentWithLogo, ImageType.Logo, parentWithLogo.GetImage(ImageType.Logo)); + dto.ParentLogoImageTag = GetImageCacheTag(parentWithLogo, ImageType.Logo, parentWithLogo.GetImagePath(ImageType.Logo)); } } @@ -831,7 +831,7 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.ParentArtItemId = GetDtoId(parentWithImage); - dto.ParentArtImageTag = GetImageCacheTag(parentWithImage, ImageType.Art, parentWithImage.GetImage(ImageType.Art)); + dto.ParentArtImageTag = GetImageCacheTag(parentWithImage, ImageType.Art, parentWithImage.GetImagePath(ImageType.Art)); } } @@ -844,7 +844,7 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.ParentThumbItemId = GetDtoId(parentWithImage); - dto.ParentThumbImageTag = GetImageCacheTag(parentWithImage, ImageType.Thumb, parentWithImage.GetImage(ImageType.Thumb)); + dto.ParentThumbImageTag = GetImageCacheTag(parentWithImage, ImageType.Thumb, parentWithImage.GetImagePath(ImageType.Thumb)); } } @@ -1037,7 +1037,7 @@ namespace MediaBrowser.Server.Implementations.Dto if (series.HasImage(ImageType.Thumb)) { - dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb, series.GetImage(ImageType.Thumb)); + dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb, series.GetImagePath(ImageType.Thumb)); } var imagePath = series.PrimaryImagePath; diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index 8d010aecc..79f126511 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -49,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.Library /// userId /// or /// key</exception> - public async Task SaveUserData(Guid userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken) + public async Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken) { if (userData == null) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs index 4a8b2d638..3d0cdd33f 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -21,18 +22,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly ILiveTvManager _liveTvManager; private readonly IProviderManager _providerManager; private readonly IFileSystem _fileSystem; + private readonly IHttpClient _httpClient; - public ChannelImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, ILiveTvManager liveTvManager, IProviderManager providerManager, IFileSystem fileSystem) + public ChannelImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, ILiveTvManager liveTvManager, IProviderManager providerManager, IFileSystem fileSystem, IHttpClient httpClient) : base(logManager, configurationManager) { _liveTvManager = liveTvManager; _providerManager = providerManager; _fileSystem = fileSystem; + _httpClient = httpClient; } public override bool Supports(BaseItem item) { - return item is Channel; + return item is LiveTvChannel; } protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) @@ -48,21 +51,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv return true; } - var channel = (Channel)item; - - if (channel.HasProviderImage ?? true) + try { - try - { - await DownloadImage(item, cancellationToken).ConfigureAwait(false); - } - catch (HttpException ex) + await DownloadImage((LiveTvChannel)item, cancellationToken).ConfigureAwait(false); + } + catch (HttpException ex) + { + // Don't fail the provider on a 404 + if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound) { - // Don't fail the provider on a 404 - if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound) - { - throw; - } + throw; } } @@ -70,20 +68,55 @@ namespace MediaBrowser.Server.Implementations.LiveTv return true; } - private async Task DownloadImage(BaseItem item, CancellationToken cancellationToken) + private async Task DownloadImage(LiveTvChannel item, CancellationToken cancellationToken) { - var channel = (Channel)item; + var channelInfo = item.ChannelInfo; - var service = _liveTvManager.Services.FirstOrDefault(i => string.Equals(i.Name, channel.ServiceName, StringComparison.OrdinalIgnoreCase)); + Stream imageStream = null; + string contentType = null; - if (service != null) + if (!string.IsNullOrEmpty(channelInfo.ImagePath)) { - var response = await service.GetChannelImageAsync(channel.ChannelId, cancellationToken).ConfigureAwait(false); + contentType = "image/" + Path.GetExtension(channelInfo.ImagePath).ToLower(); + imageStream = _fileSystem.GetFileStream(channelInfo.ImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true); + } + else if (!string.IsNullOrEmpty(channelInfo.ImageUrl)) + { + var options = new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = channelInfo.ImageUrl + }; + + var response = await _httpClient.GetResponse(options).ConfigureAwait(false); + if (!response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("Provider did not return an image content type."); + } + + imageStream = response.Content; + contentType = response.ContentType; + } + else + { + 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; + } + } + + if (imageStream != null) + { // Dummy up the original url - var url = channel.ServiceName + channel.ChannelId; + var url = item.ServiceName + channelInfo.Id; - await _providerManager.SaveImage(channel, response.Stream, response.MimeType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false); + await _providerManager.SaveImage(item, imageStream, contentType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false); } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index a58722c32..3d18e9837 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -135,11 +135,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv return pattern; } - public RecordingInfoDto GetRecordingInfoDto(RecordingInfo info, ILiveTvService service, User user = null) + /// <summary> + /// Convert the provider 0-5 scale to our 0-10 scale + /// </summary> + /// <param name="val"></param> + /// <returns></returns> + private float? GetClientCommunityRating(float? val) + { + if (!val.HasValue) + { + return null; + } + + return val.Value * 2; + } + + public RecordingInfoDto GetRecordingInfoDto(LiveTvRecording recording, ILiveTvService service, User user = null) { + var info = recording.RecordingInfo; + var dto = new RecordingInfoDto { Id = GetInternalRecordingId(service.Name, info.Id).ToString("N"), + Type = recording.GetClientTypeName(), ChannelName = info.ChannelName, Overview = info.Overview, EndDate = info.EndDate, @@ -154,7 +172,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv EpisodeTitle = info.EpisodeTitle, ChannelType = info.ChannelType, MediaType = info.ChannelType == ChannelType.Radio ? MediaType.Audio : MediaType.Video, - CommunityRating = info.CommunityRating, + CommunityRating = GetClientCommunityRating(info.CommunityRating), OfficialRating = info.OfficialRating, Audio = info.Audio, IsHD = info.IsHD, @@ -162,9 +180,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv Url = info.Url }; + var imageTag = GetImageTag(recording); + + if (imageTag.HasValue) + { + dto.ImageTags[ImageType.Primary] = imageTag.Value; + } + if (user != null) { - //dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, info.GetUserDataKey())); + dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, recording.GetUserDataKey())); } var duration = info.EndDate - info.StartDate; @@ -184,18 +209,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv /// <param name="info">The info.</param> /// <param name="user">The user.</param> /// <returns>ChannelInfoDto.</returns> - public ChannelInfoDto GetChannelInfoDto(Channel info, User user = null) + public ChannelInfoDto GetChannelInfoDto(LiveTvChannel info, User user = null) { + var channelInfo = info.ChannelInfo; + var dto = new ChannelInfoDto { Name = info.Name, ServiceName = info.ServiceName, - ChannelType = info.ChannelType, - Number = info.ChannelNumber, - Type = info.GetType().Name, + ChannelType = channelInfo.ChannelType, + Number = channelInfo.Number, + Type = info.GetClientTypeName(), Id = info.Id.ToString("N"), MediaType = info.MediaType, - ExternalId = info.ChannelId + ExternalId = channelInfo.Id }; if (user != null) @@ -203,7 +230,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, info.GetUserDataKey())); } - var imageTag = GetLogoImageTag(info); + var imageTag = GetImageTag(info); if (imageTag.HasValue) { @@ -213,7 +240,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return dto; } - public ProgramInfoDto GetProgramInfoDto(ProgramInfo program, Channel channel, User user = null) + public ProgramInfoDto GetProgramInfoDto(ProgramInfo program, LiveTvChannel channel, User user = null) { var dto = new ProgramInfoDto { @@ -230,7 +257,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv IsHD = program.IsHD, OriginalAirDate = program.OriginalAirDate, Audio = program.Audio, - CommunityRating = program.CommunityRating, + CommunityRating = GetClientCommunityRating(program.CommunityRating), AspectRatio = program.AspectRatio, IsRepeat = program.IsRepeat, EpisodeTitle = program.EpisodeTitle, @@ -248,7 +275,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv return dto; } - private Guid? GetLogoImageTag(Channel info) + private Guid? GetImageTag(BaseItem info) { var path = info.PrimaryImagePath; @@ -263,7 +290,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv } catch (Exception ex) { - _logger.ErrorException("Error getting channel image info for {0}", ex, info.Name); + _logger.ErrorException("Error getting image info for {0}", ex, info.Name); } return null; @@ -273,7 +300,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var name = serviceName + externalId + channelName; - return name.ToLower().GetMBId(typeof(Channel)); + return name.ToLower().GetMBId(typeof(LiveTvChannel)); } public Guid GetInternalTimerId(string serviceName, string externalId) @@ -314,41 +341,53 @@ namespace MediaBrowser.Server.Implementations.LiveTv Name = dto.Name, StartDate = dto.StartDate, Status = dto.Status, - SeriesTimerId = dto.ExternalSeriesTimerId, PrePaddingSeconds = dto.PrePaddingSeconds, PostPaddingSeconds = dto.PostPaddingSeconds, IsPostPaddingRequired = dto.IsPostPaddingRequired, IsPrePaddingRequired = dto.IsPrePaddingRequired, - Priority = dto.Priority + Priority = dto.Priority, + SeriesTimerId = dto.ExternalSeriesTimerId, + ProgramId = dto.ExternalProgramId, + ChannelId = dto.ExternalChannelId, + Id = dto.ExternalId }; // Convert internal server id's to external tv provider id's - if (!isNew && !string.IsNullOrEmpty(dto.Id)) + if (!isNew && !string.IsNullOrEmpty(dto.Id) && string.IsNullOrEmpty(info.Id)) { - var timer = await liveTv.GetTimer(dto.Id, cancellationToken).ConfigureAwait(false); + var timer = await liveTv.GetSeriesTimer(dto.Id, cancellationToken).ConfigureAwait(false); info.Id = timer.ExternalId; } - if (!string.IsNullOrEmpty(dto.SeriesTimerId)) + if (!string.IsNullOrEmpty(dto.ChannelId) && string.IsNullOrEmpty(info.ChannelId)) { - var timer = await liveTv.GetSeriesTimer(dto.SeriesTimerId, cancellationToken).ConfigureAwait(false); + var channel = await liveTv.GetChannel(dto.ChannelId, cancellationToken).ConfigureAwait(false); - info.SeriesTimerId = timer.ExternalId; + if (channel != null) + { + info.ChannelId = channel.ExternalId; + } } - if (!string.IsNullOrEmpty(dto.ChannelId)) + if (!string.IsNullOrEmpty(dto.ProgramId) && string.IsNullOrEmpty(info.ProgramId)) { - var channel = await liveTv.GetChannel(dto.ChannelId, cancellationToken).ConfigureAwait(false); + var program = await liveTv.GetProgram(dto.ProgramId, cancellationToken).ConfigureAwait(false); - info.ChannelId = channel.ExternalId; + if (program != null) + { + info.ProgramId = program.ExternalId; + } } - if (!string.IsNullOrEmpty(dto.ProgramId)) + if (!string.IsNullOrEmpty(dto.SeriesTimerId) && string.IsNullOrEmpty(info.SeriesTimerId)) { - var program = await liveTv.GetProgram(dto.ProgramId, cancellationToken).ConfigureAwait(false); + var timer = await liveTv.GetSeriesTimer(dto.SeriesTimerId, cancellationToken).ConfigureAwait(false); - info.ProgramId = program.ExternalId; + if (timer != null) + { + info.SeriesTimerId = timer.ExternalId; + } } return info; @@ -371,29 +410,38 @@ namespace MediaBrowser.Server.Implementations.LiveTv Priority = dto.Priority, RecordAnyChannel = dto.RecordAnyChannel, RecordAnyTime = dto.RecordAnyTime, - RecordNewOnly = dto.RecordNewOnly + RecordNewOnly = dto.RecordNewOnly, + ProgramId = dto.ExternalProgramId, + ChannelId = dto.ExternalChannelId, + Id = dto.ExternalId }; // Convert internal server id's to external tv provider id's - if (!isNew && !string.IsNullOrEmpty(dto.Id)) + if (!isNew && !string.IsNullOrEmpty(dto.Id) && string.IsNullOrEmpty(info.Id)) { var timer = await liveTv.GetSeriesTimer(dto.Id, cancellationToken).ConfigureAwait(false); info.Id = timer.ExternalId; } - if (!string.IsNullOrEmpty(dto.ChannelId)) + if (!string.IsNullOrEmpty(dto.ChannelId) && string.IsNullOrEmpty(info.ChannelId)) { var channel = await liveTv.GetChannel(dto.ChannelId, cancellationToken).ConfigureAwait(false); - info.ChannelId = channel.ExternalId; + if (channel != null) + { + info.ChannelId = channel.ExternalId; + } } - if (!string.IsNullOrEmpty(dto.ProgramId)) + if (!string.IsNullOrEmpty(dto.ProgramId) && string.IsNullOrEmpty(info.ProgramId)) { var program = await liveTv.GetProgram(dto.ProgramId, cancellationToken).ConfigureAwait(false); - info.ProgramId = program.ExternalId; + if (program != null) + { + info.ProgramId = program.ExternalId; + } } return info; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 06ed4e200..06e6fbe15 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly List<ILiveTvService> _services = new List<ILiveTvService>(); - private List<Channel> _channels = new List<Channel>(); + private List<LiveTvChannel> _channels = new List<LiveTvChannel>(); private List<ProgramInfoDto> _programs = new List<ProgramInfoDto>(); public LiveTvManager(IServerApplicationPaths appPaths, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, ILocalizationManager localization, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager) @@ -77,18 +77,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(new Guid(query.UserId)); - IEnumerable<Channel> channels = _channels; + IEnumerable<LiveTvChannel> channels = _channels; if (user != null) { - channels = channels.Where(i => i.IsParentalAllowed(user, _localization)) + channels = channels + .Where(i => i.IsParentalAllowed(user, _localization)) .OrderBy(i => { double number = 0; - if (!string.IsNullOrEmpty(i.ChannelNumber)) + if (!string.IsNullOrEmpty(i.ChannelInfo.Number)) { - double.TryParse(i.ChannelNumber, out number); + double.TryParse(i.ChannelInfo.Number, out number); } return number; @@ -100,9 +101,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv { double number = 0; - if (!string.IsNullOrEmpty(i.ChannelNumber)) + if (!string.IsNullOrEmpty(i.ChannelInfo.Number)) { - double.TryParse(i.ChannelNumber, out number); + double.TryParse(i.ChannelInfo.Number, out number); } return number; @@ -120,14 +121,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv return Task.FromResult(result); } - public Channel GetChannel(string id) + public LiveTvChannel GetInternalChannel(string id) { var guid = new Guid(id); return _channels.FirstOrDefault(i => i.Id == guid); } - private async Task<Channel> GetChannel(ChannelInfo channelInfo, string serviceName, CancellationToken cancellationToken) + public async Task<LiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken) + { + var service = ActiveService; + + var recordings = await service.GetRecordingsAsync(cancellationToken).ConfigureAwait(false); + + var recording = recordings.FirstOrDefault(i => _tvDtoService.GetInternalRecordingId(service.Name, i.Id) == new Guid(id)); + + return await GetRecording(recording, service.Name, cancellationToken).ConfigureAwait(false); + } + + private async Task<LiveTvChannel> GetChannel(ChannelInfo channelInfo, string serviceName, CancellationToken cancellationToken) { var path = Path.Combine(_appPaths.ItemsByNamePath, "channels", _fileSystem.GetValidFilename(serviceName), _fileSystem.GetValidFilename(channelInfo.Name)); @@ -150,26 +162,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv var id = _tvDtoService.GetInternalChannelId(serviceName, channelInfo.Id, channelInfo.Name); - var item = _itemRepo.RetrieveItem(id) as Channel; + var item = _itemRepo.RetrieveItem(id) as LiveTvChannel; if (item == null) { - item = new Channel + item = new LiveTvChannel { Name = channelInfo.Name, Id = id, DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo), DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo), - Path = path, - ChannelId = channelInfo.Id, - ChannelNumber = channelInfo.Number, - ServiceName = serviceName, - HasProviderImage = channelInfo.HasImage + Path = path }; isNew = true; } + item.ChannelInfo = channelInfo; + item.ServiceName = serviceName; + // Set this now so we don't cause additional file system access during provider executions item.ResetResolveArgs(fileInfo); @@ -178,6 +189,35 @@ namespace MediaBrowser.Server.Implementations.LiveTv return item; } + private async Task<LiveTvRecording> GetRecording(RecordingInfo info, string serviceName, CancellationToken cancellationToken) + { + var isNew = false; + + var id = _tvDtoService.GetInternalRecordingId(serviceName, info.Id); + + var item = _itemRepo.RetrieveItem(id) as LiveTvRecording; + + if (item == null) + { + item = new LiveTvRecording + { + Name = info.Name, + Id = id, + DateCreated = DateTime.UtcNow, + DateModified = DateTime.UtcNow + }; + + isNew = true; + } + + item.RecordingInfo = info; + item.ServiceName = serviceName; + + await item.RefreshMetadata(cancellationToken, forceSave: isNew, resetResolveArgs: false); + + return item; + } + public Task<ProgramInfoDto> GetProgram(string id, CancellationToken cancellationToken, User user = null) { var program = _programs.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase)); @@ -225,7 +265,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var allChannels = await GetChannels(service, cancellationToken).ConfigureAwait(false); var allChannelsList = allChannels.ToList(); - var list = new List<Channel>(); + var list = new List<LiveTvChannel>(); var programs = new List<ProgramInfoDto>(); var numComplete = 0; @@ -271,26 +311,34 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task<QueryResult<RecordingInfoDto>> GetRecordings(RecordingQuery query, CancellationToken cancellationToken) { - var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(new Guid(query.UserId)); + var service = ActiveService; - var list = new List<RecordingInfoDto>(); + var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(new Guid(query.UserId)); - if (ActiveService != null) - { - var recordings = await ActiveService.GetRecordingsAsync(cancellationToken).ConfigureAwait(false); + var list = new List<RecordingInfo>(); - var dtos = recordings.Select(i => _tvDtoService.GetRecordingInfoDto(i, ActiveService, user)); + var recordings = await service.GetRecordingsAsync(cancellationToken).ConfigureAwait(false); + list.AddRange(recordings); - list.AddRange(dtos); + if (!string.IsNullOrEmpty(query.ChannelId)) + { + list = list + .Where(i => _tvDtoService.GetInternalChannelId(service.Name, i.ChannelId, i.ChannelName) == new Guid(query.ChannelId)) + .ToList(); } - if (!string.IsNullOrEmpty(query.ChannelId)) + if (!string.IsNullOrEmpty(query.Id)) { - list = list.Where(i => string.Equals(i.ChannelId, query.ChannelId)) + list = list + .Where(i => _tvDtoService.GetInternalRecordingId(service.Name, i.Id) == new Guid(query.Id)) .ToList(); } - var returnArray = list.OrderByDescending(i => i.StartDate) + var entities = await GetEntities(list, service.Name, cancellationToken).ConfigureAwait(false); + + var returnArray = entities + .Select(i => _tvDtoService.GetRecordingInfoDto(i, ActiveService, user)) + .OrderByDescending(i => i.StartDate) .ToArray(); return new QueryResult<RecordingInfoDto> @@ -300,6 +348,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv }; } + private Task<LiveTvRecording[]> GetEntities(IEnumerable<RecordingInfo> recordings, string serviceName, CancellationToken cancellationToken) + { + var tasks = recordings.Select(i => GetRecording(i, serviceName, cancellationToken)); + + return Task.WhenAll(tasks); + } + private IEnumerable<ILiveTvService> GetServices(string serviceName, string channelId) { IEnumerable<ILiveTvService> services = _services; @@ -404,11 +459,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv { var results = await GetRecordings(new RecordingQuery { - UserId = user == null ? null : user.Id.ToString("N") + UserId = user == null ? null : user.Id.ToString("N"), + Id = id }, cancellationToken).ConfigureAwait(false); - return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.CurrentCulture)); + return results.Items.FirstOrDefault(); } public async Task<TimerInfoDto> GetTimer(string id, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs new file mode 100644 index 000000000..2286e3ac5 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs @@ -0,0 +1,136 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.LiveTv +{ + public class ProgramImageProvider : BaseMetadataProvider + { + private readonly ILiveTvManager _liveTvManager; + private readonly IProviderManager _providerManager; + private readonly IFileSystem _fileSystem; + private readonly IHttpClient _httpClient; + + public ProgramImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, ILiveTvManager liveTvManager, IProviderManager providerManager, IFileSystem fileSystem, IHttpClient httpClient) + : base(logManager, configurationManager) + { + _liveTvManager = liveTvManager; + _providerManager = providerManager; + _fileSystem = fileSystem; + _httpClient = httpClient; + } + + public override bool Supports(BaseItem item) + { + return item is LiveTvProgram; + } + + protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) + { + return !item.HasImage(ImageType.Primary); + } + + public override async Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken) + { + if (item.HasImage(ImageType.Primary)) + { + SetLastRefreshed(item, DateTime.UtcNow, providerInfo); + return true; + } + + try + { + await DownloadImage((LiveTvProgram)item, cancellationToken).ConfigureAwait(false); + } + catch (HttpException ex) + { + // Don't fail the provider on a 404 + if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound) + { + throw; + } + } + + SetLastRefreshed(item, DateTime.UtcNow, providerInfo); + return true; + } + + private async Task DownloadImage(LiveTvProgram item, CancellationToken cancellationToken) + { + var programInfo = item.ProgramInfo; + + Stream imageStream = null; + string contentType = null; + + if (!string.IsNullOrEmpty(programInfo.ImagePath)) + { + contentType = "image/" + Path.GetExtension(programInfo.ImagePath).ToLower(); + imageStream = _fileSystem.GetFileStream(programInfo.ImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true); + } + else if (!string.IsNullOrEmpty(programInfo.ImageUrl)) + { + var options = new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = programInfo.ImageUrl + }; + + var response = await _httpClient.GetResponse(options).ConfigureAwait(false); + + if (!response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("Provider did not return an image content type."); + } + + imageStream = response.Content; + contentType = response.ContentType; + } + else + { + 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; + } + } + + if (imageStream != null) + { + // Dummy up the original url + var url = item.ServiceName + programInfo.Id; + + await _providerManager.SaveImage(item, imageStream, contentType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false); + } + } + + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.Second; } + } + + public override ItemUpdateType ItemUpdateType + { + get + { + return ItemUpdateType.ImageUpdate; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs new file mode 100644 index 000000000..a25dfe538 --- /dev/null +++ b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs @@ -0,0 +1,136 @@ +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; + +namespace MediaBrowser.Server.Implementations.LiveTv +{ + public class RecordingImageProvider : BaseMetadataProvider + { + private readonly ILiveTvManager _liveTvManager; + private readonly IProviderManager _providerManager; + private readonly IFileSystem _fileSystem; + private readonly IHttpClient _httpClient; + + public RecordingImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, ILiveTvManager liveTvManager, IProviderManager providerManager, IFileSystem fileSystem, IHttpClient httpClient) + : base(logManager, configurationManager) + { + _liveTvManager = liveTvManager; + _providerManager = providerManager; + _fileSystem = fileSystem; + _httpClient = httpClient; + } + + public override bool Supports(BaseItem item) + { + return item is LiveTvRecording; + } + + protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) + { + return !item.HasImage(ImageType.Primary); + } + + public override async Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken) + { + if (item.HasImage(ImageType.Primary)) + { + SetLastRefreshed(item, DateTime.UtcNow, providerInfo); + return true; + } + + try + { + await DownloadImage((LiveTvRecording)item, cancellationToken).ConfigureAwait(false); + } + catch (HttpException ex) + { + // Don't fail the provider on a 404 + if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound) + { + throw; + } + } + + SetLastRefreshed(item, DateTime.UtcNow, providerInfo); + return true; + } + + private async Task DownloadImage(LiveTvRecording item, CancellationToken cancellationToken) + { + var recordingInfo = item.RecordingInfo; + + Stream imageStream = null; + string contentType = null; + + if (!string.IsNullOrEmpty(recordingInfo.ImagePath)) + { + contentType = "image/" + Path.GetExtension(recordingInfo.ImagePath).ToLower(); + imageStream = _fileSystem.GetFileStream(recordingInfo.ImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true); + } + else if (!string.IsNullOrEmpty(recordingInfo.ImageUrl)) + { + var options = new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = recordingInfo.ImageUrl + }; + + var response = await _httpClient.GetResponse(options).ConfigureAwait(false); + + if (!response.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException("Provider did not return an image content type."); + } + + imageStream = response.Content; + contentType = response.ContentType; + } + else + { + 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; + } + } + + if (imageStream != null) + { + // Dummy up the original url + var url = item.ServiceName + recordingInfo.Id; + + await _providerManager.SaveImage(item, imageStream, contentType, ImageType.Primary, null, url, cancellationToken).ConfigureAwait(false); + } + } + + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.Second; } + } + + public override ItemUpdateType ItemUpdateType + { + get + { + return ItemUpdateType.ImageUpdate; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 2516a3ae3..5a3a9ffe9 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -153,6 +153,8 @@ <Compile Include="LiveTv\ChannelImageProvider.cs" /> <Compile Include="LiveTv\LiveTvDtoService.cs" /> <Compile Include="LiveTv\LiveTvManager.cs" /> + <Compile Include="LiveTv\ProgramImageProvider.cs" /> + <Compile Include="LiveTv\RecordingImageProvider.cs" /> <Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" /> <Compile Include="Localization\LocalizationManager.cs" /> <Compile Include="MediaEncoder\MediaEncoder.cs" /> diff --git a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs index 49194ba8d..e24ed0000 100644 --- a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs +++ b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs @@ -118,6 +118,8 @@ namespace MediaBrowser.Server.Implementations.Providers imageIndex = hasScreenshots.ScreenshotImagePaths.Count; } + var index = imageIndex ?? 0; + var paths = GetSavePaths(item, type, imageIndex, mimeType, saveLocally); // If there are more than one output paths, the stream will need to be seekable @@ -132,7 +134,7 @@ namespace MediaBrowser.Server.Implementations.Providers source = memoryStream; } - var currentPath = GetCurrentImagePath(item, type, imageIndex); + var currentPath = GetCurrentImagePath(item, type, index); using (source) { @@ -152,7 +154,7 @@ namespace MediaBrowser.Server.Implementations.Providers } } - // Set the path into the BaseItem + // Set the path into the item SetImagePath(item, type, imageIndex, paths[0], sourceUrl); // Delete the current path @@ -257,27 +259,9 @@ namespace MediaBrowser.Server.Implementations.Providers /// or /// imageIndex /// </exception> - private string GetCurrentImagePath(BaseItem item, ImageType type, int? imageIndex) + private string GetCurrentImagePath(IHasImages item, ImageType type, int imageIndex) { - switch (type) - { - case ImageType.Screenshot: - - var hasScreenshots = (IHasScreenshots)item; - if (!imageIndex.HasValue) - { - throw new ArgumentNullException("imageIndex"); - } - return hasScreenshots.ScreenshotImagePaths.Count > imageIndex.Value ? hasScreenshots.ScreenshotImagePaths[imageIndex.Value] : null; - case ImageType.Backdrop: - if (!imageIndex.HasValue) - { - throw new ArgumentNullException("imageIndex"); - } - return item.BackdropImagePaths.Count > imageIndex.Value ? item.BackdropImagePaths[imageIndex.Value] : null; - default: - return item.GetImage(type); - } + return item.GetImagePath(type, imageIndex); } /// <summary> @@ -336,7 +320,7 @@ namespace MediaBrowser.Server.Implementations.Providers } break; default: - item.SetImage(type, path); + item.SetImagePath(type, path); break; } } @@ -593,7 +577,7 @@ namespace MediaBrowser.Server.Implementations.Providers /// <param name="imageFilename">The image filename.</param> /// <param name="extension">The extension.</param> /// <returns>System.String.</returns> - private string GetSavePathForItemInMixedFolder(BaseItem item, ImageType type, string imageFilename, string extension) + private string GetSavePathForItemInMixedFolder(IHasImages item, ImageType type, string imageFilename, string extension) { if (type == ImageType.Primary) { diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs index 60c8df8c1..32df5fe13 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs @@ -96,7 +96,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks // Limit to video files to reduce changes of ffmpeg crash dialog foreach (var item in newItems .Where(i => i.LocationType == LocationType.FileSystem && i.VideoType == VideoType.VideoFile && string.IsNullOrEmpty(i.PrimaryImagePath) && i.DefaultVideoStreamIndex.HasValue) - .Take(2)) + .Take(1)) { try { |
