DarKni8 37 Posted March 19, 2022 Share Posted March 19, 2022 So after my last thread and going through logs , I was able to make sure my plugin solution is building properly and not giving error in emby. But now problem is I am not getting my plugin name on emby plugin page and not even getting the configpage i created for plugin. Also i wanted to ask , is this happening because I am on beta and the guide for plugin creation is in old .NET framework!>?? Here is the link to repo. DoucheHellSung/YAScrapper: Yet Aother Scrapper (github.com) Here is screenshot of what i am getting Link to comment Share on other sites More sharing options...
DarKni8 37 Posted March 19, 2022 Author Share Posted March 19, 2022 got the name guys I have configured , config html page but its not opening Link to comment Share on other sites More sharing options...
chef 3746 Posted March 19, 2022 Share Posted March 19, 2022 Hey! Sorry I missed this. If you have any other questions let me know. More plugin developers, means more plugins... More plugins the better! DiskSpace on my GitHub uses a lot of the different plugin tricks. Recently, I posted an AI recommendations plugin on GitHub that does some cool things with .dll dependancies. 1 Link to comment Share on other sites More sharing options...
chef 3746 Posted March 19, 2022 Share Posted March 19, 2022 (edited) Okay! Cool! Your repo is looking good! You'll probabaly want to remove the IHttpClient from the plugin class. Keep only the values that structure the plugin in that class. Example: Id, Name, Configuration Pages, etc. You could create a "PluginServerEntryPoint" class that implements the IServerEntryPoint interface. Put any implementations for interacting with the server in there. Then, you could create an API folder, and place a "Service" class file, which implements IService. That file would handle any connection from the front end using Routes (like in ASP), and any connections to other services (like the Provider service, you are connecting too). Edited March 19, 2022 by chef 1 Link to comment Share on other sites More sharing options...
DarKni8 37 Posted March 19, 2022 Author Share Posted March 19, 2022 (edited) 14 minutes ago, chef said: Okay! Cool! Your repo is looking good! You'll probabaly want to remove the IHttpClient from the plugin class. Keep only the values that structure the plugin in that class. Example: Id, Name, Configuration Pages, etc. You could create a "PluginServerEntryPoint" class that implements the IServerEntryPoint interface. Put any implementations for interacting with the server in there. Then, you could create an API folder, and place a "Service" class file, which implements IService. That file would handle any connection from the front end using Routes (like in ASP), and any connections to other services (like the Provider service, you are connecting too). Thanks chef i will keep the points you highlighted in mind, Need more people like you who are cheerful in helping others. Thanks again Also I am sulking through your repos to learn ways. thanks again. @chef Also if you look at my repo i have defined config page for plugin just to show its name ! but still when i click on my plugin icon, it just doesnt load anything. How can i track and log these kind of things? Edited March 19, 2022 by DarKni8 1 Link to comment Share on other sites More sharing options...
BillOatman 501 Posted March 20, 2022 Share Posted March 20, 2022 This plugin repo has a very simple configuration page. You should be able to figure yours out from it. 2 Link to comment Share on other sites More sharing options...
DarKni8 37 Posted March 20, 2022 Author Share Posted March 20, 2022 2 hours ago, BillOatman said: This plugin repo has a very simple configuration page. You should be able to figure yours out from it. Thanks Bill Link to comment Share on other sites More sharing options...
chef 3746 Posted March 20, 2022 Share Posted March 20, 2022 On 3/19/2022 at 10:16 AM, DarKni8 said: Thanks chef i will keep the points you highlighted in mind, Need more people like you who are cheerful in helping others. Thanks again Also I am sulking through your repos to learn ways. thanks again. @chef Also if you look at my repo i have defined config page for plugin just to show its name ! but still when i click on my plugin icon, it just doesnt load anything. How can i track and log these kind of things? Did you make sure your plugin html pages and js pages are set as embedded resources? Link to comment Share on other sites More sharing options...
chef 3746 Posted March 20, 2022 Share Posted March 20, 2022 (edited) Also in your html, make sure you have the data-controller attribute set to link the javascript. data-controller="__plugin/MyPluginConfigurationPageJS" example: <div data-role="page" style="align-items: center; margin: auto;" class="type-interior pluginConfigurationPage withTabs MyPluginConfigurationPage" data-require="emby-button,emby-input,emby-select" data-controller="__plugin/MyPluginConfigurationPageJS"> <div class="content-primary"> <div class="verticalSection verticalSection"> <br /> <div class="pagingContainer"> <div class="tablesContainer"> </div> </div> </div> </div> </div> which was created in the Plugin.cs new PluginPageInfo() { Name = "MyPluginConfigurationPageJS", EmbeddedResourcePath = GetType().Namespace + ".Configuration.MyPluginConfigurationPage.js", }, which tells the plugin to look for the file "MyPluginConfiguration.js" page that has been set as an embedded resource. Does that make sense to you? Edited March 20, 2022 by chef 1 Link to comment Share on other sites More sharing options...
DarKni8 37 Posted March 21, 2022 Author Share Posted March 21, 2022 @chef yup it makes sense to me , its like giving address to my controller to let know where exactly configpage is located. But i have already given it on line 49 , and embedded script inside html under <script> tag, I will try restructuring how u said and see how things go. 1 Link to comment Share on other sites More sharing options...
chef 3746 Posted March 21, 2022 Share Posted March 21, 2022 Perhaps giving the name of the resource something other then "this.Name". Use: "configPage", or something more specific "YaScrapperConfigurationPage" I should just snag the repo... One moment Link to comment Share on other sites More sharing options...
chef 3746 Posted March 21, 2022 Share Posted March 21, 2022 (edited) Okay, a couple things to be aware about. Unfortunately, you can't easily add references to dependancies that Emby doesn't ship with. HtmlAgilityPack won't work when you load the plugin because it doesn't ship with emby. If you want to use that library, I do have a way to ship your plugin with the dll as embedded resource, and reference it, to load using Reflection. I can share that with you if you want. It gets a little advanced, but it isn't impossible. The other thing I wanted to mention, is that you don't have to add any JSON dependancies to your project because Emby has an Interface which can handle JSON serialization, and deserialization. It is called IJsonSerializer. It will load through Emby's Dependancy Injection, so you only have to add it to a constructor to use the object. You do, however, want to include the "System.Memory" reference in your dependancies. Let me know if I can be of more help, if you want the code to side load dll's in your project. Edited March 21, 2022 by chef 1 Link to comment Share on other sites More sharing options...
chef 3746 Posted March 21, 2022 Share Posted March 21, 2022 (edited) Sorry, there is more... You don't need the html, and body tags in your html documents because emby loads those pages inside it's html application. Also, you may consider moving the JavaScript to its own file to keep things clean and organized And.. maybe consider.... moving away from jQuery...? That is a personal choice I suppose, but I'm not sure if emby even ships with jQuery libraries anymore... It might... Let me know if I'm just being annoying now Edited March 21, 2022 by chef 1 Link to comment Share on other sites More sharing options...
BillOatman 501 Posted March 21, 2022 Share Posted March 21, 2022 2 hours ago, chef said: The other thing I wanted to mention, is that you don't have to add any JSON dependancies to your project because Emby ships with an Interface which can handle JSON serialization, and deserialization. It is called IJsonSerializer. I suspect it just uses the Microsoft System.Json which is used almost identically to newtonsoft. 1 Link to comment Share on other sites More sharing options...
BillOatman 501 Posted March 21, 2022 Share Posted March 21, 2022 2 hours ago, chef said: Also, maybe... consider.... moving away from jQuery...? That is a personal choice I suppose, but I'm not sure if emby even ships with jQuery libraries anymore... It might... I don't think it does. 1 Link to comment Share on other sites More sharing options...
Luke 37092 Posted March 21, 2022 Share Posted March 21, 2022 For now the web app does, but avoid writing any new code with jQuery. Eventually it will be removed and only pulled in via CDN url when requested, and some users will complain about that. 1 1 1 Link to comment Share on other sites More sharing options...
BillOatman 501 Posted March 21, 2022 Share Posted March 21, 2022 @DarKni8 I just gutted that Comskipper plugin code to be just a generic plugin with a enable/disable config control. I'll try it when I get home and when it works, I'll post a github link. 1 Link to comment Share on other sites More sharing options...
chef 3746 Posted March 21, 2022 Share Posted March 21, 2022 I actually made a skeleton here too. YAScrapper-master.zip @BillOatman That's what we should do, maybe create a github tutorial with a skeleton project to start people off with. Just the barebones example of an IService, IServerEntryPoint, and the Plugin class. With a couple embedded web pages so they can see how to wire them up and get it working. a quick write up about what is necessary, and what are the limitations as well. If there is time LOL! 1 Link to comment Share on other sites More sharing options...
DarKni8 37 Posted March 22, 2022 Author Share Posted March 22, 2022 (edited) Hi @chef, @BillOatman and @Luke You guys are awesome Oh lol about that HTML AND BODY TAG, i took it from roku bif plugin i guess....Even i dont like jquery and definitely will link a js file and write script there without jquery and in a proper structure. Yes a skeleton project will be great to kick off things for newbies like me. Otherwise it becomes difficult. But now i have understood basic structure of it but could be awesome dor future. Also i dont see documentation for metadat provider api which is used by luke and others in their plugin to provide metadata. I searched on tutorial repo, am i missing something here? Or its not made public for some reason? Thanks again Chef, bill and luke for dealing patiently with this situation, have to learn lots from you guys @chef i have seen plugins using HTML Agility...what do you suggest i should do , as its a must have thing for me. I will remove newtonsoft json though thanks for pointing it out. Edited March 22, 2022 by DarKni8 Link to comment Share on other sites More sharing options...
chef 3746 Posted March 22, 2022 Share Posted March 22, 2022 (edited) 5 hours ago, DarKni8 said: @chef i have seen plugins using HTML Agility...what do you suggest i should do , as its a must have thing for me. Ah yes, loading dependencies on command. This is a super cool trick. To do this we are going to create an event handler on the AppDomain Assembly, so when the plugin loads and it tries to use a dependency that isn't there it will load it. Cool right?!? Add the Dependency to your project for the Dynamic Link Library you want to use. In your case you will add the HTMLAgilityPack dependency. You have already done this. We will need the library accessible while you are coding it. However, issues happen when you want to load your plugin into Emby. Emby doesn't have this library, and your plugin can only use the libraries that Emby uses... not for long! 2. Create a folder in your project called "References" 3. Click on the "Reference" folder, and "Add an Existing Item" 4. Search for "HTMLAglilityPack.dll" It is most likely saved in a folder on your computer called ".nuget/packages/HTMLAgilityPack". This is where Visual studio keeps all it's nuget libraries. Be sure to Select "AllFiles (*.*)" to show the DLL in the open window I'm on Windows, this is what I see below. 5. Add the DLL inside the "Reference" folder 6. Right Click the DLL => Properties => Build Action: Embedded Resource Now, your plugin will ship with HTMLAgilityPack! And... It has references to it! Awesome! But, we are not done yet! Emby doesn't know what HTMLAgilityPack is. So, when Emby tries load you plugin it is going to error. It will NOT load your plugin. So we need to interrupt Emby's and tell it what to do when it comes across a reference to an Assembly it doesn't undertsand! 7. The Magic! Hopefully you understood what the IServerEntryPoint interface does from what I explained before. This will become important here. Remember, any class that implements the IServerEntryPoint will start when Emby loads. We'll use this to our advantage. We are going to interrupt ("extended") Emby's loading, by attaching to the "AssembyResolve" event's in the Runtime. So Cool! Now we can load our DLL before Emby has a chance to Error in the callback of this event.... ("callback"... can I use that terminology in c#.. or is that just a JS thing... maybe it is the "subscriber method"?... meh... you get it.) AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; It's magical! LOL! Create this class: using System; using System.Linq; using System.Reflection; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Logging; namespace YAScrapper.References { public class AssemblyResolve : IServerEntryPoint { private ILogger Log { get; } public AssemblyResolve(ILogManager logMan) { Log = logMan.GetLogger(Plugin.Instance.Name); //This event will fire when the plugin is loading dependencies AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; } /// <summary> /// Load any required dependent libraries into the plugin. /// </summary> /// <param name="sender"></param> /// <param name="args"></param> /// <returns></returns> private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { //Don't try and load items that are not theHTMLAgilityPack namespace if (!(args.Name.Contains("HTMLAgilityPack"))) return null; //Don't load the assembly twice var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.Name); if (assembly != null) return assembly; Log.Info($"Load Request {args.Name}"); //r1 is that Assembly we were looking for. Naming? Meh.. fix it later. var r1 = Assembly.GetExecutingAssembly().GetManifestResourceNames().FirstOrDefault(s => s.Contains(args.Name.Split(',')[0])); Log.Info($"Loading Assembly {r1}"); using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(r1)) { byte[] assemblyData = new byte[stream.Length]; stream.Read(assemblyData, 0, assemblyData.Length); return Assembly.Load(assemblyData); } } public void Dispose() { } public void Run() { } } } Craziest thing is that you can load all your external DLL's here. From this point forward, you can simply: add your DLL as an embedded resource in the "References" folder, Extended the condition: if (!(args.Name.Contains("HTMLAgilityPack")) || !(args.Name.Contains("MY_OTHER_DLL_NAME"))) return null; Mind you this code is still somewhat in it's infancies... I only just learned how to do this myself, so there is some obvious refactoring that could be done. Perhaps iterating over a static List of DLL names during load.... or something like that. And... I know... I know... attaching events in constructors *might* (not be the right thing to do (I dunno)... But we need to get that event attached ASAP. so... we're doin' it! LOL! Does this explain things in a good way. Do I need to make any steps clearer? Edited March 22, 2022 by chef 1 Link to comment Share on other sites More sharing options...
DarKni8 37 Posted March 22, 2022 Author Share Posted March 22, 2022 (edited) @chefits lots for me to digest ...but i am gonna give it a shot and see how things goes. Thanks man this is gonna help me and many people yo come Definitely i will let you know if i need any clarification in some steps, all this is alien to me but i will grasp it slowly Edited March 22, 2022 by DarKni8 Link to comment Share on other sites More sharing options...
BillOatman 501 Posted March 23, 2022 Share Posted March 23, 2022 The generic plugin seems to work OK. Here is the link. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now