Skip to content

Commit

Permalink
Ryujinx game provider addon
Browse files Browse the repository at this point in the history
  • Loading branch information
albfan committed Oct 22, 2021
1 parent 6a29ad0 commit b015cf3
Show file tree
Hide file tree
Showing 8 changed files with 967 additions and 0 deletions.
692 changes: 692 additions & 0 deletions plugin.program.ryujinx/LICENSE

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions plugin.program.ryujinx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Kodi game add-on for Ryujinx

It allows you to launch your Ryujinx games from kodi.

An installable .zip can be downloaded from "[Releases](https://github.com/albfan/com.ryujinx.source/releases)" tab.

License: [GPL v.3](http://www.gnu.org/copyleft/gpl.html)
Binary file added plugin.program.ryujinx/Ryujinx.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions plugin.program.ryujinx/addon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon id="plugin.program.ryujinx"
version="2.4.0"
name="Ryujinx"
provider-name="albfan">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.pil" version="5.1.0" />
</requires>
<extension point="xbmc.python.pluginsource" library="main.py">
<provides>executable game</provides>
</extension>
<extension point="kodi.gameclient"
library_android="game.moonlight.so"
library_linux="game.moonlight.so"
library_osx="game.moonlight.dylib"
library_windx="game.moonlight.dll"
library_wingl="game.moonlight.dll">
<platforms></platforms>
<extensions>nsp</extensions>
<supports_vfs>true</supports_vfs>
<supports_no_game>true</supports_no_game>
</extension>
<extension point="xbmc.addon.metadata">
<summary lang="en_GB">Ryujinx emulator on Kodi</summary>
<description lang="en_GB">Ryujinx frontend for Kodi.</description>
<assets>
<icon>Ryujinx.png</icon>
<fanart>fanart.jpg</fanart>
<screenshot>resources\screenshot-01.jpg</screenshot>
<screenshot>resources\screenshot-02.jpg</screenshot>
<screenshot>resources\screenshot-03.jpg</screenshot>
</assets>
<news>See ryujinx.org for latest updates</news>
<license>GPL-3.0-or-later</license>
<source>https://github.com/Ryujinx/Ryujinx</source>
</extension>
</addon>
160 changes: 160 additions & 0 deletions plugin.program.ryujinx/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Module: main
# Author: Roman V. M.
# Created on: 28.11.2014
# License: GPL v.3 https://www.gnu.org/copyleft/gpl.html
"""
Ruyjinx game addon
"""
import sys
from urllib.parse import urlencode, parse_qsl
import xbmcgui
import xbmcplugin
import xbmcaddon
import xbmcvfs
import json
import subprocess
import base64
import os
from PIL import Image
import io
import platform

# Get the plugin url in plugin:// notation.
_URL = sys.argv[0]
# Get the plugin handle as an integer number.
_HANDLE = int(sys.argv[1])

MONITOR_MODEL='XWAYLAND17'
def get_url(**kwargs):
"""
Create a URL for calling the plugin recursively from the given set of keyword arguments.
:param kwargs: "argument=value" pairs
:return: plugin call URL
:rtype: str
"""
return '{}?{}'.format(_URL, urlencode(kwargs))


def list_games():
"""
Create the list of playable games in the Kodi interface.
:type category: str
"""
emulator_path = xbmcaddon.Addon().getSettingString('emulator_path')
game_dir_path = xbmcaddon.Addon().getSettingString('game_dir_path')
result = subprocess.run([emulator_path, '--list-games', game_dir_path], stdout=subprocess.PIPE)
xbmc.log('------ {}'.format(result), xbmc.LOGINFO)
arrayMetadataGame = json.loads(result.stdout.decode('utf-8'))


# Set plugin content. It allows Kodi to select appropriate views
# for this type of content.
xbmcplugin.setContent(_HANDLE, 'games')
# Iterate through games.
for game in arrayMetadataGame:
# Create a list item with a text label and a thumbnail image.
list_item = xbmcgui.ListItem(label=game['title_name'])
# Set additional info for the list item.
# 'mediatype' is needed for skin to display info for this ListItem correctly.
title_name = game['title_name']
list_item.setInfo('game', {'title': title_name,
'path': game['path'],
'mediatype': 'game'})
# Set graphics (thumbnail, fanart, banner, poster, landscape etc.) for the list item.
# Here we use the same image for all items for simplicity's sake.
# In a real-life plugin you need to set each image accordingly.
img_data = game['icon']
im = Image.open(io.BytesIO(base64.b64decode(img_data)))
img_name = title_name + '.png'
temp_folder = xbmcvfs.translatePath('special://temp')
img_dir = os.path.join(temp_folder, 'Ryujinx')
if not os.path.exists(img_dir):
os.makedirs(img_dir)
img_path = os.path.join(img_dir, img_name)
im.save(img_path)

list_item.setArt({'thumb': img_path, 'icon': img_path, 'fanart': img_path})
# Set 'IsPlayable' property to 'true'.
# This is mandatory for playable items!
list_item.setProperty('IsPlayable', 'true')
# Create a URL for a plugin recursive call.
url = get_url(action='play', game=game['path'])
# Add the list item to a virtual Kodi folder.
# is_folder = False means that this item won't open any sub-list.
is_folder = False
# Add our item to the Kodi virtual folder listing.
xbmcplugin.addDirectoryItem(_HANDLE, url, list_item, is_folder)
# Add a sort method for the virtual folder items (alphabetically, ignore articles)
xbmcplugin.addSortMethod(_HANDLE, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE)
# Finish creating a virtual folder.
xbmcplugin.endOfDirectory(_HANDLE)


def play_game(path):
"""
Play a game by the provided path.
:param path: Fully-qualified game path
:type path: str
"""
# Create a playable item with a path to play.
#play_item = xbmcgui.ListItem(path=path)
# Pass the item to the Kodi player.
#xbmcplugin.setResolvedUrl(_HANDLE, True, listitem=play_item)

env=os.environ.copy()
#Ignore wayland
if platform.system() == 'Linux':
env['GDK_BACKEND'] = 'x11'
#TODO: Run in same screen as kodi (for multimonitor config
#env['DISPLAY'] = ':0.1'

emulator_path = xbmcaddon.Addon().getSettingString('emulator_path')
command = [emulator_path, '--run-once', '-f', path, '--move', MONITOR_MODEL]
xbmc.log('------ {}'.format(command), xbmc.LOGINFO)
p = subprocess.Popen(command, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
#p.wait()
stdout, stderr = p.communicate()
xbmc.log('------ subprocess result {}'.format(stdout), xbmc.LOGINFO)
xbmc.log('------ subprocess result {}'.format(stderr), xbmc.LOGINFO)
#TODO: Listen to ESC or EXIT on kodi to kill process
#p.terminate()


def router(paramstring):
"""
Router function that calls other functions
depending on the provided paramstring
:param paramstring: URL encoded plugin paramstring
:type paramstring: str
"""

# Parse a URL-encoded paramstring to the dictionary of
# {<parameter>: <value>} elements
params = dict(parse_qsl(paramstring))
# Check the parameters passed to the plugin
if params and 'action' in params:
action = params['action']
if action == 'play':
# Play a game from a provided URL.
play_game(params['game'])
else:
# If the provided paramstring does not contain a supported action
# we raise an exception. This helps to catch coding errors,
# e.g. typos in action names.
raise ValueError('Invalid action: {}!'.format(action))
else:
# If the plugin is called from Kodi UI without any parameters,
# display the list of games
list_games()


if __name__ == '__main__':
# Call the router function and pass the plugin call parameters to it.
# We use string slicing to trim the leading '?' from the plugin call paramstring
xbmc.log('------ {}'.format(sys.argv), xbmc.LOGINFO)
paramstring = sys.argv[2][1:]
router(paramstring)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# plugin.program.ryujinx language file
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en\n"

msgctxt "#32000"
msgid "Paths"
msgstr ""

msgctxt "#32001"
msgid "Ryujinx path"
msgstr ""

msgctxt "#32002"
msgid "Game folder path"
msgstr ""

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# plugin.program.ryujinx language file
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en\n"

msgctxt "#32000"
msgid "Paths"
msgstr "Rutas"

msgctxt "#32001"
msgid "Ryujinx path"
msgstr "Ruta de Ryujinx"

msgctxt "#32002"
msgid "Game folder path"
msgstr "Ruta del directorio de juegos"

32 changes: 32 additions & 0 deletions plugin.program.ryujinx/resources/settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" ?>
<settings version="1">
<section id="plugin.program.ryujinx">
<category help="" id="general" label="32000">
<group id="1">
<setting help="" id="emulator_path" label="32001" type="path">
<level>0</level>
<default/>
<constraints>
<writable>false</writable>
<masking>executable</masking>
<allowempty>true</allowempty>
</constraints>
<control format="file" type="button">
<heading>32001</heading>
</control>
</setting>
<setting help="" id="game_dir_path" label="32002" type="path">
<level>0</level>
<default/>
<constraints>
<writable>false</writable>
<allowempty>true</allowempty>
</constraints>
<control format="path" type="button">
<heading>32002</heading>
</control>
</setting>
</group>
</category>
</section>
</settings>

0 comments on commit b015cf3

Please sign in to comment.