@ -1,8 +1,10 @@
#nullable enable
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Net.Http ;
using System.Reflection ;
using System.Text ;
using System.Text.Json ;
@ -11,9 +13,11 @@ using MediaBrowser.Common;
using MediaBrowser.Common.Extensions ;
using MediaBrowser.Common.Json ;
using MediaBrowser.Common.Json.Converters ;
using MediaBrowser.Common.Net ;
using MediaBrowser.Common.Plugins ;
using MediaBrowser.Model.Configuration ;
using MediaBrowser.Model.Plugins ;
using MediaBrowser.Model.Updates ;
using Microsoft.Extensions.DependencyInjection ;
using Microsoft.Extensions.Logging ;
@ -33,6 +37,21 @@ namespace Emby.Server.Implementations.Plugins
private readonly IList < LocalPlugin > _plugins ;
private readonly Version _minimumVersion ;
private IHttpClientFactory ? _httpClientFactory ;
private IHttpClientFactory HttpClientFactory
{
get
{
if ( _httpClientFactory = = null )
{
_httpClientFactory = _appHost . Resolve < IHttpClientFactory > ( ) ;
}
return _httpClientFactory ;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="PluginManager"/> class.
/// </summary>
@ -332,32 +351,74 @@ namespace Emby.Server.Implementations.Plugins
ChangePluginState ( plugin , PluginStatus . Malfunctioned ) ;
}
/// <summary>
/// Saves the manifest back to disk.
/// </summary>
/// <param name="manifest">The <see cref="PluginManifest"/> to save.</param>
/// <param name="path">The path where to save the manifest.</param>
/// <returns>True if successful.</returns>
/// <inheritdoc/>
public bool SaveManifest ( PluginManifest manifest , string path )
{
if ( manifest = = null )
{
return false ;
}
try
{
var data = JsonSerializer . Serialize ( manifest , _jsonOptions ) ;
File . WriteAllText ( Path . Combine ( path , "meta.json" ) , data ) ;
return true ;
}
#pragma warning disable CA1031 // Do not catch general exception types
catch ( Exception e )
#pragma warning restore CA1031 // Do not catch general exception types
catch ( ArgumentException e )
{
_logger . LogWarning ( e , "Unable to save plugin manifest due to invalid value. {Path}" , path ) ;
return false ;
}
}
/// <inheritdoc/>
public async Task < bool > GenerateManifest ( PackageInfo packageInfo , Version version , string path )
{
if ( packageInfo = = null )
{
_logger . LogWarning ( e , "Unable to save plugin manifest. {Path}" , path ) ;
return false ;
}
var versionInfo = packageInfo . Versions . First ( v = > v . Version = = version . ToString ( ) ) ;
var imagePath = string . Empty ;
if ( ! string . IsNullOrEmpty ( packageInfo . ImageUrl ) )
{
var url = new Uri ( packageInfo . ImageUrl ) ;
imagePath = Path . Join ( path , url . Segments [ ^ 1 ] ) ;
await using var fileStream = File . OpenWrite ( imagePath ) ;
try
{
await using var downloadStream = await HttpClientFactory
. CreateClient ( NamedClient . Default )
. GetStreamAsync ( url )
. ConfigureAwait ( false ) ;
await downloadStream . CopyToAsync ( fileStream ) . ConfigureAwait ( false ) ;
}
catch ( HttpRequestException ex )
{
_logger . LogError ( ex , "Failed to download image to path {Path} on disk." , imagePath ) ;
imagePath = string . Empty ;
}
}
var manifest = new PluginManifest
{
Category = packageInfo . Category ,
Changelog = versionInfo . Changelog ? ? string . Empty ,
Description = packageInfo . Description ,
Id = new Guid ( packageInfo . Id ) ,
Name = packageInfo . Name ,
Overview = packageInfo . Overview ,
Owner = packageInfo . Owner ,
TargetAbi = versionInfo . TargetAbi ? ? string . Empty ,
Timestamp = string . IsNullOrEmpty ( versionInfo . Timestamp ) ? DateTime . MinValue : DateTime . Parse ( versionInfo . Timestamp ) ,
Version = versionInfo . Version ,
Status = PluginStatus . Active ,
AutoUpdate = true ,
ImagePath = imagePath
} ;
return SaveManifest ( manifest , path ) ;
}
/// <summary>
@ -410,7 +471,7 @@ namespace Emby.Server.Implementations.Plugins
if ( plugin = = null )
{
// Create a dummy record for the providers.
// TODO: remove this code , if all provided have been released as separate plugins.
// TODO: remove this code once all provided have been released as separate plugins.
plugin = new LocalPlugin (
instance . AssemblyFilePath ,
true ,