2013-11-05 15:12:13 +00:00
using MediaBrowser.Common.Extensions ;
2013-11-04 21:50:37 +00:00
using MediaBrowser.Common.IO ;
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 ;
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 ;
2014-01-28 18:37:01 +00:00
using ServiceStack.Text.Controller ;
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 ;
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 ; }
}
2013-11-05 15:12:13 +00:00
[Route("/Items/{Id}/RemoteImages", "GET")]
[Api(Description = "Gets available remote images for an item")]
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
}
[Route("/Artists/{Name}/RemoteImages", "GET")]
[Route("/Genres/{Name}/RemoteImages", "GET")]
[Route("/GameGenres/{Name}/RemoteImages", "GET")]
[Route("/MusicGenres/{Name}/RemoteImages", "GET")]
[Route("/Persons/{Name}/RemoteImages", "GET")]
[Route("/Studios/{Name}/RemoteImages", "GET")]
[Api(Description = "Gets available remote images for an item")]
public class GetItemByNameRemoteImages : BaseRemoteImageRequest
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Name { get ; set ; }
}
2013-11-01 01:48:14 +00:00
2013-11-05 15:38:59 +00:00
[Route("/Items/{Id}/RemoteImages/Providers", "GET")]
[Api(Description = "Gets available remote image providers for an item")]
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 ; }
}
[Route("/Artists/{Name}/RemoteImages/Providers", "GET")]
[Route("/Genres/{Name}/RemoteImages/Providers", "GET")]
[Route("/GameGenres/{Name}/RemoteImages/Providers", "GET")]
[Route("/MusicGenres/{Name}/RemoteImages/Providers", "GET")]
[Route("/Persons/{Name}/RemoteImages/Providers", "GET")]
[Route("/Studios/{Name}/RemoteImages/Providers", "GET")]
[Api(Description = "Gets available remote image providers for an item")]
public class GetItemByNameRemoteImageProviders : IReturn < List < ImageProviderInfo > >
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Name { 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
2013-11-05 15:12:13 +00:00
[Route("/Items/{Id}/RemoteImages/Download", "POST")]
[Api(Description = "Downloads a remote image for an item")]
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
2013-11-05 15:12:13 +00:00
[Route("/Artists/{Name}/RemoteImages/Download", "POST")]
[Route("/Genres/{Name}/RemoteImages/Download", "POST")]
[Route("/GameGenres/{Name}/RemoteImages/Download", "POST")]
[Route("/MusicGenres/{Name}/RemoteImages/Download", "POST")]
[Route("/Persons/{Name}/RemoteImages/Download", "POST")]
[Route("/Studios/{Name}/RemoteImages/Download", "POST")]
[Api(Description = "Downloads a remote image for an item")]
public class DownloadItemByNameRemoteImage : BaseDownloadRemoteImage
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
[ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string Name { get ; set ; }
}
2013-11-05 15:38:59 +00:00
2013-11-04 21:50:37 +00:00
[Route("/Images/Remote", "GET")]
[Api(Description = "Gets a remote image")]
public class GetRemoteImage
{
[ApiMember(Name = "Url", Description = "The image url", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Url { get ; set ; }
}
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 )
{
var item = _dtoService . GetItemByDtoId ( request . Id ) ;
var result = GetImageProviders ( item ) ;
return ToOptimizedResult ( result ) ;
}
public object Get ( GetItemByNameRemoteImageProviders request )
{
2013-12-07 15:52:38 +00:00
var pathInfo = PathInfo . Parse ( Request . PathInfo ) ;
2013-11-05 15:38:59 +00:00
var type = pathInfo . GetArgumentValue < string > ( 0 ) ;
var item = GetItemByName ( request . Name , type , _libraryManager ) ;
var result = GetImageProviders ( item ) ;
return ToOptimizedResult ( result ) ;
}
private List < ImageProviderInfo > GetImageProviders ( BaseItem item )
{
2014-01-28 18:37:01 +00:00
return _providerManager . GetImageProviderInfo ( item ) . ToList ( ) ;
2013-11-05 15:38:59 +00:00
}
2013-10-31 21:03:24 +00:00
public object Get ( GetRemoteImages request )
{
var item = _dtoService . GetItemByDtoId ( request . Id ) ;
2013-11-05 15:12:13 +00:00
var result = GetRemoteImageResult ( item , request ) ;
return ToOptimizedResult ( result ) ;
}
public object Get ( GetItemByNameRemoteImages request )
{
2013-12-07 15:52:38 +00:00
var pathInfo = PathInfo . Parse ( Request . PathInfo ) ;
2013-11-05 15:12:13 +00:00
var type = pathInfo . GetArgumentValue < string > ( 0 ) ;
var item = GetItemByName ( request . Name , type , _libraryManager ) ;
return GetRemoteImageResult ( item , request ) ;
}
2013-11-05 15:38:59 +00:00
2013-11-05 15:12:13 +00:00
private RemoteImageResult GetRemoteImageResult ( BaseItem item , BaseRemoteImageRequest request )
{
2013-11-01 01:48:14 +00:00
var images = _providerManager . GetAvailableRemoteImages ( item , CancellationToken . None , request . ProviderName , request . Type ) . Result ;
2013-10-31 21:03:24 +00:00
var imagesList = images . ToList ( ) ;
var result = new RemoteImageResult
{
2013-11-01 01:48:14 +00:00
TotalRecordCount = imagesList . Count ,
2014-01-28 18:37:01 +00:00
Providers = images . Select ( i = > i . ProviderName )
. 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 )
{
2013-11-05 15:12:13 +00:00
var item = _dtoService . GetItemByDtoId ( request . Id ) ;
var task = DownloadRemoteImage ( item , request ) ;
2013-11-01 01:48:14 +00:00
Task . WaitAll ( task ) ;
}
2013-11-05 15:12:13 +00:00
public void Post ( DownloadItemByNameRemoteImage request )
2013-11-01 01:48:14 +00:00
{
2013-12-07 15:52:38 +00:00
var pathInfo = PathInfo . Parse ( Request . PathInfo ) ;
2013-11-05 15:12:13 +00:00
var type = pathInfo . GetArgumentValue < string > ( 0 ) ;
var item = GetItemByName ( request . Name , type , _libraryManager ) ;
var task = DownloadRemoteImage ( item , request ) ;
2013-11-01 01:48:14 +00:00
2013-11-05 15:12:13 +00:00
Task . WaitAll ( task ) ;
}
2013-11-05 15:38:59 +00:00
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-01-28 18:37:01 +00:00
await item . RefreshMetadata ( new MetadataRefreshOptions
{
ForceSave = true ,
2014-01-31 04:50:09 +00:00
ImageRefreshMode = ImageRefreshMode . ValidationOnly ,
2014-01-28 18:37:01 +00:00
MetadataRefreshMode = MetadataRefreshMode . None
} , 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>
2013-11-04 21:50:37 +00:00
public object Get ( GetRemoteImage request )
{
var task = GetRemoteImage ( request ) ;
return task . Result ;
}
2013-11-05 15:12:13 +00:00
/// <summary>
/// Gets the remote image.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>Task{System.Object}.</returns>
2013-11-04 21:50:37 +00:00
private async Task < object > GetRemoteImage ( GetRemoteImage request )
{
var urlHash = request . Url . GetMD5 ( ) ;
var pointerCachePath = GetFullCachePath ( urlHash . ToString ( ) ) ;
string contentPath ;
try
{
using ( var reader = new StreamReader ( pointerCachePath ) )
{
contentPath = await reader . ReadToEndAsync ( ) . ConfigureAwait ( false ) ;
}
if ( File . Exists ( contentPath ) )
{
return ToStaticFileResult ( contentPath ) ;
}
}
catch ( FileNotFoundException )
{
// Means the file isn't cached yet
}
await DownloadImage ( request . Url , urlHash , pointerCachePath ) . ConfigureAwait ( false ) ;
// Read the pointer file again
using ( var reader = new StreamReader ( pointerCachePath ) )
{
contentPath = await reader . ReadToEndAsync ( ) . ConfigureAwait ( false ) ;
}
return ToStaticFileResult ( contentPath ) ;
}
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
{
Url = url
} ) . ConfigureAwait ( false ) ;
var ext = result . ContentType . Split ( '/' ) . Last ( ) ;
var fullCachePath = GetFullCachePath ( urlHash + "." + ext ) ;
2013-11-15 15:11:35 +00:00
Directory . 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 ) ;
}
}
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 )
{
return Path . Combine ( _appPaths . DownloadedImagesDataPath , filename . Substring ( 0 , 1 ) , filename ) ;
}
2013-10-31 21:03:24 +00:00
}
}