added IHasImages and IHasUserData
This commit is contained in:
parent
e1e5d35434
commit
cd859ac2e6
|
@ -1,17 +1,17 @@
|
|||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using ServiceStack;
|
||||
using ServiceStack.Text.Controller;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
@ -19,8 +19,6 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ServiceStack.Text.Controller;
|
||||
using ServiceStack.Web;
|
||||
|
||||
namespace MediaBrowser.Api.Images
|
||||
{
|
||||
|
@ -39,18 +37,6 @@ namespace MediaBrowser.Api.Images
|
|||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images", "GET")]
|
||||
[Api(Description = "Gets information about an item's images")]
|
||||
public class GetChannelImageInfos : IReturn<List<ImageInfo>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Artists/{Name}/Images", "GET")]
|
||||
[Route("/Genres/{Name}/Images", "GET")]
|
||||
[Route("/GameGenres/{Name}/Images", "GET")]
|
||||
|
@ -80,20 +66,7 @@ namespace MediaBrowser.Api.Images
|
|||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}", "GET")]
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "GET")]
|
||||
[Api(Description = "Gets an item image")]
|
||||
public class GetChannelImage : ImageRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Channel Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Class UpdateItemImageIndex
|
||||
/// </summary>
|
||||
|
@ -270,19 +243,6 @@ namespace MediaBrowser.Api.Images
|
|||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}", "DELETE")]
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "DELETE")]
|
||||
[Api(Description = "Deletes an item image")]
|
||||
public class DeleteChannelImage : DeleteImageRequest, IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Channel Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class PostUserImage
|
||||
/// </summary>
|
||||
|
@ -358,38 +318,13 @@ namespace MediaBrowser.Api.Images
|
|||
public Stream RequestStream { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}", "POST")]
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "POST")]
|
||||
[Api(Description = "Posts an item image")]
|
||||
public class PostChannelImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw Http Request Input Stream
|
||||
/// </summary>
|
||||
/// <value>The request stream.</value>
|
||||
public Stream RequestStream { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class ImageService
|
||||
/// </summary>
|
||||
public class ImageService : BaseApiService
|
||||
{
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
@ -400,12 +335,11 @@ namespace MediaBrowser.Api.Images
|
|||
private readonly IDtoService _dtoService;
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
|
||||
private readonly ILiveTvManager _liveTv;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ImageService" /> class.
|
||||
/// </summary>
|
||||
public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor, ILiveTvManager liveTv)
|
||||
public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
|
@ -414,7 +348,6 @@ namespace MediaBrowser.Api.Images
|
|||
_itemRepo = itemRepo;
|
||||
_dtoService = dtoService;
|
||||
_imageProcessor = imageProcessor;
|
||||
_liveTv = liveTv;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -431,15 +364,6 @@ namespace MediaBrowser.Api.Images
|
|||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetChannelImageInfos request)
|
||||
{
|
||||
var item = _liveTv.GetChannel(request.Id);
|
||||
|
||||
var result = GetItemImageInfos(item);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetItemByNameImageInfos request)
|
||||
{
|
||||
var result = GetItemByNameImageInfos(request);
|
||||
|
@ -540,7 +464,7 @@ namespace MediaBrowser.Api.Images
|
|||
return list;
|
||||
}
|
||||
|
||||
private ImageInfo GetImageInfo(string path, BaseItem item, int? imageIndex, ImageType type)
|
||||
private ImageInfo GetImageInfo(string path, IHasImages item, int? imageIndex, ImageType type)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -567,13 +491,6 @@ namespace MediaBrowser.Api.Images
|
|||
}
|
||||
}
|
||||
|
||||
public object Get(GetChannelImage request)
|
||||
{
|
||||
var item = _liveTv.GetChannel(request.Id);
|
||||
|
||||
return GetImage(request, item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
|
@ -659,20 +576,6 @@ namespace MediaBrowser.Api.Images
|
|||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
public void Post(PostChannelImage request)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var id = pathInfo.GetArgumentValue<string>(2);
|
||||
|
||||
request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue<string>(4), true);
|
||||
|
||||
var item = _liveTv.GetChannel(id);
|
||||
|
||||
var task = PostImage(item, request.RequestStream, request.Type, Request.ContentType);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified request.
|
||||
/// </summary>
|
||||
|
@ -699,15 +602,6 @@ namespace MediaBrowser.Api.Images
|
|||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
public void Delete(DeleteChannelImage request)
|
||||
{
|
||||
var item = _liveTv.GetChannel(request.Id);
|
||||
|
||||
var task = item.DeleteImage(request.Type, request.Index);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the specified request.
|
||||
/// </summary>
|
||||
|
@ -762,71 +656,9 @@ namespace MediaBrowser.Api.Images
|
|||
/// <param name="newIndex">The new index.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentException">The change index operation is only applicable to backdrops and screenshots</exception>
|
||||
private Task UpdateItemIndex(BaseItem item, ImageType type, int currentIndex, int newIndex)
|
||||
private Task UpdateItemIndex(IHasImages item, ImageType type, int currentIndex, int newIndex)
|
||||
{
|
||||
string file1;
|
||||
string file2;
|
||||
|
||||
if (type == ImageType.Screenshot)
|
||||
{
|
||||
var hasScreenshots = (IHasScreenshots)item;
|
||||
file1 = hasScreenshots.ScreenshotImagePaths[currentIndex];
|
||||
file2 = hasScreenshots.ScreenshotImagePaths[newIndex];
|
||||
}
|
||||
else if (type == ImageType.Backdrop)
|
||||
{
|
||||
file1 = item.BackdropImagePaths[currentIndex];
|
||||
file2 = item.BackdropImagePaths[newIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("The change index operation is only applicable to backdrops and screenshots");
|
||||
}
|
||||
|
||||
SwapFiles(file1, file2);
|
||||
|
||||
// Directory watchers should repeat this, but do a quick refresh first
|
||||
return item.RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swaps the files.
|
||||
/// </summary>
|
||||
/// <param name="file1">The file1.</param>
|
||||
/// <param name="file2">The file2.</param>
|
||||
private void SwapFiles(string file1, string file2)
|
||||
{
|
||||
Directory.CreateDirectory(_appPaths.TempDirectory);
|
||||
|
||||
var temp1 = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp");
|
||||
var temp2 = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp");
|
||||
|
||||
// Copying over will fail against hidden files
|
||||
RemoveHiddenAttribute(file1);
|
||||
RemoveHiddenAttribute(file2);
|
||||
|
||||
File.Copy(file1, temp1);
|
||||
File.Copy(file2, temp2);
|
||||
|
||||
File.Copy(temp1, file2, true);
|
||||
File.Copy(temp2, file1, true);
|
||||
|
||||
File.Delete(temp1);
|
||||
File.Delete(temp2);
|
||||
}
|
||||
|
||||
private void RemoveHiddenAttribute(string path)
|
||||
{
|
||||
var currentFile = new FileInfo(path);
|
||||
|
||||
// This will fail if the file is hidden
|
||||
if (currentFile.Exists)
|
||||
{
|
||||
if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
|
||||
{
|
||||
currentFile.Attributes &= ~FileAttributes.Hidden;
|
||||
}
|
||||
}
|
||||
return item.SwapImages(type, currentIndex, newIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -837,7 +669,7 @@ namespace MediaBrowser.Api.Images
|
|||
/// <returns>System.Object.</returns>
|
||||
/// <exception cref="ResourceNotFoundException">
|
||||
/// </exception>
|
||||
private object GetImage(ImageRequest request, BaseItem item)
|
||||
public object GetImage(ImageRequest request, IHasImages item)
|
||||
{
|
||||
var imagePath = GetImagePath(request, item);
|
||||
|
||||
|
@ -926,7 +758,7 @@ namespace MediaBrowser.Api.Images
|
|||
/// <param name="request">The request.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetImagePath(ImageRequest request, BaseItem item)
|
||||
private string GetImagePath(ImageRequest request, IHasImages item)
|
||||
{
|
||||
var index = request.Index ?? 0;
|
||||
|
||||
|
@ -941,7 +773,7 @@ namespace MediaBrowser.Api.Images
|
|||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <param name="mimeType">Type of the MIME.</param>
|
||||
/// <returns>Task.</returns>
|
||||
private async Task PostImage(BaseItem entity, Stream inputStream, ImageType imageType, string mimeType)
|
||||
public async Task PostImage(BaseItem entity, Stream inputStream, ImageType imageType, string mimeType)
|
||||
{
|
||||
using (var reader = new StreamReader(inputStream))
|
||||
{
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using ServiceStack;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using ServiceStack.Web;
|
||||
|
||||
namespace MediaBrowser.Api.Images
|
||||
{
|
||||
|
@ -27,7 +26,7 @@ namespace MediaBrowser.Api.Images
|
|||
/// Gets or sets the item.
|
||||
/// </summary>
|
||||
/// <value>The item.</value>
|
||||
public BaseItem Item { get; set; }
|
||||
public IHasImages Item { get; set; }
|
||||
/// <summary>
|
||||
/// The original image date modified
|
||||
/// </summary>
|
||||
|
|
|
@ -146,7 +146,7 @@ namespace MediaBrowser.Api
|
|||
|
||||
private async Task UpdateItem(UpdateChannel request)
|
||||
{
|
||||
var item = _liveTv.GetChannel(request.Id);
|
||||
var item = _liveTv.GetInternalChannel(request.Id);
|
||||
|
||||
UpdateItem(request, item);
|
||||
|
||||
|
|
184
MediaBrowser.Api/LiveTv/LiveTvImageService.cs
Normal file
184
MediaBrowser.Api/LiveTv/LiveTvImageService.cs
Normal file
|
@ -0,0 +1,184 @@
|
|||
using MediaBrowser.Api.Images;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using ServiceStack;
|
||||
using ServiceStack.Text.Controller;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Api.LiveTv
|
||||
{
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}", "POST")]
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "POST")]
|
||||
[Api(Description = "Posts an item image")]
|
||||
public class PostChannelImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw Http Request Input Stream
|
||||
/// </summary>
|
||||
/// <value>The request stream.</value>
|
||||
public Stream RequestStream { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}", "DELETE")]
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "DELETE")]
|
||||
[Api(Description = "Deletes an item image")]
|
||||
public class DeleteChannelImage : DeleteImageRequest, IReturnVoid
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Channel Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}", "GET")]
|
||||
[Route("/LiveTv/Channels/{Id}/Images/{Type}/{Index}", "GET")]
|
||||
[Api(Description = "Gets an item image")]
|
||||
public class GetChannelImage : ImageRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Channel Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Recordings/{Id}/Images/{Type}", "GET")]
|
||||
[Route("/LiveTv/Recordings/{Id}/Images/{Type}/{Index}", "GET")]
|
||||
[Api(Description = "Gets an item image")]
|
||||
public class GetRecordingImage : ImageRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Recording Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Programs/{Id}/Images/{Type}", "GET")]
|
||||
[Route("/LiveTv/Programs/{Id}/Images/{Type}/{Index}", "GET")]
|
||||
[Api(Description = "Gets an item image")]
|
||||
public class GetProgramImage : ImageRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Program Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
[Route("/LiveTv/Channels/{Id}/Images", "GET")]
|
||||
[Api(Description = "Gets information about an item's images")]
|
||||
public class GetChannelImageInfos : IReturn<List<ImageInfo>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
public class LiveTvImageService : BaseApiService
|
||||
{
|
||||
private readonly ILiveTvManager _liveTv;
|
||||
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
private readonly IItemRepository _itemRepo;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
|
||||
public LiveTvImageService(ILiveTvManager liveTv, IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor)
|
||||
{
|
||||
_liveTv = liveTv;
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
_appPaths = appPaths;
|
||||
_providerManager = providerManager;
|
||||
_itemRepo = itemRepo;
|
||||
_dtoService = dtoService;
|
||||
_imageProcessor = imageProcessor;
|
||||
}
|
||||
|
||||
public object Get(GetChannelImageInfos request)
|
||||
{
|
||||
var item = _liveTv.GetInternalChannel(request.Id);
|
||||
|
||||
var result = GetImageService().GetItemImageInfos(item);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public object Get(GetChannelImage request)
|
||||
{
|
||||
var item = _liveTv.GetInternalChannel(request.Id);
|
||||
|
||||
return GetImageService().GetImage(request, item);
|
||||
}
|
||||
|
||||
public object Get(GetRecordingImage request)
|
||||
{
|
||||
var item = _liveTv.GetInternalRecording(request.Id, CancellationToken.None).Result;
|
||||
|
||||
return GetImageService().GetImage(request, item);
|
||||
}
|
||||
|
||||
public void Post(PostChannelImage request)
|
||||
{
|
||||
var pathInfo = PathInfo.Parse(Request.PathInfo);
|
||||
var id = pathInfo.GetArgumentValue<string>(2);
|
||||
|
||||
request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue<string>(4), true);
|
||||
|
||||
var item = _liveTv.GetInternalChannel(id);
|
||||
|
||||
var task = GetImageService().PostImage(item, request.RequestStream, request.Type, Request.ContentType);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
public void Delete(DeleteChannelImage request)
|
||||
{
|
||||
var item = _liveTv.GetInternalChannel(request.Id);
|
||||
|
||||
var task = item.DeleteImage(request.Type, request.Index);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
||||
private ImageService GetImageService()
|
||||
{
|
||||
return new ImageService(_userManager, _libraryManager, _appPaths, _providerManager, _itemRepo, _dtoService,
|
||||
_imageProcessor);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -90,6 +90,7 @@
|
|||
<Compile Include="Library\LibraryHelpers.cs" />
|
||||
<Compile Include="Library\LibraryService.cs" />
|
||||
<Compile Include="Library\LibraryStructureService.cs" />
|
||||
<Compile Include="LiveTv\LiveTvImageService.cs" />
|
||||
<Compile Include="LiveTv\LiveTvService.cs" />
|
||||
<Compile Include="LocalizationService.cs" />
|
||||
<Compile Include="MoviesService.cs" />
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.MediaInfo;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaInfo;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
|
@ -110,7 +108,7 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <returns>System.String.</returns>
|
||||
protected virtual string GetOutputFileExtension(StreamState state)
|
||||
{
|
||||
return Path.GetExtension(state.Url);
|
||||
return Path.GetExtension(state.RequestedUrl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -187,7 +185,7 @@ namespace MediaBrowser.Api.Playback
|
|||
{
|
||||
var args = string.Empty;
|
||||
|
||||
if (state.Item.LocationType == LocationType.Remote)
|
||||
if (state.IsRemote)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
@ -308,7 +306,7 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
return args.Trim();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// If we're going to put a fixed size on the command line, this will calculate it
|
||||
/// </summary>
|
||||
|
@ -331,7 +329,7 @@ namespace MediaBrowser.Api.Playback
|
|||
string.Equals(state.SubtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(state.SubtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
assSubtitleParam = GetTextSubtitleParam((Video)state.Item, state.SubtitleStream, request.StartTimeTicks, performTextSubtitleConversion);
|
||||
assSubtitleParam = GetTextSubtitleParam(state, request.StartTimeTicks, performTextSubtitleConversion);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,14 +400,14 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <summary>
|
||||
/// Gets the text subtitle param.
|
||||
/// </summary>
|
||||
/// <param name="video">The video.</param>
|
||||
/// <param name="subtitleStream">The subtitle stream.</param>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <param name="startTimeTicks">The start time ticks.</param>
|
||||
/// <param name="performConversion">if set to <c>true</c> [perform conversion].</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetTextSubtitleParam(Video video, MediaStream subtitleStream, long? startTimeTicks, bool performConversion)
|
||||
protected string GetTextSubtitleParam(StreamState state, long? startTimeTicks, bool performConversion)
|
||||
{
|
||||
var path = subtitleStream.IsExternal ? GetConvertedAssPath(video, subtitleStream, startTimeTicks, performConversion) : GetExtractedAssPath(video, subtitleStream, startTimeTicks, performConversion);
|
||||
var path = state.SubtitleStream.IsExternal ? GetConvertedAssPath(state.MediaPath, state.SubtitleStream, startTimeTicks, performConversion) :
|
||||
GetExtractedAssPath(state, startTimeTicks, performConversion);
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
|
@ -422,22 +420,21 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <summary>
|
||||
/// Gets the extracted ass path.
|
||||
/// </summary>
|
||||
/// <param name="video">The video.</param>
|
||||
/// <param name="subtitleStream">The subtitle stream.</param>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <param name="startTimeTicks">The start time ticks.</param>
|
||||
/// <param name="performConversion">if set to <c>true</c> [perform conversion].</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetExtractedAssPath(Video video, MediaStream subtitleStream, long? startTimeTicks, bool performConversion)
|
||||
private string GetExtractedAssPath(StreamState state, long? startTimeTicks, bool performConversion)
|
||||
{
|
||||
var offset = TimeSpan.FromTicks(startTimeTicks ?? 0);
|
||||
|
||||
var path = FFMpegManager.Instance.GetSubtitleCachePath(video, subtitleStream.Index, offset, ".ass");
|
||||
var path = FFMpegManager.Instance.GetSubtitleCachePath(state.MediaPath, state.SubtitleStream, offset, ".ass");
|
||||
|
||||
if (performConversion)
|
||||
{
|
||||
InputType type;
|
||||
|
||||
var inputPath = MediaEncoderHelpers.GetInputArgument(video, null, out type);
|
||||
var inputPath = MediaEncoderHelpers.GetInputArgument(state.MediaPath, state.IsRemote, state.VideoType, state.IsoType, null, state.PlayableStreamFileNames, out type);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -445,7 +442,7 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
Directory.CreateDirectory(parentPath);
|
||||
|
||||
var task = MediaEncoder.ExtractTextSubtitle(inputPath, type, subtitleStream.Index, offset, path, CancellationToken.None);
|
||||
var task = MediaEncoder.ExtractTextSubtitle(inputPath, type, state.SubtitleStream.Index, offset, path, CancellationToken.None);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
@ -461,22 +458,16 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <summary>
|
||||
/// Gets the converted ass path.
|
||||
/// </summary>
|
||||
/// <param name="video">The video.</param>
|
||||
/// <param name="mediaPath">The media path.</param>
|
||||
/// <param name="subtitleStream">The subtitle stream.</param>
|
||||
/// <param name="startTimeTicks">The start time ticks.</param>
|
||||
/// <param name="performConversion">if set to <c>true</c> [perform conversion].</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetConvertedAssPath(Video video, MediaStream subtitleStream, long? startTimeTicks, bool performConversion)
|
||||
private string GetConvertedAssPath(string mediaPath, MediaStream subtitleStream, long? startTimeTicks, bool performConversion)
|
||||
{
|
||||
// If it's already ass, no conversion neccessary
|
||||
//if (string.Equals(Path.GetExtension(subtitleStream.Path), ".ass", StringComparison.OrdinalIgnoreCase))
|
||||
//{
|
||||
// return subtitleStream.Path;
|
||||
//}
|
||||
|
||||
var offset = TimeSpan.FromTicks(startTimeTicks ?? 0);
|
||||
|
||||
var path = FFMpegManager.Instance.GetSubtitleCachePath(video, subtitleStream.Index, offset, ".ass");
|
||||
var path = FFMpegManager.Instance.GetSubtitleCachePath(mediaPath, subtitleStream, offset, ".ass");
|
||||
|
||||
if (performConversion)
|
||||
{
|
||||
|
@ -524,25 +515,15 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <summary>
|
||||
/// Gets the probe size argument.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="mediaPath">The media path.</param>
|
||||
/// <param name="isVideo">if set to <c>true</c> [is video].</param>
|
||||
/// <param name="videoType">Type of the video.</param>
|
||||
/// <param name="isoType">Type of the iso.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetProbeSizeArgument(BaseItem item)
|
||||
protected string GetProbeSizeArgument(string mediaPath, bool isVideo, VideoType? videoType, IsoType? isoType)
|
||||
{
|
||||
var type = InputType.AudioFile;
|
||||
|
||||
if (item is Audio)
|
||||
{
|
||||
type = MediaEncoderHelpers.GetInputType(item.Path, null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var video = item as Video;
|
||||
|
||||
if (video != null)
|
||||
{
|
||||
type = MediaEncoderHelpers.GetInputType(item.Path, video.VideoType, video.IsoType);
|
||||
}
|
||||
}
|
||||
var type = !isVideo ? MediaEncoderHelpers.GetInputType(mediaPath, null, null) :
|
||||
MediaEncoderHelpers.GetInputType(mediaPath, videoType, isoType);
|
||||
|
||||
return MediaEncoder.GetProbeSizeArgument(type);
|
||||
}
|
||||
|
@ -652,22 +633,19 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <summary>
|
||||
/// Gets the input argument.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="isoMount">The iso mount.</param>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetInputArgument(BaseItem item, IIsoMount isoMount)
|
||||
protected string GetInputArgument(StreamState state)
|
||||
{
|
||||
var type = InputType.AudioFile;
|
||||
|
||||
var inputPath = new[] { item.Path };
|
||||
var inputPath = new[] { state.MediaPath };
|
||||
|
||||
var video = item as Video;
|
||||
|
||||
if (video != null)
|
||||
if (state.IsInputVideo)
|
||||
{
|
||||
if (!(video.VideoType == VideoType.Iso && isoMount == null))
|
||||
if (!(state.VideoType == VideoType.Iso && state.IsoMount == null))
|
||||
{
|
||||
inputPath = MediaEncoderHelpers.GetInputArgument(video, isoMount, out type);
|
||||
inputPath = MediaEncoderHelpers.GetInputArgument(state.MediaPath, state.IsRemote, state.VideoType, state.IsoType, state.IsoMount, state.PlayableStreamFileNames, out type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -686,11 +664,9 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
Directory.CreateDirectory(parentPath);
|
||||
|
||||
var video = state.Item as Video;
|
||||
|
||||
if (video != null && video.VideoType == VideoType.Iso && video.IsoType.HasValue && IsoManager.CanMount(video.Path))
|
||||
if (state.IsInputVideo && state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath))
|
||||
{
|
||||
state.IsoMount = await IsoManager.Mount(video.Path, CancellationToken.None).ConfigureAwait(false);
|
||||
state.IsoMount = await IsoManager.Mount(state.MediaPath, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var process = new Process
|
||||
|
@ -715,7 +691,7 @@ namespace MediaBrowser.Api.Playback
|
|||
EnableRaisingEvents = true
|
||||
};
|
||||
|
||||
ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, video != null, state.Request.StartTimeTicks, state.Item.Path, state.Request.DeviceId);
|
||||
ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, state.IsInputVideo, state.Request.StartTimeTicks, state.MediaPath, state.Request.DeviceId);
|
||||
|
||||
Logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
|
||||
|
||||
|
@ -754,13 +730,13 @@ namespace MediaBrowser.Api.Playback
|
|||
}
|
||||
|
||||
// Allow a small amount of time to buffer a little
|
||||
if (state.Item is Video)
|
||||
if (state.IsInputVideo)
|
||||
{
|
||||
await Task.Delay(500).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// This is arbitrary, but add a little buffer time when internet streaming
|
||||
if (state.Item.LocationType == LocationType.Remote)
|
||||
if (state.IsRemote)
|
||||
{
|
||||
await Task.Delay(4000).ConfigureAwait(false);
|
||||
}
|
||||
|
@ -787,11 +763,11 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <summary>
|
||||
/// Gets the user agent param.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetUserAgentParam(BaseItem item)
|
||||
protected string GetUserAgentParam(string path)
|
||||
{
|
||||
var useragent = GetUserAgent(item);
|
||||
var useragent = GetUserAgent(path);
|
||||
|
||||
if (!string.IsNullOrEmpty(useragent))
|
||||
{
|
||||
|
@ -804,11 +780,11 @@ namespace MediaBrowser.Api.Playback
|
|||
/// <summary>
|
||||
/// Gets the user agent.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected string GetUserAgent(BaseItem item)
|
||||
protected string GetUserAgent(string path)
|
||||
{
|
||||
if (item.Path.IndexOf("apple.com", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
if (path.IndexOf("apple.com", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return "QuickTime/7.7.4";
|
||||
}
|
||||
|
@ -852,8 +828,6 @@ namespace MediaBrowser.Api.Playback
|
|||
{
|
||||
var item = DtoService.GetItemByDtoId(request.Id);
|
||||
|
||||
var media = (IHasMediaStreams)item;
|
||||
|
||||
var url = Request.PathInfo;
|
||||
|
||||
if (!request.AudioCodec.HasValue)
|
||||
|
@ -863,11 +837,25 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
var state = new StreamState
|
||||
{
|
||||
Item = item,
|
||||
Request = request,
|
||||
Url = url
|
||||
RequestedUrl = url,
|
||||
MediaPath = item.Path,
|
||||
IsRemote = item.LocationType == LocationType.Remote
|
||||
};
|
||||
|
||||
var video = item as Video;
|
||||
|
||||
if (video != null)
|
||||
{
|
||||
state.IsInputVideo = true;
|
||||
state.VideoType = video.VideoType;
|
||||
state.IsoType = video.IsoType;
|
||||
|
||||
state.PlayableStreamFileNames = video.PlayableStreamFileNames == null
|
||||
? new List<string>()
|
||||
: video.PlayableStreamFileNames.ToList();
|
||||
}
|
||||
|
||||
var videoRequest = request as VideoStreamRequest;
|
||||
|
||||
var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery
|
||||
|
|
|
@ -4,7 +4,6 @@ using MediaBrowser.Common.MediaInfo;
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
@ -247,7 +246,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// <returns>System.String.</returns>
|
||||
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool performSubtitleConversions)
|
||||
{
|
||||
var probeSize = GetProbeSizeArgument(state.Item);
|
||||
var probeSize = GetProbeSizeArgument(state.MediaPath, state.IsInputVideo, state.VideoType, state.IsoType);
|
||||
|
||||
var hlsVideoRequest = state.VideoRequest as GetHlsVideoStream;
|
||||
|
||||
|
@ -262,9 +261,9 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
var args = string.Format("{0}{1} {2} {3} -i {4}{5} -threads {6} {7} {8} -sc_threshold 0 {9} -hls_time 10 -start_number 0 -hls_list_size 1440 \"{10}\"",
|
||||
itsOffset,
|
||||
probeSize,
|
||||
GetUserAgentParam(state.Item),
|
||||
GetUserAgentParam(state.MediaPath),
|
||||
GetFastSeekCommandLineParameter(state.Request),
|
||||
GetInputArgument(state.Item, state.IsoMount),
|
||||
GetInputArgument(state),
|
||||
GetSlowSeekCommandLineParameter(state.Request),
|
||||
threads,
|
||||
GetMapArgs(state),
|
||||
|
@ -275,7 +274,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
if (hlsVideoRequest != null)
|
||||
{
|
||||
if (hlsVideoRequest.AppendBaselineStream && state.Item is Video)
|
||||
if (hlsVideoRequest.AppendBaselineStream && state.IsInputVideo)
|
||||
{
|
||||
var lowBitratePath = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath) + "-low.m3u8");
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
|
||||
return string.Format("{0} -i {1}{2} -threads {3}{4} {5} -id3v2_version 3 -write_id3v1 1 \"{6}\"",
|
||||
GetFastSeekCommandLineParameter(request),
|
||||
GetInputArgument(state.Item, state.IsoMount),
|
||||
GetInputArgument(state),
|
||||
GetSlowSeekCommandLineParameter(request),
|
||||
threads,
|
||||
vn,
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
using MediaBrowser.Api.Images;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.MediaInfo;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -51,9 +47,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
// Try to infer based on the desired video codec
|
||||
if (videoRequest != null && videoRequest.VideoCodec.HasValue)
|
||||
{
|
||||
var video = state.Item as Video;
|
||||
|
||||
if (video != null)
|
||||
if (state.IsInputVideo)
|
||||
{
|
||||
switch (videoRequest.VideoCodec.Value)
|
||||
{
|
||||
|
@ -72,9 +66,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
// Try to infer based on the desired audio codec
|
||||
if (state.Request.AudioCodec.HasValue)
|
||||
{
|
||||
var audio = state.Item as Audio;
|
||||
|
||||
if (audio != null)
|
||||
if (!state.IsInputVideo)
|
||||
{
|
||||
switch (state.Request.AudioCodec.Value)
|
||||
{
|
||||
|
@ -188,16 +180,11 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
{
|
||||
var state = GetState(request);
|
||||
|
||||
if (request.AlbumArt)
|
||||
{
|
||||
return GetAlbumArtResponse(state);
|
||||
}
|
||||
|
||||
var responseHeaders = new Dictionary<string, string>();
|
||||
|
||||
if (request.Static && state.Item.LocationType == LocationType.Remote)
|
||||
if (request.Static && state.IsRemote)
|
||||
{
|
||||
return GetStaticRemoteStreamResult(state.Item, responseHeaders, isHeadRequest).Result;
|
||||
return GetStaticRemoteStreamResult(state.MediaPath, responseHeaders, isHeadRequest).Result;
|
||||
}
|
||||
|
||||
var outputPath = GetOutputFilePath(state);
|
||||
|
@ -210,7 +197,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
|
||||
if (request.Static)
|
||||
{
|
||||
return ResultFactory.GetStaticFileResult(Request, state.Item.Path, FileShare.Read, responseHeaders, isHeadRequest);
|
||||
return ResultFactory.GetStaticFileResult(Request, state.MediaPath, FileShare.Read, responseHeaders, isHeadRequest);
|
||||
}
|
||||
|
||||
if (outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive))
|
||||
|
@ -224,19 +211,19 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
/// <summary>
|
||||
/// Gets the static remote stream result.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="mediaPath">The media path.</param>
|
||||
/// <param name="responseHeaders">The response headers.</param>
|
||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||
/// <returns>Task{System.Object}.</returns>
|
||||
private async Task<object> GetStaticRemoteStreamResult(BaseItem item, Dictionary<string, string> responseHeaders, bool isHeadRequest)
|
||||
private async Task<object> GetStaticRemoteStreamResult(string mediaPath, Dictionary<string, string> responseHeaders, bool isHeadRequest)
|
||||
{
|
||||
responseHeaders["Accept-Ranges"] = "none";
|
||||
|
||||
var httpClient = new HttpClient();
|
||||
|
||||
using (var message = new HttpRequestMessage(HttpMethod.Get, item.Path))
|
||||
using (var message = new HttpRequestMessage(HttpMethod.Get, mediaPath))
|
||||
{
|
||||
var useragent = GetUserAgent(item);
|
||||
var useragent = GetUserAgent(mediaPath);
|
||||
|
||||
if (!string.IsNullOrEmpty(useragent))
|
||||
{
|
||||
|
@ -272,47 +259,6 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the album art response.
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
private object GetAlbumArtResponse(StreamState state)
|
||||
{
|
||||
var request = new GetItemImage
|
||||
{
|
||||
MaxWidth = 800,
|
||||
MaxHeight = 800,
|
||||
Type = ImageType.Primary,
|
||||
Id = state.Item.Id.ToString()
|
||||
};
|
||||
|
||||
// Try and find some image to return
|
||||
if (!state.Item.HasImage(ImageType.Primary))
|
||||
{
|
||||
if (state.Item.HasImage(ImageType.Backdrop))
|
||||
{
|
||||
request.Type = ImageType.Backdrop;
|
||||
}
|
||||
else if (state.Item.HasImage(ImageType.Thumb))
|
||||
{
|
||||
request.Type = ImageType.Thumb;
|
||||
}
|
||||
else if (state.Item.HasImage(ImageType.Logo))
|
||||
{
|
||||
request.Type = ImageType.Logo;
|
||||
}
|
||||
}
|
||||
|
||||
return new ImageService(UserManager, LibraryManager, ServerConfigurationManager.ApplicationPaths, null, ItemRepository, DtoService, ImageProcessor, null)
|
||||
{
|
||||
Logger = Logger,
|
||||
Request = Request,
|
||||
ResultFactory = ResultFactory
|
||||
|
||||
}.Get(request);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stream result.
|
||||
/// </summary>
|
||||
|
|
|
@ -3,7 +3,6 @@ using MediaBrowser.Common.MediaInfo;
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
@ -89,9 +88,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
/// <returns>System.String.</returns>
|
||||
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool performSubtitleConversions)
|
||||
{
|
||||
var video = (Video)state.Item;
|
||||
|
||||
var probeSize = GetProbeSizeArgument(state.Item);
|
||||
var probeSize = GetProbeSizeArgument(state.MediaPath, state.IsInputVideo, state.VideoType, state.IsoType);
|
||||
|
||||
// Get the output codec name
|
||||
var videoCodec = GetVideoCodec(state.VideoRequest);
|
||||
|
@ -108,9 +105,9 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
|
||||
return string.Format("{0} {1} {2} -i {3}{4}{5} {6} {7} -threads {8} {9}{10} \"{11}\"",
|
||||
probeSize,
|
||||
GetUserAgentParam(state.Item),
|
||||
GetUserAgentParam(state.MediaPath),
|
||||
GetFastSeekCommandLineParameter(state.Request),
|
||||
GetInputArgument(video, state.IsoMount),
|
||||
GetInputArgument(state),
|
||||
GetSlowSeekCommandLineParameter(state.Request),
|
||||
keyFrame,
|
||||
GetMapArgs(state),
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
using System.IO;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
public class StreamState
|
||||
{
|
||||
public string Url { get; set; }
|
||||
public string RequestedUrl { get; set; }
|
||||
|
||||
public StreamRequest Request { get; set; }
|
||||
|
||||
|
@ -29,12 +28,22 @@ namespace MediaBrowser.Api.Playback
|
|||
|
||||
public MediaStream SubtitleStream { get; set; }
|
||||
|
||||
public BaseItem Item { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the iso mount.
|
||||
/// </summary>
|
||||
/// <value>The iso mount.</value>
|
||||
public IIsoMount IsoMount { get; set; }
|
||||
|
||||
public string MediaPath { get; set; }
|
||||
|
||||
public bool IsRemote { get; set; }
|
||||
|
||||
public bool IsInputVideo { get; set; }
|
||||
|
||||
public VideoType VideoType { get; set; }
|
||||
|
||||
public IsoType? IsoType { get; set; }
|
||||
|
||||
public List<string> PlayableStreamFileNames { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ namespace MediaBrowser.Api
|
|||
|
||||
if (item.HasImage(ImageType.Primary))
|
||||
{
|
||||
result.PrimaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary, item.GetImage(ImageType.Primary));
|
||||
result.PrimaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary, item.GetImagePath(ImageType.Primary));
|
||||
}
|
||||
|
||||
var episode = item as Episode;
|
||||
|
|
|
@ -216,6 +216,48 @@ namespace MediaBrowser.Common.Implementations.IO
|
|||
|
||||
return new FileStream(path, mode, access, share);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swaps the files.
|
||||
/// </summary>
|
||||
/// <param name="file1">The file1.</param>
|
||||
/// <param name="file2">The file2.</param>
|
||||
public void SwapFiles(string file1, string file2)
|
||||
{
|
||||
var temp1 = Path.GetTempFileName();
|
||||
var temp2 = Path.GetTempFileName();
|
||||
|
||||
// Copying over will fail against hidden files
|
||||
RemoveHiddenAttribute(file1);
|
||||
RemoveHiddenAttribute(file2);
|
||||
|
||||
File.Copy(file1, temp1, true);
|
||||
File.Copy(file2, temp2, true);
|
||||
|
||||
File.Copy(temp1, file2, true);
|
||||
File.Copy(temp2, file1, true);
|
||||
|
||||
File.Delete(temp1);
|
||||
File.Delete(temp2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the hidden attribute.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
private void RemoveHiddenAttribute(string path)
|
||||
{
|
||||
var currentFile = new FileInfo(path);
|
||||
|
||||
// This will fail if the file is hidden
|
||||
if (currentFile.Exists)
|
||||
{
|
||||
if ((currentFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
|
||||
{
|
||||
currentFile.Attributes &= ~FileAttributes.Hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -74,5 +74,12 @@ namespace MediaBrowser.Common.IO
|
|||
/// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
|
||||
/// <returns>FileStream.</returns>
|
||||
FileStream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share, bool isAsync = false);
|
||||
|
||||
/// <summary>
|
||||
/// Swaps the files.
|
||||
/// </summary>
|
||||
/// <param name="file1">The file1.</param>
|
||||
/// <param name="file2">The file2.</param>
|
||||
void SwapFiles(string file1, string file2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace MediaBrowser.Controller.Drawing
|
|||
/// <param name="item">The item.</param>
|
||||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <returns>IEnumerable{IImageEnhancer}.</returns>
|
||||
IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType);
|
||||
IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image cache tag.
|
||||
|
@ -56,7 +56,7 @@ namespace MediaBrowser.Controller.Drawing
|
|||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <param name="imagePath">The image path.</param>
|
||||
/// <returns>Guid.</returns>
|
||||
Guid GetImageCacheTag(BaseItem item, ImageType imageType, string imagePath);
|
||||
Guid GetImageCacheTag(IHasImages item, ImageType imageType, string imagePath);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image cache tag.
|
||||
|
@ -67,7 +67,7 @@ namespace MediaBrowser.Controller.Drawing
|
|||
/// <param name="dateModified">The date modified.</param>
|
||||
/// <param name="imageEnhancers">The image enhancers.</param>
|
||||
/// <returns>Guid.</returns>
|
||||
Guid GetImageCacheTag(BaseItem item, ImageType imageType, string originalImagePath, DateTime dateModified,
|
||||
Guid GetImageCacheTag(IHasImages item, ImageType imageType, string originalImagePath, DateTime dateModified,
|
||||
List<IImageEnhancer> imageEnhancers);
|
||||
|
||||
/// <summary>
|
||||
|
@ -85,6 +85,6 @@ namespace MediaBrowser.Controller.Drawing
|
|||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns>Task{System.String}.</returns>
|
||||
Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex);
|
||||
Task<string> GetEnhancedImage(IHasImages item, ImageType imageType, int imageIndex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace MediaBrowser.Controller.Drawing
|
|||
{
|
||||
public class ImageProcessingOptions
|
||||
{
|
||||
public BaseItem Item { get; set; }
|
||||
public IHasImages Item { get; set; }
|
||||
|
||||
public ImageType ImageType { get; set; }
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// Class BaseItem
|
||||
/// </summary>
|
||||
public abstract class BaseItem : IHasProviderIds, ILibraryItem
|
||||
public abstract class BaseItem : IHasProviderIds, ILibraryItem, IHasImages, IHasUserData
|
||||
{
|
||||
protected BaseItem()
|
||||
{
|
||||
|
@ -132,8 +132,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
[IgnoreDataMember]
|
||||
public string PrimaryImagePath
|
||||
{
|
||||
get { return GetImage(ImageType.Primary); }
|
||||
set { SetImage(ImageType.Primary, value); }
|
||||
get { return this.GetImagePath(ImageType.Primary); }
|
||||
set { this.SetImagePath(ImageType.Primary, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1310,31 +1310,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// Gets an image
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
/// <exception cref="System.ArgumentException">Backdrops should be accessed using Item.Backdrops</exception>
|
||||
public string GetImage(ImageType type)
|
||||
{
|
||||
if (type == ImageType.Backdrop)
|
||||
{
|
||||
throw new ArgumentException("Backdrops should be accessed using Item.Backdrops");
|
||||
}
|
||||
if (type == ImageType.Screenshot)
|
||||
{
|
||||
throw new ArgumentException("Screenshots should be accessed using Item.Screenshots");
|
||||
}
|
||||
|
||||
string val;
|
||||
Images.TryGetValue(type, out val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an image
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns>
|
||||
/// <exception cref="System.ArgumentException">Backdrops should be accessed using Item.Backdrops</exception>
|
||||
public bool HasImage(ImageType type)
|
||||
public bool HasImage(ImageType type, int imageIndex)
|
||||
{
|
||||
if (type == ImageType.Backdrop)
|
||||
{
|
||||
|
@ -1345,16 +1324,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
throw new ArgumentException("Screenshots should be accessed using Item.Screenshots");
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(GetImage(type));
|
||||
return !string.IsNullOrEmpty(this.GetImagePath(type));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets an image
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <exception cref="System.ArgumentException">Backdrops should be accessed using Item.Backdrops</exception>
|
||||
public void SetImage(ImageType type, string path)
|
||||
public void SetImagePath(ImageType type, int index, string path)
|
||||
{
|
||||
if (type == ImageType.Backdrop)
|
||||
{
|
||||
|
@ -1423,10 +1396,10 @@ namespace MediaBrowser.Controller.Entities
|
|||
else
|
||||
{
|
||||
// Delete the source file
|
||||
DeleteImagePath(GetImage(type));
|
||||
DeleteImagePath(this.GetImagePath(type));
|
||||
|
||||
// Remove it from the item
|
||||
SetImage(type, null);
|
||||
this.SetImagePath(type, null);
|
||||
}
|
||||
|
||||
// Refresh metadata
|
||||
|
@ -1597,13 +1570,13 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
if (imageType == ImageType.Backdrop)
|
||||
{
|
||||
return BackdropImagePaths[imageIndex];
|
||||
return BackdropImagePaths.Count > imageIndex ? BackdropImagePaths[imageIndex] : null;
|
||||
}
|
||||
|
||||
if (imageType == ImageType.Screenshot)
|
||||
{
|
||||
var hasScreenshots = (IHasScreenshots)this;
|
||||
return hasScreenshots.ScreenshotImagePaths[imageIndex];
|
||||
return hasScreenshots.ScreenshotImagePaths.Count > imageIndex ? hasScreenshots.ScreenshotImagePaths[imageIndex] : null;
|
||||
}
|
||||
|
||||
if (imageType == ImageType.Chapter)
|
||||
|
@ -1611,7 +1584,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
return ItemRepository.GetChapter(Id, imageIndex).ImagePath;
|
||||
}
|
||||
|
||||
return GetImage(imageType);
|
||||
string val;
|
||||
Images.TryGetValue(imageType, out val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1658,5 +1633,21 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
return new[] { Path };
|
||||
}
|
||||
|
||||
public Task SwapImages(ImageType type, int index1, int index2)
|
||||
{
|
||||
if (type != ImageType.Screenshot && type != ImageType.Backdrop)
|
||||
{
|
||||
throw new ArgumentException("The change index operation is only applicable to backdrops and screenshots");
|
||||
}
|
||||
|
||||
var file1 = GetImagePath(type, index1);
|
||||
var file2 = GetImagePath(type, index2);
|
||||
|
||||
FileSystem.SwapFiles(file1, file2);
|
||||
|
||||
// Directory watchers should repeat this, but do a quick refresh first
|
||||
return RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
97
MediaBrowser.Controller/Entities/IHasImages.cs
Normal file
97
MediaBrowser.Controller/Entities/IHasImages.cs
Normal file
|
@ -0,0 +1,97 @@
|
|||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public interface IHasImages
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path.
|
||||
/// </summary>
|
||||
/// <value>The path.</value>
|
||||
string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the identifier.
|
||||
/// </summary>
|
||||
/// <value>The identifier.</value>
|
||||
Guid Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image path.
|
||||
/// </summary>
|
||||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetImagePath(ImageType imageType, int imageIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image date modified.
|
||||
/// </summary>
|
||||
/// <param name="imagePath">The image path.</param>
|
||||
/// <returns>DateTime.</returns>
|
||||
DateTime GetImageDateModified(string imagePath);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the image.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="index">The index.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
void SetImagePath(ImageType type, int index, string path);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified type has image.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns>
|
||||
bool HasImage(ImageType type, int imageIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Swaps the images.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="index1">The index1.</param>
|
||||
/// <param name="index2">The index2.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SwapImages(ImageType type, int index1, int index2);
|
||||
}
|
||||
|
||||
public static class HasImagesExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the image path.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public static string GetImagePath(this IHasImages item, ImageType imageType)
|
||||
{
|
||||
return item.GetImagePath(imageType, 0);
|
||||
}
|
||||
|
||||
public static bool HasImage(this IHasImages item, ImageType imageType)
|
||||
{
|
||||
return item.HasImage(imageType, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the image path.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
public static void SetImagePath(this IHasImages item, ImageType imageType, string path)
|
||||
{
|
||||
item.SetImagePath(imageType, 0, path);
|
||||
}
|
||||
}
|
||||
}
|
15
MediaBrowser.Controller/Entities/IHasUserData.cs
Normal file
15
MediaBrowser.Controller/Entities/IHasUserData.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface IHasUserData
|
||||
/// </summary>
|
||||
public interface IHasUserData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetUserDataKey();
|
||||
}
|
||||
}
|
|
@ -183,7 +183,9 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
episodes = episodes.Where(i => !i.IsVirtualUnaired);
|
||||
}
|
||||
|
||||
return LibraryManager.Sort(episodes, user, new[] { ItemSortBy.AiredEpisodeOrder }, SortOrder.Ascending)
|
||||
var sortBy = seasonNumber == 0 ? ItemSortBy.SortName : ItemSortBy.AiredEpisodeOrder;
|
||||
|
||||
return LibraryManager.Sort(episodes, user, new[] { sortBy }, SortOrder.Ascending)
|
||||
.Cast<Episode>();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <param name="reason">The reason.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SaveUserData(Guid userId, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
|
||||
Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data.
|
||||
|
|
|
@ -37,6 +37,6 @@ namespace MediaBrowser.Controller.Library
|
|||
/// Gets or sets the item.
|
||||
/// </summary>
|
||||
/// <value>The item.</value>
|
||||
public BaseItem Item { get; set; }
|
||||
public IHasUserData Item { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class Channel : BaseItem, IItemByName
|
||||
{
|
||||
public Channel()
|
||||
{
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
{
|
||||
return "Channel-" + Name;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number.
|
||||
/// </summary>
|
||||
/// <value>The number.</value>
|
||||
public string ChannelNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets the Id.
|
||||
/// </summary>
|
||||
/// <value>The id of the channel.</value>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the service.
|
||||
/// </summary>
|
||||
/// <value>The name of the service.</value>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the channel.
|
||||
/// </summary>
|
||||
/// <value>The type of the channel.</value>
|
||||
public ChannelType ChannelType { get; set; }
|
||||
|
||||
public bool? HasProviderImage { get; set; }
|
||||
|
||||
protected override string CreateSortName()
|
||||
{
|
||||
double number = 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(ChannelNumber))
|
||||
{
|
||||
double.TryParse(ChannelNumber, out number);
|
||||
}
|
||||
|
||||
return number.ToString("000-") + (Name ?? string.Empty);
|
||||
}
|
||||
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,9 +32,15 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
public ChannelType ChannelType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set this value to true or false if it is known via channel info whether there is an image or not.
|
||||
/// Leave it null if the only way to determine is by requesting the image and handling the failure.
|
||||
/// Supply the image path if it can be accessed directly from the file system
|
||||
/// </summary>
|
||||
public bool? HasImage { get; set; }
|
||||
/// <value>The image path.</value>
|
||||
public string ImagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supply the image url if it can be downloaded
|
||||
/// </summary>
|
||||
/// <value>The image URL.</value>
|
||||
public string ImageUrl { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,8 +144,16 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <returns>Channel.</returns>
|
||||
Channel GetChannel(string id);
|
||||
LiveTvChannel GetInternalChannel(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recording.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>LiveTvRecording.</returns>
|
||||
Task<LiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the program.
|
||||
/// </summary>
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel image asynchronous.
|
||||
/// Gets the channel image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to ChannelInfo
|
||||
/// </summary>
|
||||
/// <param name="channelId">The channel identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
|
@ -87,7 +87,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
Task<ImageResponseInfo> GetChannelImageAsync(string channelId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recording image asynchronous.
|
||||
/// Gets the recording image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to RecordingInfo
|
||||
/// </summary>
|
||||
/// <param name="recordingId">The recording identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
|
@ -95,7 +95,7 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
Task<ImageResponseInfo> GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the program image asynchronous.
|
||||
/// Gets the program image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to ProgramInfo
|
||||
/// </summary>
|
||||
/// <param name="programId">The program identifier.</param>
|
||||
/// <param name="channelId">The channel identifier.</param>
|
||||
|
|
57
MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
Normal file
57
MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class LiveTvChannel : BaseItem, IItemByName
|
||||
{
|
||||
public LiveTvChannel()
|
||||
{
|
||||
UserItemCountList = new List<ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
{
|
||||
return GetClientTypeName() + "-" + Name;
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public List<ItemByNameCounts> UserItemCountList { get; set; }
|
||||
|
||||
public ChannelInfo ChannelInfo { get; set; }
|
||||
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
protected override string CreateSortName()
|
||||
{
|
||||
double number = 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(ChannelInfo.Number))
|
||||
{
|
||||
double.TryParse(ChannelInfo.Number, out number);
|
||||
}
|
||||
|
||||
return number.ToString("000-") + (Name ?? string.Empty);
|
||||
}
|
||||
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChannelInfo.ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetClientTypeName()
|
||||
{
|
||||
return "Channel";
|
||||
}
|
||||
}
|
||||
}
|
33
MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
Normal file
33
MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class LiveTvProgram : BaseItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
{
|
||||
return GetClientTypeName() + "-" + Name;
|
||||
}
|
||||
|
||||
public ProgramInfo ProgramInfo { get; set; }
|
||||
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ProgramInfo.IsVideo ? Model.Entities.MediaType.Video : Model.Entities.MediaType.Audio;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetClientTypeName()
|
||||
{
|
||||
return "Program";
|
||||
}
|
||||
}
|
||||
}
|
43
MediaBrowser.Controller/LiveTv/LiveTvRecording.cs
Normal file
43
MediaBrowser.Controller/LiveTv/LiveTvRecording.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class LiveTvRecording : BaseItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
public override string GetUserDataKey()
|
||||
{
|
||||
return GetClientTypeName() + "-" + Name;
|
||||
}
|
||||
|
||||
public RecordingInfo RecordingInfo { get; set; }
|
||||
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
public override string MediaType
|
||||
{
|
||||
get
|
||||
{
|
||||
return RecordingInfo.ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video;
|
||||
}
|
||||
}
|
||||
|
||||
public override LocationType LocationType
|
||||
{
|
||||
get
|
||||
{
|
||||
return LocationType.Remote;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetClientTypeName()
|
||||
{
|
||||
return "Recording";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -98,10 +98,16 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
public string EpisodeTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set this value to true or false if it is known via program info whether there is an image or not.
|
||||
/// Leave it null if the only way to determine is by requesting the image and handling the failure.
|
||||
/// Supply the image path if it can be accessed directly from the file system
|
||||
/// </summary>
|
||||
public bool? HasImage { get; set; }
|
||||
/// <value>The image path.</value>
|
||||
public string ImagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supply the image url if it can be downloaded
|
||||
/// </summary>
|
||||
/// <value>The image URL.</value>
|
||||
public string ImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is movie.
|
||||
|
@ -120,7 +126,13 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
|
||||
public bool IsSeries { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is video.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is video; otherwise, <c>false</c>.</value>
|
||||
public bool IsVideo { get; set; }
|
||||
|
||||
public ProgramInfo()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
|
|
|
@ -114,10 +114,16 @@ namespace MediaBrowser.Controller.LiveTv
|
|||
public float? CommunityRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set this value to true or false if it is known via recording info whether there is an image or not.
|
||||
/// Leave it null if the only way to determine is by requesting the image and handling the failure.
|
||||
/// Supply the image path if it can be accessed directly from the file system
|
||||
/// </summary>
|
||||
public bool? HasImage { get; set; }
|
||||
/// <value>The image path.</value>
|
||||
public string ImagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supply the image url if it can be downloaded
|
||||
/// </summary>
|
||||
/// <value>The image URL.</value>
|
||||
public string ImageUrl { get; set; }
|
||||
|
||||
public RecordingInfo()
|
||||
{
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
<Compile Include="Entities\IHasAspectRatio.cs" />
|
||||
<Compile Include="Entities\IHasBudget.cs" />
|
||||
<Compile Include="Entities\IHasCriticRating.cs" />
|
||||
<Compile Include="Entities\IHasImages.cs" />
|
||||
<Compile Include="Entities\IHasLanguage.cs" />
|
||||
<Compile Include="Entities\IHasMediaStreams.cs" />
|
||||
<Compile Include="Entities\IHasProductionLocations.cs" />
|
||||
|
@ -94,6 +95,7 @@
|
|||
<Compile Include="Entities\IHasTags.cs" />
|
||||
<Compile Include="Entities\IHasThemeMedia.cs" />
|
||||
<Compile Include="Entities\IHasTrailers.cs" />
|
||||
<Compile Include="Entities\IHasUserData.cs" />
|
||||
<Compile Include="Entities\IItemByName.cs" />
|
||||
<Compile Include="Entities\ILibraryItem.cs" />
|
||||
<Compile Include="Entities\ImageSourceInfo.cs" />
|
||||
|
@ -106,11 +108,13 @@
|
|||
<Compile Include="Library\ItemUpdateType.cs" />
|
||||
<Compile Include="Library\IUserDataManager.cs" />
|
||||
<Compile Include="Library\UserDataSaveEventArgs.cs" />
|
||||
<Compile Include="LiveTv\Channel.cs" />
|
||||
<Compile Include="LiveTv\LiveTvChannel.cs" />
|
||||
<Compile Include="LiveTv\ChannelInfo.cs" />
|
||||
<Compile Include="LiveTv\ILiveTvManager.cs" />
|
||||
<Compile Include="LiveTv\ILiveTvService.cs" />
|
||||
<Compile Include="LiveTv\ImageResponseInfo.cs" />
|
||||
<Compile Include="LiveTv\LiveTvProgram.cs" />
|
||||
<Compile Include="LiveTv\LiveTvRecording.cs" />
|
||||
<Compile Include="LiveTv\ProgramInfo.cs" />
|
||||
<Compile Include="LiveTv\RecordingInfo.cs" />
|
||||
<Compile Include="LiveTv\SeriesTimerInfo.cs" />
|
||||
|
|
|
@ -170,7 +170,7 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
|
||||
InputType type;
|
||||
|
||||
var inputPath = MediaEncoderHelpers.GetInputArgument(video, null, out type);
|
||||
var inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, false, video.VideoType, video.IsoType, null, video.PlayableStreamFileNames, out type);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -233,33 +233,23 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
/// <summary>
|
||||
/// Gets the subtitle cache path.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
|
||||
/// <param name="mediaPath">The media path.</param>
|
||||
/// <param name="subtitleStream">The subtitle stream.</param>
|
||||
/// <param name="offset">The offset.</param>
|
||||
/// <param name="outputExtension">The output extension.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public string GetSubtitleCachePath(Video input, int subtitleStreamIndex, TimeSpan? offset, string outputExtension)
|
||||
public string GetSubtitleCachePath(string mediaPath, MediaStream subtitleStream, TimeSpan? offset, string outputExtension)
|
||||
{
|
||||
var ticksParam = offset.HasValue ? "_" + offset.Value.Ticks : "";
|
||||
|
||||
var stream = _itemRepo.GetMediaStreams(new MediaStreamQuery
|
||||
if (subtitleStream.IsExternal)
|
||||
{
|
||||
ItemId = input.Id,
|
||||
Index = subtitleStreamIndex
|
||||
|
||||
}).FirstOrDefault();
|
||||
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
ticksParam += _fileSystem.GetLastWriteTimeUtc(subtitleStream.Path).Ticks;
|
||||
}
|
||||
|
||||
if (stream.IsExternal)
|
||||
{
|
||||
ticksParam += _fileSystem.GetLastWriteTimeUtc(stream.Path).Ticks;
|
||||
}
|
||||
var date = _fileSystem.GetLastWriteTimeUtc(mediaPath);
|
||||
|
||||
var filename = (input.Id + "_" + subtitleStreamIndex.ToString(_usCulture) + "_" + input.DateModified.Ticks.ToString(_usCulture) + ticksParam).GetMD5() + outputExtension;
|
||||
var filename = (mediaPath + "_" + subtitleStream.Index.ToString(_usCulture) + "_" + date.Ticks.ToString(_usCulture) + ticksParam).GetMD5() + outputExtension;
|
||||
|
||||
var prefix = filename.Substring(0, 1);
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
using MediaBrowser.Common.MediaInfo;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Common.MediaInfo;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
|
@ -13,43 +16,47 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
/// <summary>
|
||||
/// Gets the input argument.
|
||||
/// </summary>
|
||||
/// <param name="video">The video.</param>
|
||||
/// <param name="videoPath">The video path.</param>
|
||||
/// <param name="isRemote">if set to <c>true</c> [is remote].</param>
|
||||
/// <param name="videoType">Type of the video.</param>
|
||||
/// <param name="isoType">Type of the iso.</param>
|
||||
/// <param name="isoMount">The iso mount.</param>
|
||||
/// <param name="playableStreamFileNames">The playable stream file names.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns>System.String[][].</returns>
|
||||
public static string[] GetInputArgument(Video video, IIsoMount isoMount, out InputType type)
|
||||
public static string[] GetInputArgument(string videoPath, bool isRemote, VideoType videoType, IsoType? isoType, IIsoMount isoMount, IEnumerable<string> playableStreamFileNames, out InputType type)
|
||||
{
|
||||
var inputPath = isoMount == null ? new[] { video.Path } : new[] { isoMount.MountedPath };
|
||||
var inputPath = isoMount == null ? new[] { videoPath } : new[] { isoMount.MountedPath };
|
||||
|
||||
type = InputType.VideoFile;
|
||||
|
||||
switch (video.VideoType)
|
||||
switch (videoType)
|
||||
{
|
||||
case VideoType.BluRay:
|
||||
type = InputType.Bluray;
|
||||
break;
|
||||
case VideoType.Dvd:
|
||||
type = InputType.Dvd;
|
||||
inputPath = video.GetPlayableStreamFiles(inputPath[0]).ToArray();
|
||||
inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
|
||||
break;
|
||||
case VideoType.Iso:
|
||||
if (video.IsoType.HasValue)
|
||||
if (isoType.HasValue)
|
||||
{
|
||||
switch (video.IsoType.Value)
|
||||
switch (isoType.Value)
|
||||
{
|
||||
case IsoType.BluRay:
|
||||
type = InputType.Bluray;
|
||||
break;
|
||||
case IsoType.Dvd:
|
||||
type = InputType.Dvd;
|
||||
inputPath = video.GetPlayableStreamFiles(inputPath[0]).ToArray();
|
||||
inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VideoType.VideoFile:
|
||||
{
|
||||
if (video.LocationType == LocationType.Remote)
|
||||
if (isRemote)
|
||||
{
|
||||
type = InputType.Url;
|
||||
}
|
||||
|
@ -60,6 +67,17 @@ namespace MediaBrowser.Controller.MediaInfo
|
|||
return inputPath;
|
||||
}
|
||||
|
||||
public static List<string> GetPlayableStreamFiles(string rootPath, IEnumerable<string> filenames)
|
||||
{
|
||||
var allFiles = Directory
|
||||
.EnumerateFiles(rootPath, "*", SearchOption.AllDirectories)
|
||||
.ToList();
|
||||
|
||||
return filenames.Select(name => allFiles.FirstOrDefault(f => string.Equals(Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
|
||||
.Where(f => !string.IsNullOrEmpty(f))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the input.
|
||||
/// </summary>
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// <param name="item">The item.</param>
|
||||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <returns><c>true</c> if this enhancer will enhance the supplied image for the supplied item, <c>false</c> otherwise</returns>
|
||||
bool Supports(BaseItem item, ImageType imageType);
|
||||
bool Supports(IHasImages item, ImageType imageType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority or order in which this enhancer should be run.
|
||||
|
@ -28,7 +28,7 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// <param name="item">The item.</param>
|
||||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <returns>Cache key relating to the current state of this item and configuration</returns>
|
||||
string GetConfigurationCacheKey(BaseItem item, ImageType imageType);
|
||||
string GetConfigurationCacheKey(IHasImages item, ImageType imageType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the enhanced image.
|
||||
|
@ -38,7 +38,7 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <param name="originalImageSize">Size of the original image.</param>
|
||||
/// <returns>ImageSize.</returns>
|
||||
ImageSize GetEnhancedImageSize(BaseItem item, ImageType imageType, int imageIndex, ImageSize originalImageSize);
|
||||
ImageSize GetEnhancedImageSize(IHasImages item, ImageType imageType, int imageIndex, ImageSize originalImageSize);
|
||||
|
||||
/// <summary>
|
||||
/// Enhances the image async.
|
||||
|
@ -49,6 +49,6 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns>Task{Image}.</returns>
|
||||
/// <exception cref="System.ArgumentNullException"></exception>
|
||||
Task<Image> EnhanceImageAsync(BaseItem item, Image originalImage, ImageType imageType, int imageIndex);
|
||||
Task<Image> EnhanceImageAsync(IHasImages item, Image originalImage, ImageType imageType, int imageIndex);
|
||||
}
|
||||
}
|
|
@ -252,8 +252,8 @@ namespace MediaBrowser.Model.Configuration
|
|||
EnableVideoImageExtraction = true;
|
||||
|
||||
EnableMovieChapterImageExtraction = true;
|
||||
EnableEpisodeChapterImageExtraction = true;
|
||||
EnableOtherVideoChapterImageExtraction = true;
|
||||
EnableEpisodeChapterImageExtraction = false;
|
||||
EnableOtherVideoChapterImageExtraction = false;
|
||||
|
||||
#if (DEBUG)
|
||||
EnableDeveloperTools = true;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
|
@ -108,6 +109,12 @@ namespace MediaBrowser.Model.LiveTv
|
|||
/// <value>The episode title.</value>
|
||||
public string EpisodeTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the image tags.
|
||||
/// </summary>
|
||||
/// <value>The image tags.</value>
|
||||
public Dictionary<ImageType, Guid> ImageTags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data.
|
||||
/// </summary>
|
||||
|
@ -132,9 +139,16 @@ namespace MediaBrowser.Model.LiveTv
|
|||
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
|
||||
public bool IsSeries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type.
|
||||
/// </summary>
|
||||
/// <value>The type.</value>
|
||||
public string Type { get; set; }
|
||||
|
||||
public ProgramInfoDto()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
ImageTags = new Dictionary<ImageType, Guid>();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Model.LiveTv
|
||||
{
|
||||
|
@ -136,15 +137,28 @@ namespace MediaBrowser.Model.LiveTv
|
|||
/// <value>The audio.</value>
|
||||
public ProgramAudio? Audio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the image tags.
|
||||
/// </summary>
|
||||
/// <value>The image tags.</value>
|
||||
public Dictionary<ImageType, Guid> ImageTags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user data.
|
||||
/// </summary>
|
||||
/// <value>The user data.</value>
|
||||
public UserItemDataDto UserData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type.
|
||||
/// </summary>
|
||||
/// <value>The type.</value>
|
||||
public string Type { get; set; }
|
||||
|
||||
public RecordingInfoDto()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
ImageTags = new Dictionary<ImageType, Guid>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,12 @@
|
|||
/// </summary>
|
||||
/// <value>The user identifier.</value>
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the identifier.
|
||||
/// </summary>
|
||||
/// <value>The identifier.</value>
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
public class TimerQuery
|
||||
|
|
|
@ -212,7 +212,7 @@ namespace MediaBrowser.Providers
|
|||
|
||||
if (image != null)
|
||||
{
|
||||
item.SetImage(ImageType.Logo, image.FullName);
|
||||
item.SetImagePath(ImageType.Logo, image.FullName);
|
||||
}
|
||||
|
||||
// Clearart
|
||||
|
@ -220,7 +220,7 @@ namespace MediaBrowser.Providers
|
|||
|
||||
if (image != null)
|
||||
{
|
||||
item.SetImage(ImageType.Art, image.FullName);
|
||||
item.SetImagePath(ImageType.Art, image.FullName);
|
||||
}
|
||||
|
||||
// Disc
|
||||
|
@ -229,7 +229,7 @@ namespace MediaBrowser.Providers
|
|||
|
||||
if (image != null)
|
||||
{
|
||||
item.SetImage(ImageType.Disc, image.FullName);
|
||||
item.SetImagePath(ImageType.Disc, image.FullName);
|
||||
}
|
||||
|
||||
// Box Image
|
||||
|
@ -237,7 +237,7 @@ namespace MediaBrowser.Providers
|
|||
|
||||
if (image != null)
|
||||
{
|
||||
item.SetImage(ImageType.Box, image.FullName);
|
||||
item.SetImagePath(ImageType.Box, image.FullName);
|
||||
}
|
||||
|
||||
// BoxRear Image
|
||||
|
@ -245,7 +245,7 @@ namespace MediaBrowser.Providers
|
|||
|
||||
if (image != null)
|
||||
{
|
||||
item.SetImage(ImageType.BoxRear, image.FullName);
|
||||
item.SetImagePath(ImageType.BoxRear, image.FullName);
|
||||
}
|
||||
|
||||
// Thumbnail Image
|
||||
|
@ -253,7 +253,7 @@ namespace MediaBrowser.Providers
|
|||
|
||||
if (image != null)
|
||||
{
|
||||
item.SetImage(ImageType.Menu, image.FullName);
|
||||
item.SetImagePath(ImageType.Menu, image.FullName);
|
||||
}
|
||||
|
||||
PopulateBanner(item, args);
|
||||
|
@ -311,7 +311,7 @@ namespace MediaBrowser.Providers
|
|||
|
||||
if (image != null)
|
||||
{
|
||||
item.SetImage(ImageType.Primary, image.FullName);
|
||||
item.SetImagePath(ImageType.Primary, image.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,7 +339,7 @@ namespace MediaBrowser.Providers
|
|||
|
||||
if (image != null)
|
||||
{
|
||||
item.SetImage(ImageType.Banner, image.FullName);
|
||||
item.SetImagePath(ImageType.Banner, image.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,7 +367,7 @@ namespace MediaBrowser.Providers
|
|||
|
||||
if (image != null)
|
||||
{
|
||||
item.SetImage(ImageType.Thumb, image.FullName);
|
||||
item.SetImagePath(ImageType.Thumb, image.FullName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace MediaBrowser.Providers.LiveTv
|
|||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
public override bool Supports(BaseItem item)
|
||||
{
|
||||
return item is Channel;
|
||||
return item is LiveTvChannel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -74,7 +74,7 @@ namespace MediaBrowser.Providers.LiveTv
|
|||
|
||||
try
|
||||
{
|
||||
new BaseItemXmlParser<Channel>(Logger).Fetch((Channel)item, path, cancellationToken);
|
||||
new BaseItemXmlParser<LiveTvChannel>(Logger).Fetch((LiveTvChannel)item, path, cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -115,7 +115,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||
|
||||
if (video != null)
|
||||
{
|
||||
inputPath = MediaEncoderHelpers.GetInputArgument(video, isoMount, out type);
|
||||
inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, video.LocationType == LocationType.Remote, video.VideoType, video.IsoType, isoMount, video.PlayableStreamFileNames, out type);
|
||||
}
|
||||
|
||||
return await MediaEncoder.GetMediaInfo(inputPath, type, cancellationToken).ConfigureAwait(false);
|
||||
|
|
|
@ -253,7 +253,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||
|
||||
InputType type;
|
||||
|
||||
var inputPath = MediaEncoderHelpers.GetInputArgument(video, isoMount, out type);
|
||||
var inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, video.LocationType == LocationType.Remote, video.VideoType, video.IsoType, isoMount, video.PlayableStreamFileNames, out type);
|
||||
|
||||
await _mediaEncoder.ExtractImage(inputPath, type, video.Video3DFormat, imageOffset, path, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace MediaBrowser.Providers.Savers
|
|||
// If new metadata has been downloaded or metadata was manually edited, proceed
|
||||
if ((wasMetadataEdited || wasMetadataDownloaded))
|
||||
{
|
||||
return item is Channel;
|
||||
return item is LiveTvChannel;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -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 =>
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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((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)
|
||||
{
|
||||
await DownloadImage(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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
var timer = await liveTv.GetSeriesTimer(dto.SeriesTimerId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
info.SeriesTimerId = 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(dto.SeriesTimerId) && string.IsNullOrEmpty(info.SeriesTimerId))
|
||||
{
|
||||
var timer = await liveTv.GetSeriesTimer(dto.SeriesTimerId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
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;
|
||||
|
|
|
@ -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 service = ActiveService;
|
||||
|
||||
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(new Guid(query.UserId));
|
||||
|
||||
var list = new List<RecordingInfoDto>();
|
||||
var list = new List<RecordingInfo>();
|
||||
|
||||
if (ActiveService != null)
|
||||
{
|
||||
var recordings = await ActiveService.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var dtos = recordings.Select(i => _tvDtoService.GetRecordingInfoDto(i, ActiveService, user));
|
||||
|
||||
list.AddRange(dtos);
|
||||
}
|
||||
var recordings = await service.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
|
||||
list.AddRange(recordings);
|
||||
|
||||
if (!string.IsNullOrEmpty(query.ChannelId))
|
||||
{
|
||||
list = list.Where(i => string.Equals(i.ChannelId, query.ChannelId))
|
||||
list = list
|
||||
.Where(i => _tvDtoService.GetInternalChannelId(service.Name, i.ChannelId, i.ChannelName) == new Guid(query.ChannelId))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
var returnArray = list.OrderByDescending(i => i.StartDate)
|
||||
if (!string.IsNullOrEmpty(query.Id))
|
||||
{
|
||||
list = list
|
||||
.Where(i => _tvDtoService.GetInternalRecordingId(service.Name, i.Id) == new Guid(query.Id))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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" />
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -242,19 +242,19 @@ namespace MediaBrowser.ServerApplication
|
|||
}
|
||||
if (item.HasImage(ImageType.Banner))
|
||||
{
|
||||
previews.Add(new PreviewItem(item.GetImage(ImageType.Banner), "Banner"));
|
||||
previews.Add(new PreviewItem(item.GetImagePath(ImageType.Banner), "Banner"));
|
||||
}
|
||||
if (item.HasImage(ImageType.Logo))
|
||||
{
|
||||
previews.Add(new PreviewItem(item.GetImage(ImageType.Logo), "Logo"));
|
||||
previews.Add(new PreviewItem(item.GetImagePath(ImageType.Logo), "Logo"));
|
||||
}
|
||||
if (item.HasImage(ImageType.Art))
|
||||
{
|
||||
previews.Add(new PreviewItem(item.GetImage(ImageType.Art), "Art"));
|
||||
previews.Add(new PreviewItem(item.GetImagePath(ImageType.Art), "Art"));
|
||||
}
|
||||
if (item.HasImage(ImageType.Thumb))
|
||||
{
|
||||
previews.Add(new PreviewItem(item.GetImage(ImageType.Thumb), "Thumb"));
|
||||
previews.Add(new PreviewItem(item.GetImagePath(ImageType.Thumb), "Thumb"));
|
||||
}
|
||||
previews.AddRange(
|
||||
item.BackdropImagePaths.Select(
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Common.Internal</id>
|
||||
<version>3.0.278</version>
|
||||
<version>3.0.281</version>
|
||||
<title>MediaBrowser.Common.Internal</title>
|
||||
<authors>Luke</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
|
||||
<copyright>Copyright © Media Browser 2013</copyright>
|
||||
<dependencies>
|
||||
<dependency id="MediaBrowser.Common" version="3.0.278" />
|
||||
<dependency id="MediaBrowser.Common" version="3.0.281" />
|
||||
<dependency id="NLog" version="2.1.0" />
|
||||
<dependency id="SimpleInjector" version="2.4.0" />
|
||||
<dependency id="sharpcompress" version="0.10.2" />
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Common</id>
|
||||
<version>3.0.278</version>
|
||||
<version>3.0.281</version>
|
||||
<title>MediaBrowser.Common</title>
|
||||
<authors>Media Browser Team</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Server.Core</id>
|
||||
<version>3.0.278</version>
|
||||
<version>3.0.281</version>
|
||||
<title>Media Browser.Server.Core</title>
|
||||
<authors>Media Browser Team</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||
<copyright>Copyright © Media Browser 2013</copyright>
|
||||
<dependencies>
|
||||
<dependency id="MediaBrowser.Common" version="3.0.278" />
|
||||
<dependency id="MediaBrowser.Common" version="3.0.281" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
|
Loading…
Reference in New Issue
Block a user