using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Mime; using Jellyfin.Api.Attributes; using Jellyfin.Api.Models; using MediaBrowser.Common.Plugins; using MediaBrowser.Model.Net; using MediaBrowser.Model.Plugins; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Controllers { /// /// The dashboard controller. /// [Route("")] public class DashboardController : BaseJellyfinApiController { private readonly ILogger _logger; private readonly IPluginManager _pluginManager; /// /// Initializes a new instance of the class. /// /// Instance of interface. /// Instance of interface. public DashboardController( ILogger logger, IPluginManager pluginManager) { _logger = logger; _pluginManager = pluginManager; } /// /// Gets the configuration pages. /// /// Whether to enable in the main menu. /// ConfigurationPages returned. /// Server still loading. /// An with infos about the plugins. [HttpGet("web/ConfigurationPages")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult> GetConfigurationPages( [FromQuery] bool? enableInMainMenu) { var configPages = _pluginManager.Plugins.SelectMany(GetConfigPages).ToList(); if (enableInMainMenu.HasValue) { configPages = configPages.Where(p => p!.EnableInMainMenu == enableInMainMenu.Value).ToList(); } return configPages; } /// /// Gets a dashboard configuration page. /// /// The name of the page. /// ConfigurationPage returned. /// Plugin configuration page not found. /// The configuration page. [HttpGet("web/ConfigurationPage")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesFile(MediaTypeNames.Text.Html, "application/x-javascript")] public ActionResult GetDashboardConfigurationPage([FromQuery] string? name) { var altPage = GetPluginPages().FirstOrDefault(p => string.Equals(p.Item1.Name, name, StringComparison.OrdinalIgnoreCase)); if (altPage == null) { return NotFound(); } IPlugin plugin = altPage.Item2; string resourcePath = altPage.Item1.EmbeddedResourcePath; Stream? stream = plugin.GetType().Assembly.GetManifestResourceStream(resourcePath); if (stream == null) { _logger.LogError("Failed to get resource {Resource} from plugin {Plugin}", resourcePath, plugin.Name); return NotFound(); } return File(stream, MimeTypes.GetMimeType(resourcePath)); } private IEnumerable GetConfigPages(LocalPlugin plugin) { return GetPluginPages(plugin).Select(i => new ConfigurationPageInfo(plugin.Instance, i.Item1)); } private IEnumerable> GetPluginPages(LocalPlugin? plugin) { if (plugin?.Instance is not IHasWebPages hasWebPages) { return Enumerable.Empty>(); } return hasWebPages.GetPages().Select(i => new Tuple(i, plugin.Instance)); } private IEnumerable> GetPluginPages() { return _pluginManager.Plugins.SelectMany(GetPluginPages); } } }