Giter VIP home page Giter VIP logo

kodisharp's Introduction

KodiSharp

Write rich Kodi addons using the .NET framework (C#/VB.NET/F#/...) TestPlugin

Why?

The idea started when i was writing an addon for Kodi. I was frustrated by the way addons work.

Every time you click on a menu entry, all variables are destroyed and the script is re-invoked again.

You can pass some data to the new script by using a querystring, but the size is limited and the only workaround is to use temporary files.

On top of that, not all Python modules can be used. They have to be repackaged specifically for Kodi.

By using the .NET runtime, we can

  • Use Nuget to manage dependencies
  • Use a hosted .NET runtime, which is never destroyed and can keep variables alive.
  • Run background activities without blocking the Kodi process
  • Use the .NET ecosystem: rich APIs, fast runtime (NOTE: see Performance)

How does it work?

KodiSharp works by injecting the .NET Runtime into the Kodi process.

The .NET Runtime is provided by CLRHost (for Windows users) or MonoHost (Windows/Mac/Linux), which offer functionality to load and run addons written in .NET (C#/VB.Net/F#).

Python uses ctypes to load one of the providers and to interact with .NET

This gives us an important advantage over stdout based REPL (spawning a .NET process and reading its output - e.g https://github.com/CRialDev/KSHarp)

Once the .NET runtime is loaded in the process, it persists until the host process (Kodi) terminates

We can run plugins quickly by recycling their instances: persist both static and instance variables (no more temporary files!).

The plugin gets detatched and reattached when required. If the plugin is no longer needed, it can be disposed explicitly by the developer.

Performance

To achieve Python interoperability, KodiSharp uses an in-process JSON RPC that evaluates Python code.

I explored the possibility of using the Python interpreter directly through libpython, but it isn't worth the extra effort. Ultimately, we'd still use PyRun_SimpleString, and the improvements would be minimal.

In the current implementation, every call to Kodi APIs has to undergo the following steps, involving a round-trip:

  • [C#] Escape call arguments
  • [C#] Encode to JSON
  • [C#] Pass the JSON message to Python
  • [Python] Decode the JSON message
  • [Python] Eval the code and store the result in a special accumulator variable called LastResult
  • [Python] Send the result back to C# in JSON format

Due to this, code making frequent calls to Kodi or Python should be optimized to reduce the transitions where possible

Features

  • Events support (xbmc.Monitor and xbmc.Player)
  • Python interfaces
    • Code eval
    • Variable management
    • Value escaping
    • Function calls
    • Python console logging
  • C# Bindings for Kodi modules (xbmc, xbmcgui, ...)
  • URL Routing: define handlers for different plugin sections/functionalities, and connect them to menu entries
  • Support for Service addons (executed in background, as defined in addon.xml)
  • Addons can run in the background, and persist across script invocation.

Samples

You can load the TestPlugin project for a working sample.

On Windows you can also try the SpeechRecognizerPlugin project, which is an example of speech recognition inside a Kodi Addon. Note that the speech recognition API uses the UWP APIs, and requires that you have enabled speech services. On Windows 10, you can do that from the privacy menu in the modern control panel.

Debugging

First of all, target kodi.exe as the process we want to debug for your Class Library project

  • Right click on the plugin project
  • Properties
  • Debug
  • Start external program -> Browse for Kodi.exe

How to enable debugging (for Windows)

This method works only on Windows, since it uses AllocConsole and Debugger.Launch, features that are not available on Unix

Set enable_debug to True in default.py, at the following line

bridge = Bridge(lib_path, assembly_path, enable_debug=False)

If you are on Windows, the JIT Debugger Window will pop-up and a console window will appear

Optional: Automatically start and debug the plugin from Visual Studio

Navigate to "%appdata%\Kodi\userdata" Create a file called "autoexec.py" and insert the following code to start your plugin when kodi starts

import xbmc
xbmc.executebuiltin("RunAddon(plugin.video.test)")

Replace "plugin.video.test" with the plugin name you used in addon.xml

This method avoids having to select the debugger from the JIT window every time

How to use

Create a new C# Class Library, add the KodiInterop assembly/project as reference. Model the plugin class like this

using Smx.KodiInterop;
using Smx.KodiInterop.Builtins;

namespace TestPlugin
{
    public class TestPlugin : KodiAddon
    
    [Route("/")]
	public int MainHandler(NameValueCollection parameters){
        UiBuiltins.Notification(
            header: "My Notification",
            message: "Hello World from C#",
            duration: TimeSpan.FromSeconds(1)
        );
    }

    [PluginEntry]
    public static int PluginMain() {
        return GetInstance<TestPlugin>(enableDebug: true, persist: true).Run();
    }
}

Compile MonoHost

cd MonoHost
mkdir build
cd build
cmake ..
cmake --build .

Edit default.py to specify the location of the plugin assembly. The script is configured for an in-tree build of the project.

You can use it as a starting point, changing the following variables accordingly:

File Variable Default Location
Mono Host monohost_path KodiInterop/Mono/build/libMonoHost.so|dll|dylib
CLR Host clrhost_path KodiInterop/bin/<build_arch>/<build_type>/CLRHost.dll
Plugin Assembly assembly_path KodiInterop/TestPlugin/bin/<build_arch>/<build_type>/TestPlugin.dll

If you are on Windows, you can set mono_on_windows=True if you want to use Mono instead of .NET

NOTE: it's important to use os.path.join to construct paths

TODO

  • Implement remaining builtins
  • Implement remaining modules functionality (xbmc, xbmcgui, ...)
  • Implement a JSON interface (via executeJSONRPC)

kodisharp's People

Contributors

smx-smx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

kodisharp's Issues

Update MonoHost

MonoHost has to be updated in order to work with the latest API changes

Android support

I'll make this issue to track my experiments with Android support.

Android support is actually hard to pull off due to SELinux restricting native libraries to the apk file being ran (.so files must be in the lib subfolder of the apk).

I tried to work around that by using android_create_namespace to create a new namespace, but it simply won't work until SELinux is set to permissive (which requires root access).

Even after doing that, the Kodi app just crashed upon loading the library and i'm not completely sure why that happened (didn't have time to debug the crash yet)

Due to the aforementioned limitations, it looks like the best course of action would be to
repackage the Kodi APK to include the mono host library - so that it can be loaded without hacks.

That would obviously make it annoying to maintain new versions/releases of Kodi, but i don't have any other idea in mind at the moment.

I'm starting to feel like i've reached the point where a proper integration of C# in the Kodi source code is the next step to pursuit, but that's a nontrivial step to pull off

Remove RGiesecke.DllExport

UnmanagedExports allows Windows DLLs to expose .NET methods.
This works in Windows because .DLL files can be loaded by C code seamlessy, by using LoadLibrary. Hence, python can load them using ctypes.

In Linux this doesn't work because the output format is still .DLL, and Linux can only load .so files.
This is worked around by using a little proxy library, written in C, that loads Mono into the Kodi process.

However using the [DllExport] attribute will cause errors in Linux, and needs to be made conditional.
The current workaround is a hack involving a preprocessor macro.

The usage of macros mean that the resulting assembly cannot target both Windows and Linux, and is also annoying to maintain.

UnmanagedExports on Windows should be replaced by a C++ library that does the equivalent of the mono host

As a note/reminder, loading .NET into the Kodi process offers a better advantage than using pipes with external processes.
It allows us to store static data inside Kodi, so that we can keep addon instances and all their variables across plugin invocations.
When the plugin is re-invoked, we can fetch the instance from that static pool and re-initialize the bridge with the new runtime data.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.