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.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Net; using MediaBrowser.Model.Plugins; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; namespace Jellyfin.Api.Controllers { /// /// The dashboard controller. /// [Route("")] public class DashboardController : BaseJellyfinApiController { private readonly ILogger _logger; private readonly IServerApplicationHost _appHost; private readonly IPluginManager _pluginManager; /// /// Initializes a new instance of the class. /// /// Instance of interface. /// Instance of interface. /// Instance of interface. public DashboardController( ILogger logger, IServerApplicationHost appHost, IPluginManager pluginManager) { _logger = logger; _appHost = appHost; _pluginManager = pluginManager; } /// /// Gets the configuration pages. /// /// Whether to enable in the main menu. /// The . /// 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, [FromQuery] ConfigurationPageType? pageType) { var configPages = _pluginManager.Plugins.SelectMany(GetConfigPages).ToList(); if (pageType.HasValue) { configPages = configPages.Where(p => p!.ConfigurationPageType == pageType).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) { IPlugin? plugin = null; Stream? stream = null; var isJs = false; var isTemplate = false; var altPage = GetPluginPages().FirstOrDefault(p => string.Equals(p.Item1.Name, name, StringComparison.OrdinalIgnoreCase)); if (altPage != null) { plugin = altPage.Item2; stream = plugin.GetType().Assembly.GetManifestResourceStream(altPage.Item1.EmbeddedResourcePath); isJs = string.Equals(Path.GetExtension(altPage.Item1.EmbeddedResourcePath), ".js", StringComparison.OrdinalIgnoreCase); isTemplate = altPage.Item1.EmbeddedResourcePath.EndsWith(".template.html", StringComparison.Ordinal); } if (plugin != null && stream != null) { if (isJs) { return File(stream, MimeTypes.GetMimeType("page.js")); } if (isTemplate) { return File(stream, MimeTypes.GetMimeType("page.html")); } return File(stream, MimeTypes.GetMimeType("page.html")); } return NotFound(); } 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 new List>(); } return hasWebPages.GetPages().Select(i => new Tuple(i, plugin.Instance)); } private IEnumerable> GetPluginPages() { return _pluginManager.Plugins.SelectMany(GetPluginPages); } } }