2019-01-13 21:01:16 +01:00
using System ;
2019-01-13 20:24:58 +01:00
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Threading ;
using System.Threading.Tasks ;
using MediaBrowser.Common.Extensions ;
2013-11-04 22:50:37 +01:00
using MediaBrowser.Common.Net ;
using MediaBrowser.Controller ;
2019-11-17 23:05:39 +01:00
using MediaBrowser.Controller.Configuration ;
2013-11-05 16:12:13 +01:00
using MediaBrowser.Controller.Entities ;
using MediaBrowser.Controller.Library ;
2014-11-15 03:31:03 +01:00
using MediaBrowser.Controller.Net ;
2013-10-31 22:03:24 +01:00
using MediaBrowser.Controller.Providers ;
using MediaBrowser.Model.Entities ;
2016-10-25 21:02:04 +02:00
using MediaBrowser.Model.IO ;
2019-01-13 20:24:58 +01:00
using MediaBrowser.Model.Providers ;
2016-10-25 21:02:04 +02:00
using MediaBrowser.Model.Services ;
2019-11-17 23:05:39 +01:00
using Microsoft.Extensions.Logging ;
2013-10-31 22:03:24 +01:00
2013-11-05 16:12:13 +01:00
namespace MediaBrowser.Api.Images
2013-10-31 22:03:24 +01:00
{
2013-11-05 16:12:13 +01:00
public class BaseRemoteImageRequest : IReturn < RemoteImageResult >
2013-10-31 22:03:24 +01:00
{
2013-11-04 21:49:36 +01:00
[ApiMember(Name = "Type", Description = "The image type", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
2013-11-01 02:48:14 +01:00
public ImageType ? Type { get ; set ; }
2013-10-31 22:03:24 +01: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 02:48:14 +01: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 04:46:27 +01:00
[ApiMember(Name = "IncludeAllLanguages", Description = "Optional.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool IncludeAllLanguages { get ; set ; }
2013-11-01 02:48:14 +01:00
}
2014-11-15 03:31:03 +01:00
[Route("/Items/{Id}/RemoteImages", "GET", Summary = "Gets available remote images for an item")]
[Authenticated]
2013-11-05 16:12:13 +01:00
public class GetRemoteImages : BaseRemoteImageRequest
2013-11-01 02:48:14 +01: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 16:12:13 +01:00
}
2014-11-15 03:31:03 +01:00
[Route("/Items/{Id}/RemoteImages/Providers", "GET", Summary = "Gets available remote image providers for an item")]
[Authenticated]
2013-11-05 16:38:59 +01: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 16:12:13 +01:00
public class BaseDownloadRemoteImage : IReturnVoid
{
2018-09-12 19:26:21 +02:00
[ApiMember(Name = "Type", Description = "The image type", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
2013-11-01 02:48:14 +01:00
public ImageType Type { get ; set ; }
2018-09-12 19:26:21 +02:00
[ApiMember(Name = "ProviderName", Description = "The image provider", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
2013-11-01 02:48:14 +01:00
public string ProviderName { get ; set ; }
2018-09-12 19:26:21 +02:00
[ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
2013-11-01 02:48:14 +01:00
public string ImageUrl { get ; set ; }
2013-10-31 22:03:24 +01:00
}
2013-11-05 16:38:59 +01:00
2014-11-15 03:31:03 +01:00
[Route("/Items/{Id}/RemoteImages/Download", "POST", Summary = "Downloads a remote image for an item")]
2017-10-03 20:39:37 +02:00
[Authenticated(Roles = "Admin")]
2013-11-05 16:12:13 +01:00
public class DownloadRemoteImage : BaseDownloadRemoteImage
{
/// <summary>
/// Gets or sets the id.
/// </summary>
/// <value>The id.</value>
2018-09-12 19:26:21 +02:00
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
2013-11-05 16:12:13 +01:00
public string Id { get ; set ; }
}
2013-10-31 22:03:24 +01:00
2014-11-15 03:31:03 +01:00
[Route("/Images/Remote", "GET", Summary = "Gets a remote image")]
2013-11-04 22:50:37 +01:00
public class GetRemoteImage
{
2014-02-09 07:08:10 +01:00
[ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ImageUrl { get ; set ; }
2013-11-04 22:50:37 +01:00
}
2013-10-31 22:03:24 +01:00
public class RemoteImageService : BaseApiService
{
private readonly IProviderManager _providerManager ;
2013-11-04 22:50:37 +01:00
private readonly IServerApplicationPaths _appPaths ;
private readonly IHttpClient _httpClient ;
private readonly IFileSystem _fileSystem ;
2013-11-05 16:12:13 +01:00
private readonly ILibraryManager _libraryManager ;
2013-10-31 22:03:24 +01:00
2019-11-17 23:05:39 +01:00
public RemoteImageService (
ILogger < RemoteImageService > logger ,
IServerConfigurationManager serverConfigurationManager ,
IHttpResultFactory httpResultFactory ,
IProviderManager providerManager ,
IServerApplicationPaths appPaths ,
IHttpClient httpClient ,
IFileSystem fileSystem ,
ILibraryManager libraryManager )
: base ( logger , serverConfigurationManager , httpResultFactory )
2013-10-31 22:03:24 +01:00
{
_providerManager = providerManager ;
2013-11-04 22:50:37 +01:00
_appPaths = appPaths ;
_httpClient = httpClient ;
_fileSystem = fileSystem ;
2013-11-05 16:12:13 +01:00
_libraryManager = libraryManager ;
2013-10-31 22:03:24 +01:00
}
2013-11-05 16:38:59 +01:00
public object Get ( GetRemoteImageProviders request )
{
2014-04-25 22:15:50 +02:00
var item = _libraryManager . GetItemById ( request . Id ) ;
2013-11-05 16:38:59 +01:00
var result = GetImageProviders ( item ) ;
2018-09-12 19:26:21 +02:00
return ToOptimizedResult ( result ) ;
2013-11-05 16:38:59 +01:00
}
private List < ImageProviderInfo > GetImageProviders ( BaseItem item )
{
2014-02-09 22:11:11 +01:00
return _providerManager . GetRemoteImageProviderInfo ( item ) . ToList ( ) ;
2013-11-05 16:38:59 +01:00
}
2014-08-19 03:42:53 +02:00
public async Task < object > Get ( GetRemoteImages request )
2013-10-31 22:03:24 +01:00
{
2014-04-25 22:15:50 +02:00
var item = _libraryManager . GetItemById ( request . Id ) ;
2013-10-31 22:03:24 +01:00
2014-08-17 07:38:13 +02:00
var images = await _providerManager . GetAvailableRemoteImages ( item , new RemoteImageQuery
2014-02-12 04:46:27 +01:00
{
ProviderName = request . ProviderName ,
IncludeAllLanguages = request . IncludeAllLanguages ,
IncludeDisabledProviders = true ,
ImageType = request . Type
2014-08-17 07:38:13 +02:00
} , CancellationToken . None ) . ConfigureAwait ( false ) ;
2013-10-31 22:03:24 +01:00
2017-08-19 21:43:35 +02:00
var imagesList = images . ToArray ( ) ;
2013-10-31 22:03:24 +01:00
2014-02-11 05:55:01 +01:00
var allProviders = _providerManager . GetRemoteImageProviderInfo ( item ) ;
if ( request . Type . HasValue )
{
allProviders = allProviders . Where ( i = > i . SupportedImages . Contains ( request . Type . Value ) ) ;
}
2013-10-31 22:03:24 +01:00
var result = new RemoteImageResult
{
2017-08-19 21:43:35 +02:00
TotalRecordCount = imagesList . Length ,
2014-02-11 05:55:01 +01:00
Providers = allProviders . Select ( i = > i . Name )
2014-01-28 19:37:01 +01:00
. Distinct ( StringComparer . OrdinalIgnoreCase )
2017-08-19 21:43:35 +02:00
. ToArray ( )
2013-10-31 22:03:24 +01:00
} ;
if ( request . StartIndex . HasValue )
{
imagesList = imagesList . Skip ( request . StartIndex . Value )
2017-08-19 21:43:35 +02:00
. ToArray ( ) ;
2013-10-31 22:03:24 +01:00
}
if ( request . Limit . HasValue )
{
imagesList = imagesList . Take ( request . Limit . Value )
2017-08-19 21:43:35 +02:00
. ToArray ( ) ;
2013-10-31 22:03:24 +01:00
}
result . Images = imagesList ;
2013-11-05 16:12:13 +01:00
return result ;
2013-10-31 22:03:24 +01:00
}
2013-11-01 02:48:14 +01:00
2013-11-05 16:12:13 +01:00
/// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
2018-09-12 19:26:21 +02:00
public Task Post ( DownloadRemoteImage request )
2013-11-01 02:48:14 +01:00
{
2014-04-25 22:15:50 +02:00
var item = _libraryManager . GetItemById ( request . Id ) ;
2013-11-05 16:12:13 +01:00
2018-09-12 19:26:21 +02:00
return DownloadRemoteImage ( item , request ) ;
2013-11-01 02:48:14 +01:00
}
2013-11-05 16:12:13 +01: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 )
{
2017-02-04 22:22:55 +01:00
await _providerManager . SaveImage ( item , request . ImageUrl , request . Type , null , CancellationToken . None ) . ConfigureAwait ( false ) ;
2013-11-01 02:48:14 +01:00
2017-10-03 20:39:37 +02:00
item . UpdateToRepository ( ItemUpdateType . ImageUpdate , CancellationToken . None ) ;
2013-11-01 02:48:14 +01:00
}
2013-11-04 22:50:37 +01:00
2013-11-05 16:12:13 +01:00
/// <summary>
/// Gets the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
2018-09-12 19:26:21 +02:00
public async Task < object > Get ( GetRemoteImage request )
2013-11-04 22:50:37 +01:00
{
2014-02-09 07:08:10 +01:00
var urlHash = request . ImageUrl . GetMD5 ( ) ;
2013-11-04 22:50:37 +01:00
var pointerCachePath = GetFullCachePath ( urlHash . ToString ( ) ) ;
string contentPath ;
try
{
2019-01-26 23:09:07 +01:00
contentPath = File . ReadAllText ( pointerCachePath ) ;
2013-11-04 22:50:37 +01:00
2019-01-26 22:59:53 +01:00
if ( File . Exists ( contentPath ) )
2017-10-03 20:39:37 +02:00
{
return await ResultFactory . GetStaticFileResult ( Request , contentPath ) . ConfigureAwait ( false ) ;
}
2013-11-04 22:50:37 +01:00
}
2016-11-01 04:07:45 +01:00
catch ( FileNotFoundException )
2014-02-09 08:27:44 +01:00
{
// Means the file isn't cached yet
}
2016-11-01 04:07:45 +01:00
catch ( IOException )
2013-11-04 22:50:37 +01:00
{
// Means the file isn't cached yet
}
2014-02-09 07:08:10 +01:00
await DownloadImage ( request . ImageUrl , urlHash , pointerCachePath ) . ConfigureAwait ( false ) ;
2013-11-04 22:50:37 +01:00
// Read the pointer file again
2019-01-26 23:09:07 +01:00
contentPath = File . ReadAllText ( pointerCachePath ) ;
2013-11-04 22:50:37 +01:00
2016-06-19 08:18:29 +02:00
return await ResultFactory . GetStaticFileResult ( Request , contentPath ) . ConfigureAwait ( false ) ;
2013-11-04 22:50:37 +01:00
}
2016-06-19 08:18:29 +02:00
2013-11-05 16:12:13 +01: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 22:50:37 +01:00
private async Task DownloadImage ( string url , Guid urlHash , string pointerCachePath )
{
2020-04-05 18:26:11 +02:00
using var result = await _httpClient . GetResponse ( new HttpRequestOptions
2013-11-04 22:50:37 +01:00
{
2016-10-06 20:55:01 +02:00
Url = url ,
BufferContent = false
2013-11-04 22:50:37 +01:00
2020-04-05 18:26:11 +02:00
} ) . ConfigureAwait ( false ) ;
var ext = result . ContentType . Split ( '/' ) . Last ( ) ;
2013-11-04 22:50:37 +01:00
2020-04-05 18:26:11 +02:00
var fullCachePath = GetFullCachePath ( urlHash + "." + ext ) ;
2013-11-04 22:50:37 +01:00
2020-04-05 18:26:11 +02:00
Directory . CreateDirectory ( Path . GetDirectoryName ( fullCachePath ) ) ;
using ( var stream = result . Content )
{
using var filestream = new FileStream ( fullCachePath , FileMode . Create , FileAccess . Write , FileShare . Read , IODefaults . FileStreamBufferSize , true ) ;
await stream . CopyToAsync ( filestream ) . ConfigureAwait ( false ) ;
2017-10-20 18:16:56 +02:00
}
2020-04-05 18:26:11 +02:00
Directory . CreateDirectory ( Path . GetDirectoryName ( pointerCachePath ) ) ;
File . WriteAllText ( pointerCachePath , fullCachePath ) ;
2013-11-04 22:50:37 +01:00
}
2013-11-05 16:12:13 +01:00
/// <summary>
/// Gets the full cache path.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>System.String.</returns>
2013-11-04 22:50:37 +01:00
private string GetFullCachePath ( string filename )
{
2014-02-08 21:02:35 +01:00
return Path . Combine ( _appPaths . CachePath , "remote-images" , filename . Substring ( 0 , 1 ) , filename ) ;
2013-11-04 22:50:37 +01:00
}
2013-10-31 22:03:24 +01:00
}
}