using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Jellyfin.Api.Constants; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Updates; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Jellyfin.Api.Controllers; /// /// Package Controller. /// [Route("")] [Authorize] public class PackageController : BaseJellyfinApiController { private readonly IInstallationManager _installationManager; private readonly IServerConfigurationManager _serverConfigurationManager; /// /// Initializes a new instance of the class. /// /// Instance of the interface. /// Instance of the interface. public PackageController(IInstallationManager installationManager, IServerConfigurationManager serverConfigurationManager) { _installationManager = installationManager; _serverConfigurationManager = serverConfigurationManager; } /// /// Gets a package by name or assembly GUID. /// /// The name of the package. /// The GUID of the associated assembly. /// Package retrieved. /// A containing package information. [HttpGet("Packages/{name}")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetPackageInfo( [FromRoute, Required] string name, [FromQuery] Guid? assemblyGuid) { var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false); var result = _installationManager.FilterPackages( packages, name, assemblyGuid ?? default) .FirstOrDefault(); if (result is null) { return NotFound(); } return result; } /// /// Gets available packages. /// /// Available packages returned. /// An containing available packages information. [HttpGet("Packages")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetPackages() { IEnumerable packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false); return packages; } /// /// Installs a package. /// /// Package name. /// GUID of the associated assembly. /// Optional version. Defaults to latest version. /// Optional. Specify the repository to install from. /// Package found. /// Package not found. /// A on success, or a if the package could not be found. [HttpPost("Packages/Installed/{name}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] [Authorize(Policy = Policies.RequiresElevation)] public async Task InstallPackage( [FromRoute, Required] string name, [FromQuery] Guid? assemblyGuid, [FromQuery] string? version, [FromQuery] string? repositoryUrl) { var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false); if (!string.IsNullOrEmpty(repositoryUrl)) { packages = packages.Where(p => p.Versions.Any(q => q.RepositoryUrl.Equals(repositoryUrl, StringComparison.OrdinalIgnoreCase))) .ToList(); } var package = _installationManager.GetCompatibleVersions( packages, name, assemblyGuid ?? Guid.Empty, specificVersion: string.IsNullOrEmpty(version) ? null : Version.Parse(version)) .FirstOrDefault(); if (package is null) { return NotFound(); } await _installationManager.InstallPackage(package).ConfigureAwait(false); return NoContent(); } /// /// Cancels a package installation. /// /// Installation Id. /// Installation cancelled. /// A on successfully cancelling a package installation. [HttpDelete("Packages/Installing/{packageId}")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult CancelPackageInstallation( [FromRoute, Required] Guid packageId) { _installationManager.CancelInstallation(packageId); return NoContent(); } /// /// Gets all package repositories. /// /// Package repositories returned. /// An containing the list of package repositories. [HttpGet("Repositories")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetRepositories() { return Ok(_serverConfigurationManager.Configuration.PluginRepositories.AsEnumerable()); } /// /// Sets the enabled and existing package repositories. /// /// The list of package repositories. /// Package repositories saved. /// A . [HttpPost("Repositories")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] public ActionResult SetRepositories([FromBody, Required] RepositoryInfo[] repositoryInfos) { _serverConfigurationManager.Configuration.PluginRepositories = repositoryInfos; _serverConfigurationManager.SaveConfiguration(); return NoContent(); } }