aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2013-12-19 16:51:32 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2013-12-19 16:51:32 -0500
commitcd859ac2e6d499ce2cdf531058e64a4c3402910f (patch)
treee453d21e99ef2d6aee7f5e4af668a69147b31dfd /MediaBrowser.Server.Implementations
parente1e5d354345008e8d4ddc2dbbb99a68df4133280 (diff)
added IHasImages and IHasUserData
Diffstat (limited to 'MediaBrowser.Server.Implementations')
-rw-r--r--MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs14
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs8
-rw-r--r--MediaBrowser.Server.Implementations/Library/UserDataManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs77
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs114
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs114
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs136
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs136
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj2
-rw-r--r--MediaBrowser.Server.Implementations/Providers/ImageSaver.cs32
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs2
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
{