Jump to content

Noob question: accessing configuration setting withing a plugin


Go to solution Solved by softworkz,

Recommended Posts

Killface69
Posted

Hi, I'm workin in C.
So far I tried the examle simple UI from the SDK, especially the TargetFolder

// <copyright file="PluginUIDemoPlugin.cs" company="Emby LLC">
// Copyright © 2022 - Emby LLC. All rights reserved.
// </copyright>

namespace EmbyPluginUiDemo
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using EmbyFileBrowser.Model;


    using MediaBrowser.Common.Plugins;
    using MediaBrowser.Controller;
    using MediaBrowser.Controller.Plugins;
    using MediaBrowser.Model.Drawing;
    using MediaBrowser.Model.Logging;
    using MediaBrowser.Model.Plugins;
    using MediaBrowser.Model.Plugins.UI;

    /// <summary>
    /// The plugin.
    /// </summary>
    public class meetPlugin : BasePluginSimpleUI<FileBrowserPluginOptions>, IHasThumbImage
    {
        private readonly IServerApplicationHost applicationHost;

        /// <summary>The Plugin ID.</summary>
        private readonly Guid id = new Guid("9D22C04B-744C-4F8A-A009-F4CFDCF73ECF");
        public static meetPlugin Instance { get; private set; }
        private readonly ILogger logger;

        private List<IPluginUIPageController> pages;

        /// <summary>Initializes a new instance of the <see cref="meetPlugin" /> class.</summary>
        /// <param name="applicationHost">The application host.</param>
        /// <param name="logManager">The log manager.</param>
        public meetPlugin(IServerApplicationHost applicationHost, ILogManager logManager)
         : base(applicationHost)
        {
            this.applicationHost = applicationHost;
            this.logger = logManager.GetLogger(this.Name);
                        
        }

        /// <summary>Gets the description.</summary>
        /// <value>The description.</value>
        public override string Description => "This plugin demonstrates the new Emby Plugin UI features";

        /// <summary>Gets the unique id.</summary>
        /// <value>The unique id.</value>
        public override Guid Id => this.id;

        /// <summary>Gets the name of the plugin</summary>
        /// <value>The name.</value>
        public override sealed string Name => "meet Moovie manager";
        public const string PluginName = "meet Moovie manager";


        /// <summary>Gets the thumb image format.</summary>
        /// <value>The thumb image format.</value>
        public ImageFormat ThumbImageFormat => ImageFormat.Jpg;

        /// <summary>Gets the thumb image.</summary>
        /// <returns>An image stream.</returns>
        public Stream GetThumbImage()
        {
            var type = this.GetType();
            return type.Assembly.GetManifestResourceStream(type.Namespace + ".PluginUiThumb.jpg");
        }

        protected override bool OnOptionsSaving(FileBrowserPluginOptions options)
        {
            options.ValidateOrThrow();

            return base.OnOptionsSaving(options);
        }

        protected override void OnOptionsSaved(FileBrowserPluginOptions options)
        {
            base.OnOptionsSaved(options);
        }

        /// <summary>
        /// Completely overwrites the current configuration with a new copy
        /// Returns true or false indicating success or failure
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        /// <exception cref="System.ArgumentNullException">configuration</exception>
        public void UpdateConfiguration(BasePluginConfiguration configuration)
        {
            //Configuration= configuration;
        }

        /// <summary>
        /// Gets the plugin's configuration
        /// </summary>
        /// <value>The configuration.</value>
        public FileBrowserPluginOptions Configuration  = new FileBrowserPluginOptions();

        public void SetStartupInfo(Action<string> directoryCreateFn)
        {
        }
    }
}
    public class PluginOptions : EditableOptionsBase
    {
        public override string EditorTitle => "Plugin Options";

        public override string EditorDescription => "This is a description text, shown at the top of the options page.\n"
                                                    + "The options below are just a few examples for creating UI elementsd.";

        [DisplayName("Output Folder")]
        [Description("Please choose a folder for plugin output")]
        [EditFolderPicker]
        public string TargetFolder { get; set; }

I want to access the setting from within an ImageEnhancer

    class ImageEnhancer : IImageEnhancer
    {
...

        bool IImageEnhancer.Supports(BaseItem item, ImageType imageType)
        {
            var supportedTypes = new[] { "Movie", "BoxSet" };
            bool isSupported = Array.IndexOf(supportedTypes, item.GetType().Name) >= 0;


            // access folder info here for example
            
            logger.Info($"Support check for item: {item.Name}, Supported: {isSupported}");
            return isSupported;
        }
 }

I tried for hours, tried the advanced UI sample but I cannot figure out the instancing studd/actually accessing the variables.

Any help appreciated.

 

  • Solution
Posted
2 hours ago, Killface69 said:

I tried for hours, tried the advanced UI sample but I cannot figure out the instancing studd/actually accessing the variables.

Yea, sorry for that, this is admittedly everything but obvious. It has always been a kind of plothole and many plugins had resorted to exposing their own instance as a static property, which is really an awful pattern.

Also the Dependency Injection via class constructors can be quite confusing when you aren't fully clear about which classes are being created by DI and which are created and tracked manually or as children of a DI-created instance. In the latter cases you would often need to transfer lots of instances through your constructors, because they can only come from the DI-created parent instance.

We have a pattern that helps with these things and adds a lot of convenience and allows to write code that is much cleaner:

  • There's a base class Emby SDK Reference: CommonBaseCore that you can use
  • You create your own derivate (once) in your plugin, like CommonBase
  • Then you derive all most of your classes from CommonBase (of course not those which have other bases)
  • The constructor needs an Emby SDK Reference: IServiceRoot implementation for which you can use the provided Emby SDK Reference: ServiceRoot class
    (this one is stateless, you can create new instances or reuse existing ones - it doesn't matter)
  • That ServiceRoot is just a wrapper around Emby SDK Reference: IApplicationHost in this case
  • ApplicationHost is carrying the "root" of everything: The DI container. With it's Emby SDK Reference: IApplicationHost.Resolve<T>() method, you can get and create instances for all DI types without constrructor injection. The CommonBaseCore class wraps that and when you use that as base class, you can call this.GetService<>() from everywhere in your code to get any instances from DI
  • Now for how to get at the options? You expose them on the plugin class and you can get an instance of the plugin, again from Emby SDK Reference: IApplicationHost.Plugins
  • You can do that in your CommonBase class and that allows you to access the options easily from everywhere in your code:

 

    public abstract class CommonBase : CommonBaseCore
    {
        private MyPlugin myPlugin;

        protected CommonBase(IServiceRoot serviceRoot, string logName = null)
            : base(serviceRoot, logName)
        {
        }

        protected MyPluginOptions Options => this.Plugin.Options;

        protected MyPlugin Plugin
        {
            get
            {
                if (this.myPlugin == null)
                {
                    this.myPlugin = this.GetService<IApplicationHost>().Plugins.OfType<MyPlugin>().FirstOrDefault();
                    if (this.myPlugin == null)
                    {
                        throw this.GetEx(@"The {0} plugin is not loaded", MyPlugin.PluginName);
                    }
                }

                return this.myPlugin;
            }
        }
    }

 

I have extended the SDK sample with all the things I mentioned above. It will be in the next beta SDK, but here's a copy up-front:

EmbyPluginSimpleUi.zip

 

  • Like 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...