Merge pull request #5217 from jellyfin/auto-manifest

handle plugin manifests automatically

(cherry picked from commit c54ca489f1)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
This commit is contained in:
dkanada
2021-02-25 17:17:34 +09:00
committed by Joshua M. Boniface
parent 621c0b9d15
commit eb0621a354
4 changed files with 99 additions and 33 deletions

View File

@@ -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,34 +351,76 @@ 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. {Path}", path);
_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)
{
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>
/// Changes a plugin's load status.
/// </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,