2019-01-13 20:01:16 +00:00
using System ;
2019-01-13 19:24:58 +00: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 21:50:37 +00:00
using MediaBrowser.Common.Net ;
using MediaBrowser.Controller ;
2019-11-17 22:05:39 +00:00
using MediaBrowser.Controller.Configuration ;
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 ;
2016-10-25 19:02:04 +00:00
using MediaBrowser.Model.IO ;
2019-01-13 19:24:58 +00:00
using MediaBrowser.Model.Providers ;
2016-10-25 19:02:04 +00:00
using MediaBrowser.Model.Services ;
2019-11-17 22:05:39 +00:00
using Microsoft.Extensions.Logging ;
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
{
2018-09-12 17:26:21 +00:00
[ApiMember(Name = "Type", Description = "The image type", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
2013-11-01 01:48:14 +00:00
public ImageType Type { get ; set ; }
2018-09-12 17:26:21 +00:00
[ApiMember(Name = "ProviderName", Description = "The image provider", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
2013-11-01 01:48:14 +00:00
public string ProviderName { get ; set ; }
2018-09-12 17:26:21 +00:00
[ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
2013-11-01 01:48:14 +00:00
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")]
2017-10-03 18:39:37 +00:00
[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>
2018-09-12 17:26:21 +00:00
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
2013-11-05 15:12:13 +00:00
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-11-05 15:12:13 +00:00
private readonly ILibraryManager _libraryManager ;
2013-10-31 21:03:24 +00:00
2019-11-17 22:05:39 +00: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 21:03:24 +00:00
{
_providerManager = providerManager ;
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 ) ;
2018-09-12 17:26:21 +00:00
return ToOptimizedResult ( 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
2020-04-05 16:10:56 +00:00
var images = await _providerManager . GetAvailableRemoteImages ( item , new RemoteImageQuery ( request . ProviderName )
2014-02-12 03:46:27 +00:00
{
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
2017-08-19 19:43:35 +00:00
var imagesList = images . ToArray ( ) ;
2013-10-31 21:03:24 +00:00
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
{
2017-08-19 19:43:35 +00:00
TotalRecordCount = imagesList . Length ,
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 )
2017-08-19 19:43:35 +00:00
. ToArray ( )
2013-10-31 21:03:24 +00:00
} ;
if ( request . StartIndex . HasValue )
{
imagesList = imagesList . Skip ( request . StartIndex . Value )
2017-08-19 19:43:35 +00:00
. ToArray ( ) ;
2013-10-31 21:03:24 +00:00
}
if ( request . Limit . HasValue )
{
imagesList = imagesList . Take ( request . Limit . Value )
2017-08-19 19:43:35 +00:00
. ToArray ( ) ;
2013-10-31 21:03:24 +00:00
}
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>
2018-09-12 17:26:21 +00:00
public Task Post ( DownloadRemoteImage request )
2013-11-01 01:48:14 +00:00
{
2014-04-25 20:15:50 +00:00
var item = _libraryManager . GetItemById ( request . Id ) ;
2013-11-05 15:12:13 +00:00
2018-09-12 17:26:21 +00:00
return DownloadRemoteImage ( item , request ) ;
2013-11-01 01:48:14 +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 )
{
2017-02-04 21:22:55 +00:00
await _providerManager . SaveImage ( item , request . ImageUrl , request . Type , null , CancellationToken . None ) . ConfigureAwait ( false ) ;
2013-11-01 01:48:14 +00:00
2017-10-03 18:39:37 +00:00
item . UpdateToRepository ( ItemUpdateType . ImageUpdate , CancellationToken . None ) ;
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>
2018-09-12 17:26:21 +00:00
public async Task < object > Get ( 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
{
2019-01-26 22:09:07 +00:00
contentPath = File . ReadAllText ( pointerCachePath ) ;
2013-11-04 21:50:37 +00:00
2019-01-26 21:59:53 +00:00
if ( File . Exists ( contentPath ) )
2017-10-03 18:39:37 +00:00
{
return await ResultFactory . GetStaticFileResult ( Request , contentPath ) . ConfigureAwait ( false ) ;
}
2013-11-04 21:50:37 +00:00
}
2016-11-01 03:07:45 +00:00
catch ( FileNotFoundException )
2014-02-09 07:27:44 +00:00
{
// Means the file isn't cached yet
}
2016-11-01 03:07:45 +00:00
catch ( IOException )
2013-11-04 21:50:37 +00:00
{
// 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
2019-01-26 22:09:07 +00:00
contentPath = File . ReadAllText ( pointerCachePath ) ;
2013-11-04 21:50:37 +00:00
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 )
{
2020-04-05 16:26:11 +00:00
using var result = await _httpClient . GetResponse ( new HttpRequestOptions
2013-11-04 21:50:37 +00:00
{
2016-10-06 18:55:01 +00:00
Url = url ,
BufferContent = false
2020-04-05 16:26:11 +00:00
} ) . ConfigureAwait ( false ) ;
2020-04-11 17:36:28 +00:00
var ext = result . ContentType . Split ( '/' ) [ ^ 1 ] ;
2013-11-04 21:50:37 +00:00
2020-04-05 16:26:11 +00:00
var fullCachePath = GetFullCachePath ( urlHash + "." + ext ) ;
2013-11-04 21:50:37 +00:00
2020-04-05 16:26:11 +00:00
Directory . CreateDirectory ( Path . GetDirectoryName ( fullCachePath ) ) ;
2020-04-11 17:36:28 +00:00
var stream = result . Content ;
await using ( stream . ConfigureAwait ( false ) )
2020-04-05 16:26:11 +00:00
{
2020-04-11 17:36:28 +00:00
var filestream = new FileStream ( fullCachePath , FileMode . Create , FileAccess . Write , FileShare . Read , IODefaults . FileStreamBufferSize , true ) ;
await using ( filestream . ConfigureAwait ( false ) )
{
await stream . CopyToAsync ( filestream ) . ConfigureAwait ( false ) ;
}
2017-10-20 16:16:56 +00:00
}
2020-04-05 16:26:11 +00:00
Directory . CreateDirectory ( Path . GetDirectoryName ( pointerCachePath ) ) ;
File . WriteAllText ( pointerCachePath , fullCachePath ) ;
2013-11-04 21:50:37 +00:00
}
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
}
}