2013-11-05 15:12:13 +00:00
using MediaBrowser.Common.Extensions ;
2013-11-04 21:50:37 +00:00
using MediaBrowser.Common.Net ;
using MediaBrowser.Controller ;
using MediaBrowser.Controller.Dto ;
2013-11-05 15:12:13 +00:00
using MediaBrowser.Controller.Entities ;
using MediaBrowser.Controller.Library ;
2014-11-15 02:31:03 +00:00
using MediaBrowser.Controller.Net ;
2013-10-31 21:03:24 +00:00
using MediaBrowser.Controller.Providers ;
using MediaBrowser.Model.Entities ;
using MediaBrowser.Model.Providers ;
2013-12-07 15:52:38 +00:00
using ServiceStack ;
2013-11-05 15:12:13 +00:00
using System ;
2013-11-05 15:38:59 +00:00
using System.Collections.Generic ;
2013-11-05 15:12:13 +00:00
using System.IO ;
2013-10-31 21:03:24 +00:00
using System.Linq ;
using System.Threading ;
2013-11-01 01:48:14 +00:00
using System.Threading.Tasks ;
2015-10-04 04:23:11 +00:00
using CommonIO ;
2013-10-31 21:03:24 +00:00
2013-11-05 15:12:13 +00:00
namespace MediaBrowser.Api.Images
2013-10-31 21:03:24 +00:00
{
2013-11-05 15:12:13 +00:00
public class BaseRemoteImageRequest : IReturn < RemoteImageResult >
2013-10-31 21:03:24 +00:00
{
2013-11-04 20:49:36 +00:00
[ApiMember(Name = "Type", Description = "The image type", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
2013-11-01 01:48:14 +00:00
public ImageType ? Type { get ; set ; }
2013-10-31 21:03:24 +00:00
/// <summary>
/// Skips over a given number of items within the results. Use for paging.
/// </summary>
/// <value>The start index.</value>
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? StartIndex { get ; set ; }
/// <summary>
/// The maximum number of items to return
/// </summary>
/// <value>The limit.</value>
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? Limit { get ; set ; }
2013-11-01 01:48:14 +00:00
[ApiMember(Name = "ProviderName", Description = "Optional. The image provider to use", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ProviderName { get ; set ; }
2014-02-12 03:46:27 +00:00
[ApiMember(Name = "IncludeAllLanguages", Description = "Optional.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool IncludeAllLanguages { get ; set ; }
2013-11-01 01:48:14 +00:00
}
2014-11-15 02:31:03 +00:00
[Route("/Items/{Id}/RemoteImages", "GET", Summary = "Gets available remote images for an item")]
[Authenticated]
2013-11-05 15:12:13 +00:00
public class GetRemoteImages : BaseRemoteImageRequest
2013-11-01 01:48:14 +00:00
{
/// <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 ; }
2013-11-05 15:12:13 +00:00
}
2014-11-15 02:31:03 +00:00
[Route("/Items/{Id}/RemoteImages/Providers", "GET", Summary = "Gets available remote image providers for an item")]
[Authenticated]
2013-11-05 15:38:59 +00:00
public class GetRemoteImageProviders : IReturn < List < ImageProviderInfo > >
{
/// <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 ; }
}
2013-11-05 15:12:13 +00:00
public class BaseDownloadRemoteImage : IReturnVoid
{
2013-11-01 01:48:14 +00:00
[ApiMember(Name = "Type", Description = "The image type", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public ImageType Type { get ; set ; }
[ApiMember(Name = "ProviderName", Description = "The image provider", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ProviderName { get ; set ; }
[ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ImageUrl { get ; set ; }
2013-10-31 21:03:24 +00:00
}
2013-11-05 15:38:59 +00:00
2014-11-15 02:31:03 +00:00
[Route("/Items/{Id}/RemoteImages/Download", "POST", Summary = "Downloads a remote image for an item")]
[Authenticated(Roles="Admin")]
2013-11-05 15:12:13 +00:00
public class DownloadRemoteImage : BaseDownloadRemoteImage
{
/// <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 ; }
}
2013-10-31 21:03:24 +00:00
2014-11-15 02:31:03 +00:00
[Route("/Images/Remote", "GET", Summary = "Gets a remote image")]
2013-11-04 21:50:37 +00:00
public class GetRemoteImage
{
2014-02-09 06:08:10 +00:00
[ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ImageUrl { get ; set ; }
2013-11-04 21:50:37 +00:00
}
2013-10-31 21:03:24 +00:00
public class RemoteImageService : BaseApiService
{
private readonly IProviderManager _providerManager ;
2013-11-04 21:50:37 +00:00
private readonly IServerApplicationPaths _appPaths ;
private readonly IHttpClient _httpClient ;
private readonly IFileSystem _fileSystem ;
2013-10-31 21:03:24 +00:00
private readonly IDtoService _dtoService ;
2013-11-05 15:12:13 +00:00
private readonly ILibraryManager _libraryManager ;
2013-10-31 21:03:24 +00:00
2013-11-05 15:12:13 +00:00
public RemoteImageService ( IProviderManager providerManager , IDtoService dtoService , IServerApplicationPaths appPaths , IHttpClient httpClient , IFileSystem fileSystem , ILibraryManager libraryManager )
2013-10-31 21:03:24 +00:00
{
_providerManager = providerManager ;
_dtoService = dtoService ;
2013-11-04 21:50:37 +00:00
_appPaths = appPaths ;
_httpClient = httpClient ;
_fileSystem = fileSystem ;
2013-11-05 15:12:13 +00:00
_libraryManager = libraryManager ;
2013-10-31 21:03:24 +00:00
}
2013-11-05 15:38:59 +00:00
public object Get ( GetRemoteImageProviders request )
{
2014-04-25 20:15:50 +00:00
var item = _libraryManager . GetItemById ( request . Id ) ;
2013-11-05 15:38:59 +00:00
var result = GetImageProviders ( item ) ;
2014-02-04 04:04:19 +00:00
return ToOptimizedSerializedResultUsingCache ( result ) ;
2013-11-05 15:38:59 +00:00
}
private List < ImageProviderInfo > GetImageProviders ( BaseItem item )
{
2014-02-09 21:11:11 +00:00
return _providerManager . GetRemoteImageProviderInfo ( item ) . ToList ( ) ;
2013-11-05 15:38:59 +00:00
}
2014-08-19 01:42:53 +00:00
public async Task < object > Get ( GetRemoteImages request )
2013-10-31 21:03:24 +00:00
{
2014-04-25 20:15:50 +00:00
var item = _libraryManager . GetItemById ( request . Id ) ;
2013-10-31 21:03:24 +00:00
2014-08-19 01:42:53 +00:00
return await GetRemoteImageResult ( item , request ) . ConfigureAwait ( false ) ;
2013-11-05 15:12:13 +00:00
}
2014-08-17 05:38:13 +00:00
private async Task < RemoteImageResult > GetRemoteImageResult ( BaseItem item , BaseRemoteImageRequest request )
2013-11-05 15:12:13 +00:00
{
2014-08-17 05:38:13 +00:00
var images = await _providerManager . GetAvailableRemoteImages ( item , new RemoteImageQuery
2014-02-12 03:46:27 +00:00
{
ProviderName = request . ProviderName ,
IncludeAllLanguages = request . IncludeAllLanguages ,
IncludeDisabledProviders = true ,
ImageType = request . Type
2014-08-17 05:38:13 +00:00
} , CancellationToken . None ) . ConfigureAwait ( false ) ;
2013-10-31 21:03:24 +00:00
var imagesList = images . ToList ( ) ;
2014-02-11 04:55:01 +00:00
var allProviders = _providerManager . GetRemoteImageProviderInfo ( item ) ;
if ( request . Type . HasValue )
{
allProviders = allProviders . Where ( i = > i . SupportedImages . Contains ( request . Type . Value ) ) ;
}
2013-10-31 21:03:24 +00:00
var result = new RemoteImageResult
{
2013-11-01 01:48:14 +00:00
TotalRecordCount = imagesList . Count ,
2014-02-11 04:55:01 +00:00
Providers = allProviders . Select ( i = > i . Name )
2014-01-28 18:37:01 +00:00
. Distinct ( StringComparer . OrdinalIgnoreCase )
. ToList ( )
2013-10-31 21:03:24 +00:00
} ;
if ( request . StartIndex . HasValue )
{
imagesList = imagesList . Skip ( request . StartIndex . Value )
. ToList ( ) ;
}
if ( request . Limit . HasValue )
{
imagesList = imagesList . Take ( request . Limit . Value )
. ToList ( ) ;
}
result . Images = imagesList ;
2013-11-05 15:12:13 +00:00
return result ;
2013-10-31 21:03:24 +00:00
}
2013-11-01 01:48:14 +00:00
2013-11-05 15:12:13 +00:00
/// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
2013-11-01 01:48:14 +00:00
public void Post ( DownloadRemoteImage request )
{
2014-04-25 20:15:50 +00:00
var item = _libraryManager . GetItemById ( request . Id ) ;
2013-11-05 15:12:13 +00:00
var task = DownloadRemoteImage ( item , request ) ;
2013-11-01 01:48:14 +00:00
Task . WaitAll ( task ) ;
}
2013-11-05 15:12:13 +00:00
/// <summary>
/// Downloads the remote image.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="request">The request.</param>
/// <returns>Task.</returns>
private async Task DownloadRemoteImage ( BaseItem item , BaseDownloadRemoteImage request )
{
2013-11-07 16:48:23 +00:00
await _providerManager . SaveImage ( item , request . ImageUrl , null , request . Type , null , CancellationToken . None ) . ConfigureAwait ( false ) ;
2013-11-01 01:48:14 +00:00
2014-02-07 22:40:03 +00:00
await item . UpdateToRepository ( ItemUpdateType . ImageUpdate , CancellationToken . None ) . ConfigureAwait ( false ) ;
2013-11-01 01:48:14 +00:00
}
2013-11-04 21:50:37 +00:00
2013-11-05 15:12:13 +00:00
/// <summary>
/// Gets the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
2014-08-19 01:42:53 +00:00
public object Get ( GetRemoteImage request )
{
return GetAsync ( request ) . Result ;
}
public async Task < object > GetAsync ( GetRemoteImage request )
2013-11-04 21:50:37 +00:00
{
2014-02-09 06:08:10 +00:00
var urlHash = request . ImageUrl . GetMD5 ( ) ;
2013-11-04 21:50:37 +00:00
var pointerCachePath = GetFullCachePath ( urlHash . ToString ( ) ) ;
string contentPath ;
try
{
using ( var reader = new StreamReader ( pointerCachePath ) )
{
contentPath = await reader . ReadToEndAsync ( ) . ConfigureAwait ( false ) ;
}
2015-09-13 21:32:02 +00:00
if ( _fileSystem . FileExists ( contentPath ) )
2016-06-19 06:18:29 +00:00
{
return await ResultFactory . GetStaticFileResult ( Request , contentPath ) . ConfigureAwait ( false ) ;
}
2013-11-04 21:50:37 +00:00
}
2014-02-09 07:27:44 +00:00
catch ( DirectoryNotFoundException )
{
// Means the file isn't cached yet
}
2013-11-04 21:50:37 +00:00
catch ( FileNotFoundException )
{
// Means the file isn't cached yet
}
2014-02-09 06:08:10 +00:00
await DownloadImage ( request . ImageUrl , urlHash , pointerCachePath ) . ConfigureAwait ( false ) ;
2013-11-04 21:50:37 +00:00
// Read the pointer file again
using ( var reader = new StreamReader ( pointerCachePath ) )
{
contentPath = await reader . ReadToEndAsync ( ) . ConfigureAwait ( false ) ;
}
2016-06-19 06:18:29 +00:00
return await ResultFactory . GetStaticFileResult ( Request , contentPath ) . ConfigureAwait ( false ) ;
2013-11-04 21:50:37 +00:00
}
2016-06-19 06:18:29 +00:00
2013-11-05 15:12:13 +00:00
/// <summary>
/// Downloads the image.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="urlHash">The URL hash.</param>
/// <param name="pointerCachePath">The pointer cache path.</param>
/// <returns>Task.</returns>
2013-11-04 21:50:37 +00:00
private async Task DownloadImage ( string url , Guid urlHash , string pointerCachePath )
{
var result = await _httpClient . GetResponse ( new HttpRequestOptions
{
2016-10-06 18:55:01 +00:00
Url = url ,
BufferContent = false
2013-11-04 21:50:37 +00:00
} ) . ConfigureAwait ( false ) ;
var ext = result . ContentType . Split ( '/' ) . Last ( ) ;
var fullCachePath = GetFullCachePath ( urlHash + "." + ext ) ;
2015-09-13 21:32:02 +00:00
_fileSystem . CreateDirectory ( Path . GetDirectoryName ( fullCachePath ) ) ;
2013-11-04 21:50:37 +00:00
using ( var stream = result . Content )
{
using ( var filestream = _fileSystem . GetFileStream ( fullCachePath , FileMode . Create , FileAccess . Write , FileShare . Read , true ) )
{
await stream . CopyToAsync ( filestream ) . ConfigureAwait ( false ) ;
}
}
2015-09-13 21:32:02 +00:00
_fileSystem . CreateDirectory ( Path . GetDirectoryName ( pointerCachePath ) ) ;
2013-11-04 21:50:37 +00:00
using ( var writer = new StreamWriter ( pointerCachePath ) )
{
await writer . WriteAsync ( fullCachePath ) . ConfigureAwait ( false ) ;
}
}
2013-11-05 15:12:13 +00:00
/// <summary>
/// Gets the full cache path.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
2013-11-04 21:50:37 +00:00
private string GetFullCachePath ( string filename )
{
2014-02-08 20:02:35 +00:00
return Path . Combine ( _appPaths . CachePath , "remote-images" , filename . Substring ( 0 , 1 ) , filename ) ;
2013-11-04 21:50:37 +00:00
}
2013-10-31 21:03:24 +00:00
}
}