mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-07-09 15:20:34 +02:00
added IHasImages and IHasUserData
This commit is contained in:
parent
e1e5d35434
commit
cd859ac2e6
|
@ -1,17 +1,17 @@
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
|
using ServiceStack.Text.Controller;
|
||||||
|
using ServiceStack.Web;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
@ -19,8 +19,6 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ServiceStack.Text.Controller;
|
|
||||||
using ServiceStack.Web;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Images
|
namespace MediaBrowser.Api.Images
|
||||||
{
|
{
|
||||||
|
@ -39,18 +37,6 @@ namespace MediaBrowser.Api.Images
|
||||||
public string Id { get; set; }
|
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("/Artists/{Name}/Images", "GET")]
|
||||||
[Route("/Genres/{Name}/Images", "GET")]
|
[Route("/Genres/{Name}/Images", "GET")]
|
||||||
[Route("/GameGenres/{Name}/Images", "GET")]
|
[Route("/GameGenres/{Name}/Images", "GET")]
|
||||||
|
@ -81,19 +67,6 @@ namespace MediaBrowser.Api.Images
|
||||||
public string Id { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Class UpdateItemImageIndex
|
/// Class UpdateItemImageIndex
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -270,19 +243,6 @@ namespace MediaBrowser.Api.Images
|
||||||
public Guid Id { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Class PostUserImage
|
/// Class PostUserImage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -358,38 +318,13 @@ namespace MediaBrowser.Api.Images
|
||||||
public Stream RequestStream { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Class ImageService
|
/// Class ImageService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ImageService : BaseApiService
|
public class ImageService : BaseApiService
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The _user manager
|
|
||||||
/// </summary>
|
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _library manager
|
|
||||||
/// </summary>
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
private readonly IApplicationPaths _appPaths;
|
private readonly IApplicationPaths _appPaths;
|
||||||
|
@ -400,12 +335,11 @@ namespace MediaBrowser.Api.Images
|
||||||
private readonly IDtoService _dtoService;
|
private readonly IDtoService _dtoService;
|
||||||
private readonly IImageProcessor _imageProcessor;
|
private readonly IImageProcessor _imageProcessor;
|
||||||
|
|
||||||
private readonly ILiveTvManager _liveTv;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ImageService" /> class.
|
/// Initializes a new instance of the <see cref="ImageService" /> class.
|
||||||
/// </summary>
|
/// </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;
|
_userManager = userManager;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
|
@ -414,7 +348,6 @@ namespace MediaBrowser.Api.Images
|
||||||
_itemRepo = itemRepo;
|
_itemRepo = itemRepo;
|
||||||
_dtoService = dtoService;
|
_dtoService = dtoService;
|
||||||
_imageProcessor = imageProcessor;
|
_imageProcessor = imageProcessor;
|
||||||
_liveTv = liveTv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -431,15 +364,6 @@ namespace MediaBrowser.Api.Images
|
||||||
return ToOptimizedResult(result);
|
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)
|
public object Get(GetItemByNameImageInfos request)
|
||||||
{
|
{
|
||||||
var result = GetItemByNameImageInfos(request);
|
var result = GetItemByNameImageInfos(request);
|
||||||
|
@ -540,7 +464,7 @@ namespace MediaBrowser.Api.Images
|
||||||
return list;
|
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
|
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>
|
/// <summary>
|
||||||
/// Gets the specified request.
|
/// Gets the specified request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -659,20 +576,6 @@ namespace MediaBrowser.Api.Images
|
||||||
Task.WaitAll(task);
|
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>
|
/// <summary>
|
||||||
/// Deletes the specified request.
|
/// Deletes the specified request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -699,15 +602,6 @@ namespace MediaBrowser.Api.Images
|
||||||
Task.WaitAll(task);
|
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>
|
/// <summary>
|
||||||
/// Deletes the specified request.
|
/// Deletes the specified request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -762,71 +656,9 @@ namespace MediaBrowser.Api.Images
|
||||||
/// <param name="newIndex">The new index.</param>
|
/// <param name="newIndex">The new index.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
/// <exception cref="System.ArgumentException">The change index operation is only applicable to backdrops and screenshots</exception>
|
/// <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;
|
return item.SwapImages(type, currentIndex, newIndex);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -837,7 +669,7 @@ namespace MediaBrowser.Api.Images
|
||||||
/// <returns>System.Object.</returns>
|
/// <returns>System.Object.</returns>
|
||||||
/// <exception cref="ResourceNotFoundException">
|
/// <exception cref="ResourceNotFoundException">
|
||||||
/// </exception>
|
/// </exception>
|
||||||
private object GetImage(ImageRequest request, BaseItem item)
|
public object GetImage(ImageRequest request, IHasImages item)
|
||||||
{
|
{
|
||||||
var imagePath = GetImagePath(request, item);
|
var imagePath = GetImagePath(request, item);
|
||||||
|
|
||||||
|
@ -926,7 +758,7 @@ namespace MediaBrowser.Api.Images
|
||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private string GetImagePath(ImageRequest request, BaseItem item)
|
private string GetImagePath(ImageRequest request, IHasImages item)
|
||||||
{
|
{
|
||||||
var index = request.Index ?? 0;
|
var index = request.Index ?? 0;
|
||||||
|
|
||||||
|
@ -941,7 +773,7 @@ namespace MediaBrowser.Api.Images
|
||||||
/// <param name="imageType">Type of the image.</param>
|
/// <param name="imageType">Type of the image.</param>
|
||||||
/// <param name="mimeType">Type of the MIME.</param>
|
/// <param name="mimeType">Type of the MIME.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <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))
|
using (var reader = new StreamReader(inputStream))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using ServiceStack;
|
using ServiceStack.Web;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ServiceStack.Web;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Images
|
namespace MediaBrowser.Api.Images
|
||||||
{
|
{
|
||||||
|
@ -27,7 +26,7 @@ namespace MediaBrowser.Api.Images
|
||||||
/// Gets or sets the item.
|
/// Gets or sets the item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The item.</value>
|
/// <value>The item.</value>
|
||||||
public BaseItem Item { get; set; }
|
public IHasImages Item { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The original image date modified
|
/// The original image date modified
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -146,7 +146,7 @@ namespace MediaBrowser.Api
|
||||||
|
|
||||||
private async Task UpdateItem(UpdateChannel request)
|
private async Task UpdateItem(UpdateChannel request)
|
||||||
{
|
{
|
||||||
var item = _liveTv.GetChannel(request.Id);
|
var item = _liveTv.GetInternalChannel(request.Id);
|
||||||
|
|
||||||
UpdateItem(request, item);
|
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\LibraryHelpers.cs" />
|
||||||
<Compile Include="Library\LibraryService.cs" />
|
<Compile Include="Library\LibraryService.cs" />
|
||||||
<Compile Include="Library\LibraryStructureService.cs" />
|
<Compile Include="Library\LibraryStructureService.cs" />
|
||||||
|
<Compile Include="LiveTv\LiveTvImageService.cs" />
|
||||||
<Compile Include="LiveTv\LiveTvService.cs" />
|
<Compile Include="LiveTv\LiveTvService.cs" />
|
||||||
<Compile Include="LocalizationService.cs" />
|
<Compile Include="LocalizationService.cs" />
|
||||||
<Compile Include="MoviesService.cs" />
|
<Compile Include="MoviesService.cs" />
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.MediaInfo;
|
using MediaBrowser.Common.MediaInfo;
|
||||||
using MediaBrowser.Controller;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaInfo;
|
using MediaBrowser.Controller.MediaInfo;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
|
@ -110,7 +108,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected virtual string GetOutputFileExtension(StreamState state)
|
protected virtual string GetOutputFileExtension(StreamState state)
|
||||||
{
|
{
|
||||||
return Path.GetExtension(state.Url);
|
return Path.GetExtension(state.RequestedUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -187,7 +185,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
var args = string.Empty;
|
var args = string.Empty;
|
||||||
|
|
||||||
if (state.Item.LocationType == LocationType.Remote)
|
if (state.IsRemote)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
@ -331,7 +329,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
string.Equals(state.SubtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase) ||
|
string.Equals(state.SubtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(state.SubtitleStream.Codec, "ssa", 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>
|
/// <summary>
|
||||||
/// Gets the text subtitle param.
|
/// Gets the text subtitle param.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="video">The video.</param>
|
/// <param name="state">The state.</param>
|
||||||
/// <param name="subtitleStream">The subtitle stream.</param>
|
|
||||||
/// <param name="startTimeTicks">The start time ticks.</param>
|
/// <param name="startTimeTicks">The start time ticks.</param>
|
||||||
/// <param name="performConversion">if set to <c>true</c> [perform conversion].</param>
|
/// <param name="performConversion">if set to <c>true</c> [perform conversion].</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <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))
|
if (string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
|
@ -422,22 +420,21 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the extracted ass path.
|
/// Gets the extracted ass path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="video">The video.</param>
|
/// <param name="state">The state.</param>
|
||||||
/// <param name="subtitleStream">The subtitle stream.</param>
|
|
||||||
/// <param name="startTimeTicks">The start time ticks.</param>
|
/// <param name="startTimeTicks">The start time ticks.</param>
|
||||||
/// <param name="performConversion">if set to <c>true</c> [perform conversion].</param>
|
/// <param name="performConversion">if set to <c>true</c> [perform conversion].</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <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 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)
|
if (performConversion)
|
||||||
{
|
{
|
||||||
InputType type;
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -445,7 +442,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
Directory.CreateDirectory(parentPath);
|
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);
|
Task.WaitAll(task);
|
||||||
}
|
}
|
||||||
|
@ -461,22 +458,16 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the converted ass path.
|
/// Gets the converted ass path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="video">The video.</param>
|
/// <param name="mediaPath">The media path.</param>
|
||||||
/// <param name="subtitleStream">The subtitle stream.</param>
|
/// <param name="subtitleStream">The subtitle stream.</param>
|
||||||
/// <param name="startTimeTicks">The start time ticks.</param>
|
/// <param name="startTimeTicks">The start time ticks.</param>
|
||||||
/// <param name="performConversion">if set to <c>true</c> [perform conversion].</param>
|
/// <param name="performConversion">if set to <c>true</c> [perform conversion].</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <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 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)
|
if (performConversion)
|
||||||
{
|
{
|
||||||
|
@ -524,25 +515,15 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the probe size argument.
|
/// Gets the probe size argument.
|
||||||
/// </summary>
|
/// </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>
|
/// <returns>System.String.</returns>
|
||||||
protected string GetProbeSizeArgument(BaseItem item)
|
protected string GetProbeSizeArgument(string mediaPath, bool isVideo, VideoType? videoType, IsoType? isoType)
|
||||||
{
|
{
|
||||||
var type = InputType.AudioFile;
|
var type = !isVideo ? MediaEncoderHelpers.GetInputType(mediaPath, null, null) :
|
||||||
|
MediaEncoderHelpers.GetInputType(mediaPath, videoType, isoType);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MediaEncoder.GetProbeSizeArgument(type);
|
return MediaEncoder.GetProbeSizeArgument(type);
|
||||||
}
|
}
|
||||||
|
@ -652,22 +633,19 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the input argument.
|
/// Gets the input argument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="state">The state.</param>
|
||||||
/// <param name="isoMount">The iso mount.</param>
|
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected string GetInputArgument(BaseItem item, IIsoMount isoMount)
|
protected string GetInputArgument(StreamState state)
|
||||||
{
|
{
|
||||||
var type = InputType.AudioFile;
|
var type = InputType.AudioFile;
|
||||||
|
|
||||||
var inputPath = new[] { item.Path };
|
var inputPath = new[] { state.MediaPath };
|
||||||
|
|
||||||
var video = item as Video;
|
if (state.IsInputVideo)
|
||||||
|
|
||||||
if (video != null)
|
|
||||||
{
|
{
|
||||||
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);
|
Directory.CreateDirectory(parentPath);
|
||||||
|
|
||||||
var video = state.Item as Video;
|
if (state.IsInputVideo && state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath))
|
||||||
|
|
||||||
if (video != null && video.VideoType == VideoType.Iso && video.IsoType.HasValue && IsoManager.CanMount(video.Path))
|
|
||||||
{
|
{
|
||||||
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
|
var process = new Process
|
||||||
|
@ -715,7 +691,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
EnableRaisingEvents = true
|
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);
|
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
|
// Allow a small amount of time to buffer a little
|
||||||
if (state.Item is Video)
|
if (state.IsInputVideo)
|
||||||
{
|
{
|
||||||
await Task.Delay(500).ConfigureAwait(false);
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is arbitrary, but add a little buffer time when internet streaming
|
// 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);
|
await Task.Delay(4000).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -787,11 +763,11 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user agent param.
|
/// Gets the user agent param.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <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))
|
if (!string.IsNullOrEmpty(useragent))
|
||||||
{
|
{
|
||||||
|
@ -804,11 +780,11 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user agent.
|
/// Gets the user agent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="path">The path.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <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";
|
return "QuickTime/7.7.4";
|
||||||
}
|
}
|
||||||
|
@ -852,8 +828,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
var item = DtoService.GetItemByDtoId(request.Id);
|
var item = DtoService.GetItemByDtoId(request.Id);
|
||||||
|
|
||||||
var media = (IHasMediaStreams)item;
|
|
||||||
|
|
||||||
var url = Request.PathInfo;
|
var url = Request.PathInfo;
|
||||||
|
|
||||||
if (!request.AudioCodec.HasValue)
|
if (!request.AudioCodec.HasValue)
|
||||||
|
@ -863,11 +837,25 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
var state = new StreamState
|
var state = new StreamState
|
||||||
{
|
{
|
||||||
Item = item,
|
|
||||||
Request = request,
|
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 videoRequest = request as VideoStreamRequest;
|
||||||
|
|
||||||
var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery
|
var mediaStreams = ItemRepository.GetMediaStreams(new MediaStreamQuery
|
||||||
|
|
|
@ -4,7 +4,6 @@ using MediaBrowser.Common.MediaInfo;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
|
@ -247,7 +246,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool performSubtitleConversions)
|
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;
|
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}\"",
|
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,
|
itsOffset,
|
||||||
probeSize,
|
probeSize,
|
||||||
GetUserAgentParam(state.Item),
|
GetUserAgentParam(state.MediaPath),
|
||||||
GetFastSeekCommandLineParameter(state.Request),
|
GetFastSeekCommandLineParameter(state.Request),
|
||||||
GetInputArgument(state.Item, state.IsoMount),
|
GetInputArgument(state),
|
||||||
GetSlowSeekCommandLineParameter(state.Request),
|
GetSlowSeekCommandLineParameter(state.Request),
|
||||||
threads,
|
threads,
|
||||||
GetMapArgs(state),
|
GetMapArgs(state),
|
||||||
|
@ -275,7 +274,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
if (hlsVideoRequest != null)
|
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");
|
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}\"",
|
return string.Format("{0} -i {1}{2} -threads {3}{4} {5} -id3v2_version 3 -write_id3v1 1 \"{6}\"",
|
||||||
GetFastSeekCommandLineParameter(request),
|
GetFastSeekCommandLineParameter(request),
|
||||||
GetInputArgument(state.Item, state.IsoMount),
|
GetInputArgument(state),
|
||||||
GetSlowSeekCommandLineParameter(request),
|
GetSlowSeekCommandLineParameter(request),
|
||||||
threads,
|
threads,
|
||||||
vn,
|
vn,
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
using MediaBrowser.Api.Images;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Common.MediaInfo;
|
using MediaBrowser.Common.MediaInfo;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -51,9 +47,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
// Try to infer based on the desired video codec
|
// Try to infer based on the desired video codec
|
||||||
if (videoRequest != null && videoRequest.VideoCodec.HasValue)
|
if (videoRequest != null && videoRequest.VideoCodec.HasValue)
|
||||||
{
|
{
|
||||||
var video = state.Item as Video;
|
if (state.IsInputVideo)
|
||||||
|
|
||||||
if (video != null)
|
|
||||||
{
|
{
|
||||||
switch (videoRequest.VideoCodec.Value)
|
switch (videoRequest.VideoCodec.Value)
|
||||||
{
|
{
|
||||||
|
@ -72,9 +66,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
// Try to infer based on the desired audio codec
|
// Try to infer based on the desired audio codec
|
||||||
if (state.Request.AudioCodec.HasValue)
|
if (state.Request.AudioCodec.HasValue)
|
||||||
{
|
{
|
||||||
var audio = state.Item as Audio;
|
if (!state.IsInputVideo)
|
||||||
|
|
||||||
if (audio != null)
|
|
||||||
{
|
{
|
||||||
switch (state.Request.AudioCodec.Value)
|
switch (state.Request.AudioCodec.Value)
|
||||||
{
|
{
|
||||||
|
@ -188,16 +180,11 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
{
|
{
|
||||||
var state = GetState(request);
|
var state = GetState(request);
|
||||||
|
|
||||||
if (request.AlbumArt)
|
|
||||||
{
|
|
||||||
return GetAlbumArtResponse(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
var responseHeaders = new Dictionary<string, string>();
|
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);
|
var outputPath = GetOutputFilePath(state);
|
||||||
|
@ -210,7 +197,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
|
|
||||||
if (request.Static)
|
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))
|
if (outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive))
|
||||||
|
@ -224,19 +211,19 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the static remote stream result.
|
/// Gets the static remote stream result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="mediaPath">The media path.</param>
|
||||||
/// <param name="responseHeaders">The response headers.</param>
|
/// <param name="responseHeaders">The response headers.</param>
|
||||||
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
|
||||||
/// <returns>Task{System.Object}.</returns>
|
/// <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";
|
responseHeaders["Accept-Ranges"] = "none";
|
||||||
|
|
||||||
var httpClient = new HttpClient();
|
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))
|
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>
|
/// <summary>
|
||||||
/// Gets the stream result.
|
/// Gets the stream result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -3,7 +3,6 @@ using MediaBrowser.Common.MediaInfo;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Dto;
|
using MediaBrowser.Controller.Dto;
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Persistence;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
@ -89,9 +88,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool performSubtitleConversions)
|
protected override string GetCommandLineArguments(string outputPath, StreamState state, bool performSubtitleConversions)
|
||||||
{
|
{
|
||||||
var video = (Video)state.Item;
|
var probeSize = GetProbeSizeArgument(state.MediaPath, state.IsInputVideo, state.VideoType, state.IsoType);
|
||||||
|
|
||||||
var probeSize = GetProbeSizeArgument(state.Item);
|
|
||||||
|
|
||||||
// Get the output codec name
|
// Get the output codec name
|
||||||
var videoCodec = GetVideoCodec(state.VideoRequest);
|
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}\"",
|
return string.Format("{0} {1} {2} -i {3}{4}{5} {6} {7} -threads {8} {9}{10} \"{11}\"",
|
||||||
probeSize,
|
probeSize,
|
||||||
GetUserAgentParam(state.Item),
|
GetUserAgentParam(state.MediaPath),
|
||||||
GetFastSeekCommandLineParameter(state.Request),
|
GetFastSeekCommandLineParameter(state.Request),
|
||||||
GetInputArgument(video, state.IsoMount),
|
GetInputArgument(state),
|
||||||
GetSlowSeekCommandLineParameter(state.Request),
|
GetSlowSeekCommandLineParameter(state.Request),
|
||||||
keyFrame,
|
keyFrame,
|
||||||
GetMapArgs(state),
|
GetMapArgs(state),
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
using System.IO;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Controller.Entities;
|
|
||||||
using MediaBrowser.Model.Entities;
|
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
public class StreamState
|
public class StreamState
|
||||||
{
|
{
|
||||||
public string Url { get; set; }
|
public string RequestedUrl { get; set; }
|
||||||
|
|
||||||
public StreamRequest Request { get; set; }
|
public StreamRequest Request { get; set; }
|
||||||
|
|
||||||
|
@ -29,12 +28,22 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
public MediaStream SubtitleStream { get; set; }
|
public MediaStream SubtitleStream { get; set; }
|
||||||
|
|
||||||
public BaseItem Item { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the iso mount.
|
/// Gets or sets the iso mount.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The iso mount.</value>
|
/// <value>The iso mount.</value>
|
||||||
public IIsoMount IsoMount { get; set; }
|
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))
|
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;
|
var episode = item as Episode;
|
||||||
|
|
|
@ -216,6 +216,48 @@ namespace MediaBrowser.Common.Implementations.IO
|
||||||
|
|
||||||
return new FileStream(path, mode, access, share);
|
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>
|
/// <summary>
|
||||||
|
|
|
@ -74,5 +74,12 @@ namespace MediaBrowser.Common.IO
|
||||||
/// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
|
/// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
|
||||||
/// <returns>FileStream.</returns>
|
/// <returns>FileStream.</returns>
|
||||||
FileStream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share, bool isAsync = false);
|
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="item">The item.</param>
|
||||||
/// <param name="imageType">Type of the image.</param>
|
/// <param name="imageType">Type of the image.</param>
|
||||||
/// <returns>IEnumerable{IImageEnhancer}.</returns>
|
/// <returns>IEnumerable{IImageEnhancer}.</returns>
|
||||||
IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType);
|
IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasImages item, ImageType imageType);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the image cache tag.
|
/// Gets the image cache tag.
|
||||||
|
@ -56,7 +56,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||||
/// <param name="imageType">Type of the image.</param>
|
/// <param name="imageType">Type of the image.</param>
|
||||||
/// <param name="imagePath">The image path.</param>
|
/// <param name="imagePath">The image path.</param>
|
||||||
/// <returns>Guid.</returns>
|
/// <returns>Guid.</returns>
|
||||||
Guid GetImageCacheTag(BaseItem item, ImageType imageType, string imagePath);
|
Guid GetImageCacheTag(IHasImages item, ImageType imageType, string imagePath);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the image cache tag.
|
/// Gets the image cache tag.
|
||||||
|
@ -67,7 +67,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||||
/// <param name="dateModified">The date modified.</param>
|
/// <param name="dateModified">The date modified.</param>
|
||||||
/// <param name="imageEnhancers">The image enhancers.</param>
|
/// <param name="imageEnhancers">The image enhancers.</param>
|
||||||
/// <returns>Guid.</returns>
|
/// <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);
|
List<IImageEnhancer> imageEnhancers);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -85,6 +85,6 @@ namespace MediaBrowser.Controller.Drawing
|
||||||
/// <param name="imageType">Type of the image.</param>
|
/// <param name="imageType">Type of the image.</param>
|
||||||
/// <param name="imageIndex">Index of the image.</param>
|
/// <param name="imageIndex">Index of the image.</param>
|
||||||
/// <returns>Task{System.String}.</returns>
|
/// <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 class ImageProcessingOptions
|
||||||
{
|
{
|
||||||
public BaseItem Item { get; set; }
|
public IHasImages Item { get; set; }
|
||||||
|
|
||||||
public ImageType ImageType { get; set; }
|
public ImageType ImageType { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class BaseItem
|
/// Class BaseItem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseItem : IHasProviderIds, ILibraryItem
|
public abstract class BaseItem : IHasProviderIds, ILibraryItem, IHasImages, IHasUserData
|
||||||
{
|
{
|
||||||
protected BaseItem()
|
protected BaseItem()
|
||||||
{
|
{
|
||||||
|
@ -132,8 +132,8 @@ namespace MediaBrowser.Controller.Entities
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public string PrimaryImagePath
|
public string PrimaryImagePath
|
||||||
{
|
{
|
||||||
get { return GetImage(ImageType.Primary); }
|
get { return this.GetImagePath(ImageType.Primary); }
|
||||||
set { SetImage(ImageType.Primary, value); }
|
set { this.SetImagePath(ImageType.Primary, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1310,31 +1310,10 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// Gets an image
|
/// Gets an image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="type">The type.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <param name="imageIndex">Index of the image.</param>
|
||||||
/// <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>
|
|
||||||
/// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns>
|
/// <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>
|
/// <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)
|
if (type == ImageType.Backdrop)
|
||||||
{
|
{
|
||||||
|
@ -1345,16 +1324,10 @@ namespace MediaBrowser.Controller.Entities
|
||||||
throw new ArgumentException("Screenshots should be accessed using Item.Screenshots");
|
throw new ArgumentException("Screenshots should be accessed using Item.Screenshots");
|
||||||
}
|
}
|
||||||
|
|
||||||
return !string.IsNullOrEmpty(GetImage(type));
|
return !string.IsNullOrEmpty(this.GetImagePath(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public void SetImagePath(ImageType type, int index, string path)
|
||||||
/// 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)
|
|
||||||
{
|
{
|
||||||
if (type == ImageType.Backdrop)
|
if (type == ImageType.Backdrop)
|
||||||
{
|
{
|
||||||
|
@ -1423,10 +1396,10 @@ namespace MediaBrowser.Controller.Entities
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Delete the source file
|
// Delete the source file
|
||||||
DeleteImagePath(GetImage(type));
|
DeleteImagePath(this.GetImagePath(type));
|
||||||
|
|
||||||
// Remove it from the item
|
// Remove it from the item
|
||||||
SetImage(type, null);
|
this.SetImagePath(type, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh metadata
|
// Refresh metadata
|
||||||
|
@ -1597,13 +1570,13 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
if (imageType == ImageType.Backdrop)
|
if (imageType == ImageType.Backdrop)
|
||||||
{
|
{
|
||||||
return BackdropImagePaths[imageIndex];
|
return BackdropImagePaths.Count > imageIndex ? BackdropImagePaths[imageIndex] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageType == ImageType.Screenshot)
|
if (imageType == ImageType.Screenshot)
|
||||||
{
|
{
|
||||||
var hasScreenshots = (IHasScreenshots)this;
|
var hasScreenshots = (IHasScreenshots)this;
|
||||||
return hasScreenshots.ScreenshotImagePaths[imageIndex];
|
return hasScreenshots.ScreenshotImagePaths.Count > imageIndex ? hasScreenshots.ScreenshotImagePaths[imageIndex] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageType == ImageType.Chapter)
|
if (imageType == ImageType.Chapter)
|
||||||
|
@ -1611,7 +1584,9 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return ItemRepository.GetChapter(Id, imageIndex).ImagePath;
|
return ItemRepository.GetChapter(Id, imageIndex).ImagePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetImage(imageType);
|
string val;
|
||||||
|
Images.TryGetValue(imageType, out val);
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1658,5 +1633,21 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
return new[] { Path };
|
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);
|
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>();
|
.Cast<Episode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// <param name="reason">The reason.</param>
|
/// <param name="reason">The reason.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <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>
|
/// <summary>
|
||||||
/// Gets the user data.
|
/// Gets the user data.
|
||||||
|
|
|
@ -37,6 +37,6 @@ namespace MediaBrowser.Controller.Library
|
||||||
/// Gets or sets the item.
|
/// Gets or sets the item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The item.</value>
|
/// <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; }
|
public ChannelType ChannelType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this value to true or false if it is known via channel info whether there is an image or not.
|
/// Supply the image path if it can be accessed directly from the file system
|
||||||
/// Leave it null if the only way to determine is by requesting the image and handling the failure.
|
|
||||||
/// </summary>
|
/// </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,7 +144,15 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The identifier.</param>
|
/// <param name="id">The identifier.</param>
|
||||||
/// <returns>Channel.</returns>
|
/// <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>
|
/// <summary>
|
||||||
/// Gets the program.
|
/// Gets the program.
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken);
|
Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <param name="channelId">The channel identifier.</param>
|
/// <param name="channelId">The channel identifier.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
@ -87,7 +87,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
Task<ImageResponseInfo> GetChannelImageAsync(string channelId, CancellationToken cancellationToken);
|
Task<ImageResponseInfo> GetChannelImageAsync(string channelId, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <param name="recordingId">The recording identifier.</param>
|
/// <param name="recordingId">The recording identifier.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
@ -95,7 +95,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
Task<ImageResponseInfo> GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken);
|
Task<ImageResponseInfo> GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
/// <param name="programId">The program identifier.</param>
|
/// <param name="programId">The program identifier.</param>
|
||||||
/// <param name="channelId">The channel 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; }
|
public string EpisodeTitle { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this value to true or false if it is known via program info whether there is an image or not.
|
/// Supply the image path if it can be accessed directly from the file system
|
||||||
/// Leave it null if the only way to determine is by requesting the image and handling the failure.
|
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether this instance is movie.
|
/// Gets or sets a value indicating whether this instance is movie.
|
||||||
|
@ -121,6 +127,12 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
|
||||||
public bool IsSeries { get; set; }
|
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()
|
public ProgramInfo()
|
||||||
{
|
{
|
||||||
Genres = new List<string>();
|
Genres = new List<string>();
|
||||||
|
|
|
@ -114,10 +114,16 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
public float? CommunityRating { get; set; }
|
public float? CommunityRating { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this value to true or false if it is known via recording info whether there is an image or not.
|
/// Supply the image path if it can be accessed directly from the file system
|
||||||
/// Leave it null if the only way to determine is by requesting the image and handling the failure.
|
|
||||||
/// </summary>
|
/// </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()
|
public RecordingInfo()
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
<Compile Include="Entities\IHasAspectRatio.cs" />
|
<Compile Include="Entities\IHasAspectRatio.cs" />
|
||||||
<Compile Include="Entities\IHasBudget.cs" />
|
<Compile Include="Entities\IHasBudget.cs" />
|
||||||
<Compile Include="Entities\IHasCriticRating.cs" />
|
<Compile Include="Entities\IHasCriticRating.cs" />
|
||||||
|
<Compile Include="Entities\IHasImages.cs" />
|
||||||
<Compile Include="Entities\IHasLanguage.cs" />
|
<Compile Include="Entities\IHasLanguage.cs" />
|
||||||
<Compile Include="Entities\IHasMediaStreams.cs" />
|
<Compile Include="Entities\IHasMediaStreams.cs" />
|
||||||
<Compile Include="Entities\IHasProductionLocations.cs" />
|
<Compile Include="Entities\IHasProductionLocations.cs" />
|
||||||
|
@ -94,6 +95,7 @@
|
||||||
<Compile Include="Entities\IHasTags.cs" />
|
<Compile Include="Entities\IHasTags.cs" />
|
||||||
<Compile Include="Entities\IHasThemeMedia.cs" />
|
<Compile Include="Entities\IHasThemeMedia.cs" />
|
||||||
<Compile Include="Entities\IHasTrailers.cs" />
|
<Compile Include="Entities\IHasTrailers.cs" />
|
||||||
|
<Compile Include="Entities\IHasUserData.cs" />
|
||||||
<Compile Include="Entities\IItemByName.cs" />
|
<Compile Include="Entities\IItemByName.cs" />
|
||||||
<Compile Include="Entities\ILibraryItem.cs" />
|
<Compile Include="Entities\ILibraryItem.cs" />
|
||||||
<Compile Include="Entities\ImageSourceInfo.cs" />
|
<Compile Include="Entities\ImageSourceInfo.cs" />
|
||||||
|
@ -106,11 +108,13 @@
|
||||||
<Compile Include="Library\ItemUpdateType.cs" />
|
<Compile Include="Library\ItemUpdateType.cs" />
|
||||||
<Compile Include="Library\IUserDataManager.cs" />
|
<Compile Include="Library\IUserDataManager.cs" />
|
||||||
<Compile Include="Library\UserDataSaveEventArgs.cs" />
|
<Compile Include="Library\UserDataSaveEventArgs.cs" />
|
||||||
<Compile Include="LiveTv\Channel.cs" />
|
<Compile Include="LiveTv\LiveTvChannel.cs" />
|
||||||
<Compile Include="LiveTv\ChannelInfo.cs" />
|
<Compile Include="LiveTv\ChannelInfo.cs" />
|
||||||
<Compile Include="LiveTv\ILiveTvManager.cs" />
|
<Compile Include="LiveTv\ILiveTvManager.cs" />
|
||||||
<Compile Include="LiveTv\ILiveTvService.cs" />
|
<Compile Include="LiveTv\ILiveTvService.cs" />
|
||||||
<Compile Include="LiveTv\ImageResponseInfo.cs" />
|
<Compile Include="LiveTv\ImageResponseInfo.cs" />
|
||||||
|
<Compile Include="LiveTv\LiveTvProgram.cs" />
|
||||||
|
<Compile Include="LiveTv\LiveTvRecording.cs" />
|
||||||
<Compile Include="LiveTv\ProgramInfo.cs" />
|
<Compile Include="LiveTv\ProgramInfo.cs" />
|
||||||
<Compile Include="LiveTv\RecordingInfo.cs" />
|
<Compile Include="LiveTv\RecordingInfo.cs" />
|
||||||
<Compile Include="LiveTv\SeriesTimerInfo.cs" />
|
<Compile Include="LiveTv\SeriesTimerInfo.cs" />
|
||||||
|
|
|
@ -170,7 +170,7 @@ namespace MediaBrowser.Controller.MediaInfo
|
||||||
|
|
||||||
InputType type;
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -233,33 +233,23 @@ namespace MediaBrowser.Controller.MediaInfo
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the subtitle cache path.
|
/// Gets the subtitle cache path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">The input.</param>
|
/// <param name="mediaPath">The media path.</param>
|
||||||
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
|
/// <param name="subtitleStream">The subtitle stream.</param>
|
||||||
/// <param name="offset">The offset.</param>
|
/// <param name="offset">The offset.</param>
|
||||||
/// <param name="outputExtension">The output extension.</param>
|
/// <param name="outputExtension">The output extension.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <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 ticksParam = offset.HasValue ? "_" + offset.Value.Ticks : "";
|
||||||
|
|
||||||
var stream = _itemRepo.GetMediaStreams(new MediaStreamQuery
|
if (subtitleStream.IsExternal)
|
||||||
{
|
{
|
||||||
ItemId = input.Id,
|
ticksParam += _fileSystem.GetLastWriteTimeUtc(subtitleStream.Path).Ticks;
|
||||||
Index = subtitleStreamIndex
|
|
||||||
|
|
||||||
}).FirstOrDefault();
|
|
||||||
|
|
||||||
if (stream == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream.IsExternal)
|
var date = _fileSystem.GetLastWriteTimeUtc(mediaPath);
|
||||||
{
|
|
||||||
ticksParam += _fileSystem.GetLastWriteTimeUtc(stream.Path).Ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
var prefix = filename.Substring(0, 1);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
using MediaBrowser.Common.MediaInfo;
|
using System;
|
||||||
using MediaBrowser.Controller.Entities;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using MediaBrowser.Common.MediaInfo;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
|
@ -13,43 +16,47 @@ namespace MediaBrowser.Controller.MediaInfo
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the input argument.
|
/// Gets the input argument.
|
||||||
/// </summary>
|
/// </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="isoMount">The iso mount.</param>
|
||||||
|
/// <param name="playableStreamFileNames">The playable stream file names.</param>
|
||||||
/// <param name="type">The type.</param>
|
/// <param name="type">The type.</param>
|
||||||
/// <returns>System.String[][].</returns>
|
/// <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;
|
type = InputType.VideoFile;
|
||||||
|
|
||||||
switch (video.VideoType)
|
switch (videoType)
|
||||||
{
|
{
|
||||||
case VideoType.BluRay:
|
case VideoType.BluRay:
|
||||||
type = InputType.Bluray;
|
type = InputType.Bluray;
|
||||||
break;
|
break;
|
||||||
case VideoType.Dvd:
|
case VideoType.Dvd:
|
||||||
type = InputType.Dvd;
|
type = InputType.Dvd;
|
||||||
inputPath = video.GetPlayableStreamFiles(inputPath[0]).ToArray();
|
inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
|
||||||
break;
|
break;
|
||||||
case VideoType.Iso:
|
case VideoType.Iso:
|
||||||
if (video.IsoType.HasValue)
|
if (isoType.HasValue)
|
||||||
{
|
{
|
||||||
switch (video.IsoType.Value)
|
switch (isoType.Value)
|
||||||
{
|
{
|
||||||
case IsoType.BluRay:
|
case IsoType.BluRay:
|
||||||
type = InputType.Bluray;
|
type = InputType.Bluray;
|
||||||
break;
|
break;
|
||||||
case IsoType.Dvd:
|
case IsoType.Dvd:
|
||||||
type = InputType.Dvd;
|
type = InputType.Dvd;
|
||||||
inputPath = video.GetPlayableStreamFiles(inputPath[0]).ToArray();
|
inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VideoType.VideoFile:
|
case VideoType.VideoFile:
|
||||||
{
|
{
|
||||||
if (video.LocationType == LocationType.Remote)
|
if (isRemote)
|
||||||
{
|
{
|
||||||
type = InputType.Url;
|
type = InputType.Url;
|
||||||
}
|
}
|
||||||
|
@ -60,6 +67,17 @@ namespace MediaBrowser.Controller.MediaInfo
|
||||||
return inputPath;
|
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>
|
/// <summary>
|
||||||
/// Gets the type of the input.
|
/// Gets the type of the input.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Providers
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <param name="imageType">Type of the image.</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>
|
/// <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>
|
/// <summary>
|
||||||
/// Gets the priority or order in which this enhancer should be run.
|
/// 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="item">The item.</param>
|
||||||
/// <param name="imageType">Type of the image.</param>
|
/// <param name="imageType">Type of the image.</param>
|
||||||
/// <returns>Cache key relating to the current state of this item and configuration</returns>
|
/// <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>
|
/// <summary>
|
||||||
/// Gets the size of the enhanced image.
|
/// 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="imageIndex">Index of the image.</param>
|
||||||
/// <param name="originalImageSize">Size of the original image.</param>
|
/// <param name="originalImageSize">Size of the original image.</param>
|
||||||
/// <returns>ImageSize.</returns>
|
/// <returns>ImageSize.</returns>
|
||||||
ImageSize GetEnhancedImageSize(BaseItem item, ImageType imageType, int imageIndex, ImageSize originalImageSize);
|
ImageSize GetEnhancedImageSize(IHasImages item, ImageType imageType, int imageIndex, ImageSize originalImageSize);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enhances the image async.
|
/// Enhances the image async.
|
||||||
|
@ -49,6 +49,6 @@ namespace MediaBrowser.Controller.Providers
|
||||||
/// <param name="imageIndex">Index of the image.</param>
|
/// <param name="imageIndex">Index of the image.</param>
|
||||||
/// <returns>Task{Image}.</returns>
|
/// <returns>Task{Image}.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException"></exception>
|
/// <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;
|
EnableVideoImageExtraction = true;
|
||||||
|
|
||||||
EnableMovieChapterImageExtraction = true;
|
EnableMovieChapterImageExtraction = true;
|
||||||
EnableEpisodeChapterImageExtraction = true;
|
EnableEpisodeChapterImageExtraction = false;
|
||||||
EnableOtherVideoChapterImageExtraction = true;
|
EnableOtherVideoChapterImageExtraction = false;
|
||||||
|
|
||||||
#if (DEBUG)
|
#if (DEBUG)
|
||||||
EnableDeveloperTools = true;
|
EnableDeveloperTools = true;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.LiveTv
|
namespace MediaBrowser.Model.LiveTv
|
||||||
{
|
{
|
||||||
|
@ -108,6 +109,12 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
/// <value>The episode title.</value>
|
/// <value>The episode title.</value>
|
||||||
public string EpisodeTitle { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Gets or sets the user data.
|
/// Gets or sets the user data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -132,9 +139,16 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
|
||||||
public bool IsSeries { get; set; }
|
public bool IsSeries { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type.</value>
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
public ProgramInfoDto()
|
public ProgramInfoDto()
|
||||||
{
|
{
|
||||||
Genres = new List<string>();
|
Genres = new List<string>();
|
||||||
|
ImageTags = new Dictionary<ImageType, Guid>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.LiveTv
|
namespace MediaBrowser.Model.LiveTv
|
||||||
{
|
{
|
||||||
|
@ -136,15 +137,28 @@ namespace MediaBrowser.Model.LiveTv
|
||||||
/// <value>The audio.</value>
|
/// <value>The audio.</value>
|
||||||
public ProgramAudio? Audio { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Gets or sets the user data.
|
/// Gets or sets the user data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The user data.</value>
|
/// <value>The user data.</value>
|
||||||
public UserItemDataDto UserData { get; set; }
|
public UserItemDataDto UserData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The type.</value>
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
public RecordingInfoDto()
|
public RecordingInfoDto()
|
||||||
{
|
{
|
||||||
Genres = new List<string>();
|
Genres = new List<string>();
|
||||||
|
ImageTags = new Dictionary<ImageType, Guid>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,6 +16,12 @@
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The user identifier.</value>
|
/// <value>The user identifier.</value>
|
||||||
public string UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The identifier.</value>
|
||||||
|
public string Id { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TimerQuery
|
public class TimerQuery
|
||||||
|
|
|
@ -212,7 +212,7 @@ namespace MediaBrowser.Providers
|
||||||
|
|
||||||
if (image != null)
|
if (image != null)
|
||||||
{
|
{
|
||||||
item.SetImage(ImageType.Logo, image.FullName);
|
item.SetImagePath(ImageType.Logo, image.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clearart
|
// Clearart
|
||||||
|
@ -220,7 +220,7 @@ namespace MediaBrowser.Providers
|
||||||
|
|
||||||
if (image != null)
|
if (image != null)
|
||||||
{
|
{
|
||||||
item.SetImage(ImageType.Art, image.FullName);
|
item.SetImagePath(ImageType.Art, image.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disc
|
// Disc
|
||||||
|
@ -229,7 +229,7 @@ namespace MediaBrowser.Providers
|
||||||
|
|
||||||
if (image != null)
|
if (image != null)
|
||||||
{
|
{
|
||||||
item.SetImage(ImageType.Disc, image.FullName);
|
item.SetImagePath(ImageType.Disc, image.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Box Image
|
// Box Image
|
||||||
|
@ -237,7 +237,7 @@ namespace MediaBrowser.Providers
|
||||||
|
|
||||||
if (image != null)
|
if (image != null)
|
||||||
{
|
{
|
||||||
item.SetImage(ImageType.Box, image.FullName);
|
item.SetImagePath(ImageType.Box, image.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// BoxRear Image
|
// BoxRear Image
|
||||||
|
@ -245,7 +245,7 @@ namespace MediaBrowser.Providers
|
||||||
|
|
||||||
if (image != null)
|
if (image != null)
|
||||||
{
|
{
|
||||||
item.SetImage(ImageType.BoxRear, image.FullName);
|
item.SetImagePath(ImageType.BoxRear, image.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thumbnail Image
|
// Thumbnail Image
|
||||||
|
@ -253,7 +253,7 @@ namespace MediaBrowser.Providers
|
||||||
|
|
||||||
if (image != null)
|
if (image != null)
|
||||||
{
|
{
|
||||||
item.SetImage(ImageType.Menu, image.FullName);
|
item.SetImagePath(ImageType.Menu, image.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
PopulateBanner(item, args);
|
PopulateBanner(item, args);
|
||||||
|
@ -311,7 +311,7 @@ namespace MediaBrowser.Providers
|
||||||
|
|
||||||
if (image != null)
|
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)
|
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)
|
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>
|
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||||
public override bool Supports(BaseItem item)
|
public override bool Supports(BaseItem item)
|
||||||
{
|
{
|
||||||
return item is Channel;
|
return item is LiveTvChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -74,7 +74,7 @@ namespace MediaBrowser.Providers.LiveTv
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
new BaseItemXmlParser<Channel>(Logger).Fetch((Channel)item, path, cancellationToken);
|
new BaseItemXmlParser<LiveTvChannel>(Logger).Fetch((LiveTvChannel)item, path, cancellationToken);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
@ -115,7 +115,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
|
|
||||||
if (video != null)
|
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);
|
return await MediaEncoder.GetMediaInfo(inputPath, type, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
|
@ -253,7 +253,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
|
|
||||||
InputType type;
|
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);
|
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 new metadata has been downloaded or metadata was manually edited, proceed
|
||||||
if ((wasMetadataEdited || wasMetadataDownloaded))
|
if ((wasMetadataEdited || wasMetadataDownloaded))
|
||||||
{
|
{
|
||||||
return item is Channel;
|
return item is LiveTvChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -594,7 +594,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
/// <param name="imagePath">The image path.</param>
|
/// <param name="imagePath">The image path.</param>
|
||||||
/// <returns>Guid.</returns>
|
/// <returns>Guid.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException">item</exception>
|
/// <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)
|
if (item == null)
|
||||||
{
|
{
|
||||||
|
@ -623,7 +623,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
/// <param name="imageEnhancers">The image enhancers.</param>
|
/// <param name="imageEnhancers">The image enhancers.</param>
|
||||||
/// <returns>Guid.</returns>
|
/// <returns>Guid.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException">item</exception>
|
/// <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)
|
if (item == null)
|
||||||
{
|
{
|
||||||
|
@ -660,7 +660,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
/// <param name="imageType">Type of the image.</param>
|
/// <param name="imageType">Type of the image.</param>
|
||||||
/// <param name="imageIndex">Index of the image.</param>
|
/// <param name="imageIndex">Index of the image.</param>
|
||||||
/// <returns>Task{System.String}.</returns>
|
/// <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();
|
var enhancers = GetSupportedEnhancers(item, imageType).ToList();
|
||||||
|
|
||||||
|
@ -673,7 +673,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
return result.Item1;
|
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,
|
ImageType imageType, int imageIndex,
|
||||||
List<IImageEnhancer> enhancers)
|
List<IImageEnhancer> enhancers)
|
||||||
{
|
{
|
||||||
|
@ -709,7 +709,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
/// <param name="supportedEnhancers">The supported enhancers.</param>
|
/// <param name="supportedEnhancers">The supported enhancers.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException">originalImagePath</exception>
|
/// <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))
|
if (string.IsNullOrEmpty(originalImagePath))
|
||||||
{
|
{
|
||||||
|
@ -782,7 +782,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
/// <param name="imageType">Type of the image.</param>
|
/// <param name="imageType">Type of the image.</param>
|
||||||
/// <param name="imageIndex">Index of the image.</param>
|
/// <param name="imageIndex">Index of the image.</param>
|
||||||
/// <returns>Task{EnhancedImage}.</returns>
|
/// <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;
|
var result = originalImage;
|
||||||
|
|
||||||
|
@ -900,7 +900,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
|
||||||
return Path.Combine(path, filename);
|
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 =>
|
return ImageEnhancers.Where(i =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -818,7 +818,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
{
|
{
|
||||||
dto.ParentLogoItemId = GetDtoId(parentWithLogo);
|
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.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.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))
|
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;
|
var imagePath = series.PrimaryImagePath;
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
/// userId
|
/// userId
|
||||||
/// or
|
/// or
|
||||||
/// key</exception>
|
/// 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)
|
if (userData == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
@ -21,18 +22,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
private readonly ILiveTvManager _liveTvManager;
|
private readonly ILiveTvManager _liveTvManager;
|
||||||
private readonly IProviderManager _providerManager;
|
private readonly IProviderManager _providerManager;
|
||||||
private readonly IFileSystem _fileSystem;
|
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)
|
: base(logManager, configurationManager)
|
||||||
{
|
{
|
||||||
_liveTvManager = liveTvManager;
|
_liveTvManager = liveTvManager;
|
||||||
_providerManager = providerManager;
|
_providerManager = providerManager;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
|
_httpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Supports(BaseItem item)
|
public override bool Supports(BaseItem item)
|
||||||
{
|
{
|
||||||
return item is Channel;
|
return item is LiveTvChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
|
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
|
||||||
|
@ -48,13 +51,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var channel = (Channel)item;
|
|
||||||
|
|
||||||
if (channel.HasProviderImage ?? true)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await DownloadImage(item, cancellationToken).ConfigureAwait(false);
|
await DownloadImage((LiveTvChannel)item, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (HttpException ex)
|
catch (HttpException ex)
|
||||||
{
|
{
|
||||||
|
@ -64,26 +63,60 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
|
SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
|
||||||
return true;
|
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 (!string.IsNullOrEmpty(channelInfo.ImagePath))
|
||||||
|
{
|
||||||
|
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)
|
if (service != null)
|
||||||
{
|
{
|
||||||
var response = await service.GetChannelImageAsync(channel.ChannelId, cancellationToken).ConfigureAwait(false);
|
var response = await service.GetChannelImageAsync(channelInfo.Id, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
imageStream = response.Stream;
|
||||||
|
contentType = response.MimeType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageStream != null)
|
||||||
|
{
|
||||||
// Dummy up the original url
|
// 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;
|
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
|
var dto = new RecordingInfoDto
|
||||||
{
|
{
|
||||||
Id = GetInternalRecordingId(service.Name, info.Id).ToString("N"),
|
Id = GetInternalRecordingId(service.Name, info.Id).ToString("N"),
|
||||||
|
Type = recording.GetClientTypeName(),
|
||||||
ChannelName = info.ChannelName,
|
ChannelName = info.ChannelName,
|
||||||
Overview = info.Overview,
|
Overview = info.Overview,
|
||||||
EndDate = info.EndDate,
|
EndDate = info.EndDate,
|
||||||
|
@ -154,7 +172,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
EpisodeTitle = info.EpisodeTitle,
|
EpisodeTitle = info.EpisodeTitle,
|
||||||
ChannelType = info.ChannelType,
|
ChannelType = info.ChannelType,
|
||||||
MediaType = info.ChannelType == ChannelType.Radio ? MediaType.Audio : MediaType.Video,
|
MediaType = info.ChannelType == ChannelType.Radio ? MediaType.Audio : MediaType.Video,
|
||||||
CommunityRating = info.CommunityRating,
|
CommunityRating = GetClientCommunityRating(info.CommunityRating),
|
||||||
OfficialRating = info.OfficialRating,
|
OfficialRating = info.OfficialRating,
|
||||||
Audio = info.Audio,
|
Audio = info.Audio,
|
||||||
IsHD = info.IsHD,
|
IsHD = info.IsHD,
|
||||||
|
@ -162,9 +180,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
Url = info.Url
|
Url = info.Url
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var imageTag = GetImageTag(recording);
|
||||||
|
|
||||||
|
if (imageTag.HasValue)
|
||||||
|
{
|
||||||
|
dto.ImageTags[ImageType.Primary] = imageTag.Value;
|
||||||
|
}
|
||||||
|
|
||||||
if (user != null)
|
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;
|
var duration = info.EndDate - info.StartDate;
|
||||||
|
@ -184,18 +209,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
/// <param name="info">The info.</param>
|
/// <param name="info">The info.</param>
|
||||||
/// <param name="user">The user.</param>
|
/// <param name="user">The user.</param>
|
||||||
/// <returns>ChannelInfoDto.</returns>
|
/// <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
|
var dto = new ChannelInfoDto
|
||||||
{
|
{
|
||||||
Name = info.Name,
|
Name = info.Name,
|
||||||
ServiceName = info.ServiceName,
|
ServiceName = info.ServiceName,
|
||||||
ChannelType = info.ChannelType,
|
ChannelType = channelInfo.ChannelType,
|
||||||
Number = info.ChannelNumber,
|
Number = channelInfo.Number,
|
||||||
Type = info.GetType().Name,
|
Type = info.GetClientTypeName(),
|
||||||
Id = info.Id.ToString("N"),
|
Id = info.Id.ToString("N"),
|
||||||
MediaType = info.MediaType,
|
MediaType = info.MediaType,
|
||||||
ExternalId = info.ChannelId
|
ExternalId = channelInfo.Id
|
||||||
};
|
};
|
||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
|
@ -203,7 +230,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, info.GetUserDataKey()));
|
dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, info.GetUserDataKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageTag = GetLogoImageTag(info);
|
var imageTag = GetImageTag(info);
|
||||||
|
|
||||||
if (imageTag.HasValue)
|
if (imageTag.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -213,7 +240,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
return dto;
|
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
|
var dto = new ProgramInfoDto
|
||||||
{
|
{
|
||||||
|
@ -230,7 +257,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
IsHD = program.IsHD,
|
IsHD = program.IsHD,
|
||||||
OriginalAirDate = program.OriginalAirDate,
|
OriginalAirDate = program.OriginalAirDate,
|
||||||
Audio = program.Audio,
|
Audio = program.Audio,
|
||||||
CommunityRating = program.CommunityRating,
|
CommunityRating = GetClientCommunityRating(program.CommunityRating),
|
||||||
AspectRatio = program.AspectRatio,
|
AspectRatio = program.AspectRatio,
|
||||||
IsRepeat = program.IsRepeat,
|
IsRepeat = program.IsRepeat,
|
||||||
EpisodeTitle = program.EpisodeTitle,
|
EpisodeTitle = program.EpisodeTitle,
|
||||||
|
@ -248,7 +275,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Guid? GetLogoImageTag(Channel info)
|
private Guid? GetImageTag(BaseItem info)
|
||||||
{
|
{
|
||||||
var path = info.PrimaryImagePath;
|
var path = info.PrimaryImagePath;
|
||||||
|
|
||||||
|
@ -263,7 +290,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
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;
|
return null;
|
||||||
|
@ -273,7 +300,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
{
|
{
|
||||||
var name = serviceName + externalId + channelName;
|
var name = serviceName + externalId + channelName;
|
||||||
|
|
||||||
return name.ToLower().GetMBId(typeof(Channel));
|
return name.ToLower().GetMBId(typeof(LiveTvChannel));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid GetInternalTimerId(string serviceName, string externalId)
|
public Guid GetInternalTimerId(string serviceName, string externalId)
|
||||||
|
@ -314,42 +341,54 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
Name = dto.Name,
|
Name = dto.Name,
|
||||||
StartDate = dto.StartDate,
|
StartDate = dto.StartDate,
|
||||||
Status = dto.Status,
|
Status = dto.Status,
|
||||||
SeriesTimerId = dto.ExternalSeriesTimerId,
|
|
||||||
PrePaddingSeconds = dto.PrePaddingSeconds,
|
PrePaddingSeconds = dto.PrePaddingSeconds,
|
||||||
PostPaddingSeconds = dto.PostPaddingSeconds,
|
PostPaddingSeconds = dto.PostPaddingSeconds,
|
||||||
IsPostPaddingRequired = dto.IsPostPaddingRequired,
|
IsPostPaddingRequired = dto.IsPostPaddingRequired,
|
||||||
IsPrePaddingRequired = dto.IsPrePaddingRequired,
|
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
|
// 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;
|
info.Id = timer.ExternalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(dto.SeriesTimerId))
|
if (!string.IsNullOrEmpty(dto.ChannelId) && string.IsNullOrEmpty(info.ChannelId))
|
||||||
{
|
|
||||||
var timer = await liveTv.GetSeriesTimer(dto.SeriesTimerId, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
info.SeriesTimerId = timer.ExternalId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(dto.ChannelId))
|
|
||||||
{
|
{
|
||||||
var channel = await liveTv.GetChannel(dto.ChannelId, cancellationToken).ConfigureAwait(false);
|
var channel = await liveTv.GetChannel(dto.ChannelId, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (channel != null)
|
||||||
|
{
|
||||||
info.ChannelId = channel.ExternalId;
|
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);
|
var program = await liveTv.GetProgram(dto.ProgramId, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (program != null)
|
||||||
|
{
|
||||||
info.ProgramId = program.ExternalId;
|
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;
|
return info;
|
||||||
}
|
}
|
||||||
|
@ -371,30 +410,39 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
Priority = dto.Priority,
|
Priority = dto.Priority,
|
||||||
RecordAnyChannel = dto.RecordAnyChannel,
|
RecordAnyChannel = dto.RecordAnyChannel,
|
||||||
RecordAnyTime = dto.RecordAnyTime,
|
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
|
// 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);
|
var timer = await liveTv.GetSeriesTimer(dto.Id, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
info.Id = timer.ExternalId;
|
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);
|
var channel = await liveTv.GetChannel(dto.ChannelId, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (channel != null)
|
||||||
|
{
|
||||||
info.ChannelId = channel.ExternalId;
|
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);
|
var program = await liveTv.GetProgram(dto.ProgramId, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (program != null)
|
||||||
|
{
|
||||||
info.ProgramId = program.ExternalId;
|
info.ProgramId = program.ExternalId;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
|
|
||||||
private readonly List<ILiveTvService> _services = new List<ILiveTvService>();
|
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>();
|
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)
|
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));
|
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(new Guid(query.UserId));
|
||||||
|
|
||||||
IEnumerable<Channel> channels = _channels;
|
IEnumerable<LiveTvChannel> channels = _channels;
|
||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
channels = channels.Where(i => i.IsParentalAllowed(user, _localization))
|
channels = channels
|
||||||
|
.Where(i => i.IsParentalAllowed(user, _localization))
|
||||||
.OrderBy(i =>
|
.OrderBy(i =>
|
||||||
{
|
{
|
||||||
double number = 0;
|
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;
|
return number;
|
||||||
|
@ -100,9 +101,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
{
|
{
|
||||||
double number = 0;
|
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;
|
return number;
|
||||||
|
@ -120,14 +121,25 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
return Task.FromResult(result);
|
return Task.FromResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Channel GetChannel(string id)
|
public LiveTvChannel GetInternalChannel(string id)
|
||||||
{
|
{
|
||||||
var guid = new Guid(id);
|
var guid = new Guid(id);
|
||||||
|
|
||||||
return _channels.FirstOrDefault(i => i.Id == guid);
|
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));
|
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 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)
|
if (item == null)
|
||||||
{
|
{
|
||||||
item = new Channel
|
item = new LiveTvChannel
|
||||||
{
|
{
|
||||||
Name = channelInfo.Name,
|
Name = channelInfo.Name,
|
||||||
Id = id,
|
Id = id,
|
||||||
DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo),
|
DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo),
|
||||||
DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo),
|
DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo),
|
||||||
Path = path,
|
Path = path
|
||||||
ChannelId = channelInfo.Id,
|
|
||||||
ChannelNumber = channelInfo.Number,
|
|
||||||
ServiceName = serviceName,
|
|
||||||
HasProviderImage = channelInfo.HasImage
|
|
||||||
};
|
};
|
||||||
|
|
||||||
isNew = true;
|
isNew = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item.ChannelInfo = channelInfo;
|
||||||
|
item.ServiceName = serviceName;
|
||||||
|
|
||||||
// Set this now so we don't cause additional file system access during provider executions
|
// Set this now so we don't cause additional file system access during provider executions
|
||||||
item.ResetResolveArgs(fileInfo);
|
item.ResetResolveArgs(fileInfo);
|
||||||
|
|
||||||
|
@ -178,6 +189,35 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
return item;
|
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)
|
public Task<ProgramInfoDto> GetProgram(string id, CancellationToken cancellationToken, User user = null)
|
||||||
{
|
{
|
||||||
var program = _programs.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
|
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 allChannels = await GetChannels(service, cancellationToken).ConfigureAwait(false);
|
||||||
var allChannelsList = allChannels.ToList();
|
var allChannelsList = allChannels.ToList();
|
||||||
|
|
||||||
var list = new List<Channel>();
|
var list = new List<LiveTvChannel>();
|
||||||
var programs = new List<ProgramInfoDto>();
|
var programs = new List<ProgramInfoDto>();
|
||||||
|
|
||||||
var numComplete = 0;
|
var numComplete = 0;
|
||||||
|
@ -271,26 +311,34 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
|
|
||||||
public async Task<QueryResult<RecordingInfoDto>> GetRecordings(RecordingQuery query, CancellationToken cancellationToken)
|
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 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 service.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
|
||||||
{
|
list.AddRange(recordings);
|
||||||
var recordings = await ActiveService.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var dtos = recordings.Select(i => _tvDtoService.GetRecordingInfoDto(i, ActiveService, user));
|
|
||||||
|
|
||||||
list.AddRange(dtos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(query.ChannelId))
|
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();
|
.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();
|
.ToArray();
|
||||||
|
|
||||||
return new QueryResult<RecordingInfoDto>
|
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)
|
private IEnumerable<ILiveTvService> GetServices(string serviceName, string channelId)
|
||||||
{
|
{
|
||||||
IEnumerable<ILiveTvService> services = _services;
|
IEnumerable<ILiveTvService> services = _services;
|
||||||
|
@ -404,11 +459,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
{
|
{
|
||||||
var results = await GetRecordings(new RecordingQuery
|
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);
|
}, 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)
|
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\ChannelImageProvider.cs" />
|
||||||
<Compile Include="LiveTv\LiveTvDtoService.cs" />
|
<Compile Include="LiveTv\LiveTvDtoService.cs" />
|
||||||
<Compile Include="LiveTv\LiveTvManager.cs" />
|
<Compile Include="LiveTv\LiveTvManager.cs" />
|
||||||
|
<Compile Include="LiveTv\ProgramImageProvider.cs" />
|
||||||
|
<Compile Include="LiveTv\RecordingImageProvider.cs" />
|
||||||
<Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
|
<Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
|
||||||
<Compile Include="Localization\LocalizationManager.cs" />
|
<Compile Include="Localization\LocalizationManager.cs" />
|
||||||
<Compile Include="MediaEncoder\MediaEncoder.cs" />
|
<Compile Include="MediaEncoder\MediaEncoder.cs" />
|
||||||
|
|
|
@ -118,6 +118,8 @@ namespace MediaBrowser.Server.Implementations.Providers
|
||||||
imageIndex = hasScreenshots.ScreenshotImagePaths.Count;
|
imageIndex = hasScreenshots.ScreenshotImagePaths.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var index = imageIndex ?? 0;
|
||||||
|
|
||||||
var paths = GetSavePaths(item, type, imageIndex, mimeType, saveLocally);
|
var paths = GetSavePaths(item, type, imageIndex, mimeType, saveLocally);
|
||||||
|
|
||||||
// If there are more than one output paths, the stream will need to be seekable
|
// 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;
|
source = memoryStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentPath = GetCurrentImagePath(item, type, imageIndex);
|
var currentPath = GetCurrentImagePath(item, type, index);
|
||||||
|
|
||||||
using (source)
|
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);
|
SetImagePath(item, type, imageIndex, paths[0], sourceUrl);
|
||||||
|
|
||||||
// Delete the current path
|
// Delete the current path
|
||||||
|
@ -257,27 +259,9 @@ namespace MediaBrowser.Server.Implementations.Providers
|
||||||
/// or
|
/// or
|
||||||
/// imageIndex
|
/// imageIndex
|
||||||
/// </exception>
|
/// </exception>
|
||||||
private string GetCurrentImagePath(BaseItem item, ImageType type, int? imageIndex)
|
private string GetCurrentImagePath(IHasImages item, ImageType type, int imageIndex)
|
||||||
{
|
{
|
||||||
switch (type)
|
return item.GetImagePath(type, imageIndex);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -336,7 +320,7 @@ namespace MediaBrowser.Server.Implementations.Providers
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
item.SetImage(type, path);
|
item.SetImagePath(type, path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,7 +577,7 @@ namespace MediaBrowser.Server.Implementations.Providers
|
||||||
/// <param name="imageFilename">The image filename.</param>
|
/// <param name="imageFilename">The image filename.</param>
|
||||||
/// <param name="extension">The extension.</param>
|
/// <param name="extension">The extension.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <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)
|
if (type == ImageType.Primary)
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,7 +96,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
||||||
// Limit to video files to reduce changes of ffmpeg crash dialog
|
// Limit to video files to reduce changes of ffmpeg crash dialog
|
||||||
foreach (var item in newItems
|
foreach (var item in newItems
|
||||||
.Where(i => i.LocationType == LocationType.FileSystem && i.VideoType == VideoType.VideoFile && string.IsNullOrEmpty(i.PrimaryImagePath) && i.DefaultVideoStreamIndex.HasValue)
|
.Where(i => i.LocationType == LocationType.FileSystem && i.VideoType == VideoType.VideoFile && string.IsNullOrEmpty(i.PrimaryImagePath) && i.DefaultVideoStreamIndex.HasValue)
|
||||||
.Take(2))
|
.Take(1))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -242,19 +242,19 @@ namespace MediaBrowser.ServerApplication
|
||||||
}
|
}
|
||||||
if (item.HasImage(ImageType.Banner))
|
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))
|
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))
|
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))
|
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(
|
previews.AddRange(
|
||||||
item.BackdropImagePaths.Select(
|
item.BackdropImagePaths.Select(
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common.Internal</id>
|
<id>MediaBrowser.Common.Internal</id>
|
||||||
<version>3.0.278</version>
|
<version>3.0.281</version>
|
||||||
<title>MediaBrowser.Common.Internal</title>
|
<title>MediaBrowser.Common.Internal</title>
|
||||||
<authors>Luke</authors>
|
<authors>Luke</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<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>
|
<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>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<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="NLog" version="2.1.0" />
|
||||||
<dependency id="SimpleInjector" version="2.4.0" />
|
<dependency id="SimpleInjector" version="2.4.0" />
|
||||||
<dependency id="sharpcompress" version="0.10.2" />
|
<dependency id="sharpcompress" version="0.10.2" />
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common</id>
|
<id>MediaBrowser.Common</id>
|
||||||
<version>3.0.278</version>
|
<version>3.0.281</version>
|
||||||
<title>MediaBrowser.Common</title>
|
<title>MediaBrowser.Common</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Server.Core</id>
|
<id>MediaBrowser.Server.Core</id>
|
||||||
<version>3.0.278</version>
|
<version>3.0.281</version>
|
||||||
<title>Media Browser.Server.Core</title>
|
<title>Media Browser.Server.Core</title>
|
||||||
<authors>Media Browser Team</authors>
|
<authors>Media Browser Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||||
<copyright>Copyright © Media Browser 2013</copyright>
|
<copyright>Copyright © Media Browser 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.278" />
|
<dependency id="MediaBrowser.Common" version="3.0.281" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
|
Loading…
Reference in a new issue