Help for runscript in settings.xml
#1
Hello,
It's my first app for Kodi.
I have now a question, my addon have for the moment one file main.py and in this file i have a functon who is calle "showMessage", that it open a popup alert on kodi. At this point every thing is working, but i would like to run this function from the settings file.
So i have try this code 
xml:
<setting label="ShowPopu" type="action" action="RunScript(plugin.video.example,showMessage)"/>
But it dosen't work and after several hours of research i less find the solution. 
So i write this message. 
Thanks a lot for all your work and your help.
Sorry for my bad english, i'm french Wink
Reply
#2
(2022-03-22, 19:35)ronaldonizula Wrote: Hello,
It's my first app for Kodi.
I have now a question, my addon have for the moment one file main.py and in this file i have a functon who is calle "showMessage", that it open a popup alert on kodi. At this point every thing is working, but i would like to run this function from the settings file.
So i have try this code 
xml:
<setting label="ShowPopu" type="action" action="RunScript(plugin.video.example,showMessage)"/>
But it dosen't work and after several hours of research i less find the solution. 
So i write this message. 
Thanks a lot for all your work and your help.
Sorry for my bad english, i'm french Wink
I banged my head a bit on this too.  Here's what mine looks like:

    <setting id="getservers" type="action" label="30392" action="RunScript(plugin.video.mezzmo,servers)"/>

Do you have an extension point in your addon.xml file to catch this ?  Here's mine:

  <extension point="xbmc.python.library"
               library="resources/lib/utilities.py"/>

Then in utilities.py I have something which parses sys.argv to get the servers command:

if sys.argv[1] == 'count':                                        # Playcount modification cMost Recent
    playCount()
elif sys.argv[1] == 'auto':                                       # Set / Remove autostart
    autoStart()
elif sys.argv[1] == 'playm':                                      # Play music with bookmark
    playMusic()
elif sys.argv[1] == 'performance':                            # Display Performance stats
    displayMenu()
elif sys.argv[1] == 'servers':                                    # Display Sync servers
    displayServers()
elif sys.argv[1] == 'pictures':                                   # Display Pictures
    picDisplay()
elif sys.argv[1] == 'export':                                     # Export data
    selectExport()

If you want to see the full addon code look here.  Note this settings format is for Kodi 18. You can view the Kodi 19+ version of this at the same link, just select the Kodi 19+ version in GitHub.



Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#3
Thanks foryour answer ! 
I'm "happy" to see that i'm not alone lol
This is my addon.xml (take from the how to from KODI)
xml:
<?xml version="1.0" encoding="UTF-8"?>
<addon id="plugin.video.example"
version="2.4.0"
name="Example Kodi Video Plugin"
provider-name="Roman_V_M">
<requires>
  <import addon="xbmc.python" version="3.0.0"/>
</requires>
<extension point="xbmc.python.pluginsource" library="main.py">
  <provides>video</provides>
</extension>
<extension point="xbmc.addon.metadata">
  <summary lang="en">Example Kodi Video Plugin</summary>
  <description lang="en_GB">An example video plugin for Kodi mediacenter.</description>
  <disclaimer lang="en_GB">Free sample videos are provided by www.vidsplay.com.</disclaimer>
  <assets>
    <icon>icon.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>Updated with latest artwork metadata</news>
</extension>
</addon>

So i have an extension point. 
But i don't understand what happens next. What should I do in this basic example ?
Thanks a lot for your help !
Reply
#4
Ok so i have do like you tell me.
I have do in my main.py this : 
 
python:
if sys.argv [1] == 'show' :
showMessage()

And now it's working but it still show a error message :
Code:
2022-03-22 21:59:41.484 T:12892 ERROR <general>: EXCEPTION Thrown (PythonToCppException) : -->Python callback/script returned the following error<--
- NOTE: IGNORING THIS CAN LEAD TO MEMORY LEAKS!
Error Type: <class 'ValueError'>
Error Contents: invalid literal for int() with base 10: 'show'
Traceback (most recent call last):
File "C:\Users\Oni\AppData\Roaming\Kodi\addons\plugin.video.example\main.py", line 45, in <module>
_handle = int(sys.argv[1])
ValueError: invalid literal for int() with base 10: 'show'
-->End of Python script error report<--

Thanks you.
Reply
#5
Are you wanting to run your showMessage class or function when you click on the settings option you have defined ?  And do you want your addon to do anything else when it starts normally (i.e. not clicking on the setting) ?

If you look at my addon.xml file there are two extension points:

Normal startup

  <extension point="xbmc.python.pluginsource"
               library="default.py">
        <provides>video audio image</provides>
  </extension>

Runscript call from settings:

  <extension point="xbmc.python.library"
               library="resources/lib/utilities.py"/>

These execute differently.  The addon handle is passed as sys.argv1 (a numeric value) in the run normal code execution.  But when the settings calls the utilities.py script the script name is passed as sys.argv[0] and the first passed value is passed as sys.srgv[1].  There is no addon handle because it is run as a script and not an addon.  It looks like you are attempting to combine both modes into one Python file, which may not be possible. 

It would help to better understand how you want it to operate.


Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#6
Hello,
Thanks again for your help. 
That i would it to run a function from the setting pannel. It look like easy but i don't understand why it's not working. 
I have create another file in ressources/lib/teste.py where in put my function, but it's notworking yet. 
Always the same error (sorry if my questions are stupids) :

 
Code:
2022-03-23 08:50:49.618 T:14340 ERROR <general>: EXCEPTION Thrown (PythonToCppException) : -->Python callback/script returned the following error<--
- NOTE: IGNORING THIS CAN LEAD TO MEMORY LEAKS!
Error Type: <class 'ValueError'>
Error Contents: invalid literal for int() with base 10: 'show'
Traceback (most recent call last):
File "C:\Users\Oni\AppData\Roaming\Kodi\addons\plugin.video.example\main.py", line 16, in <module>
_handle = int(sys.argv[1])
ValueError: invalid literal for int() with base 10: 'show'
-->End of Python script error report<--

Thanks.
Reply
#7
It would be helpful if I could see how main.py is being called.  In this case the error is indicating that Python is trying to convert the string 'show' to an int, which won't evaluate properly, hence the error.  The issue isn't with your test.py file, at least from what I can see.  When is the above error occurring, when the addon starts or when you hit the settings button ?


Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#8
Hi,
The error is show only when i click on the setting button. 
This is my main.py (take from the HOW-TO):
py:

# Module: main
# Author: Roman V. M.
# Created on: 28.11.2014
# License: GPL v.3 https://www.gnu.org/copyleft/gpl.html
"""
Example video plugin that is compatible with Kodi 19.x "Matrix" and above
"""
import sys
from urllib.parse import urlencode, parse_qsl
import xbmcgui
import xbmcplugin
import xbmcvfs
import xbmcaddon
import os

def LoguerUpto():
        xbmc.executebuiltin('Notification(Hello World,This is a simple example of notifications,5000,/script.hellow.world.png)')

if sys.argv [1] == 'show' : # modification du nombre de lectures cMost Recent
    LoguerUpto()

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

# Free sample videos are provided by www.vidsplay.com
# Here we use a fixed set of properties simply for demonstrating purposes
# In a "real life" plugin you will need to get info and links to video files/streams
# from some web-site or online service.
VIDEOS = {'Animals': [{'name': 'Crab',
                       'thumb': 'http://www.vidsplay.com/wp-content/uploads/2017/04/crab-screenshot.jpg',
                       'video': 'https://www.appsloveworld.com/wp-content/uploads/2018/10/640.mp4',
                       'genre': 'Animals'},
                      {'name': 'Alligator',
                       'thumb': 'http://www.vidsplay.com/wp-content/uploads/2017/04/alligator-screenshot.jpg',
                       'video': 'https://www88.uptostream.com/stream/6q3snodb79/_m_main_0.mpd',
                       'genre': 'Animals'},
                      {'name': 'Turtle',
                       'thumb': 'http://www.vidsplay.com/wp-content/uploads/2017/04/turtle-screenshot.jpg',
                       'video': 'http://www.vidsplay.com/wp-content/uploads/2017/04/turtle.mp4',
                       'genre': 'Animals'}
                      ],
            'Cars': [{'name': 'Postal Truck',
                      'thumb': 'http://www.vidsplay.com/wp-content/uploads/2017/05/us_postal-screenshot.jpg',
                      'video': 'http://www.vidsplay.com/wp-content/uploads/2017/05/us_postal.mp4',
                      'genre': 'Cars'},
                     {'name': 'Traffic',
                      'thumb': 'http://www.vidsplay.com/wp-content/uploads/2017/05/traffic1-screenshot.jpg',
                      'video': 'http://www.vidsplay.com/wp-content/uploads/2017/05/traffic1.mp4',
                      'genre': 'Cars'},
                     {'name': 'Traffic Arrows',
                      'thumb': 'http://www.vidsplay.com/wp-content/uploads/2017/05/traffic_arrows-screenshot.jpg',
                      'video': 'http://www.vidsplay.com/wp-content/uploads/2017/05/traffic_arrows.mp4',
                      'genre': 'Cars'}
                     ],
            'Food': [{'name': 'Chicken',
                      'thumb': 'http://www.vidsplay.com/wp-content/uploads/2017/05/bbq_chicken-screenshot.jpg',
                      'video': 'http://www.vidsplay.com/wp-content/uploads/2017/05/bbqchicken.mp4',
                      'genre': 'Food'},
                     {'name': 'Hamburger',
                      'thumb': 'http://www.vidsplay.com/wp-content/uploads/2017/05/hamburger-screenshot.jpg',
                      'video': 'http://www.vidsplay.com/wp-content/uploads/2017/05/hamburger.mp4',
                      'genre': 'Food'},
                     {'name': 'Pizza',
                      'thumb': 'http://www.vidsplay.com/wp-content/uploads/2017/05/pizza-screenshot.jpg',
                      'video': 'http://www.vidsplay.com/wp-content/uploads/2017/05/pizza.mp4',
                      'genre': 'Food'}
                     ]}




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 '{0}?{1}'.format(_url, urlencode(kwargs))


def get_categories():
    """
    Get the list of video categories.

    Here you can insert some parsing code that retrieves
    the list of video categories (e.g. 'Movies', 'TV-shows', 'Documentaries' etc.)
    from some site or API.

    .. note:: Consider using `generator functions <https://wiki.python.org/moin/Generators>`_
        instead of returning lists.

    :return: The list of video categories
    :rtype: types.GeneratorType
    """
    return VIDEOS.keys()


def get_videos(category):
    """
    Get the list of videofiles/streams.

    Here you can insert some parsing code that retrieves
    the list of video streams in the given category from some site or API.

    .. note:: Consider using `generators functions <https://wiki.python.org/moin/Generators>`_
        instead of returning lists.

    :param category: Category name
    :type category: str
    :return: the list of videos in the category
    :rtype: list
    """
    return VIDEOS[category]


def list_categories():
    """
    Create the list of video categories in the Kodi interface.
    """
    # Set plugin category. It is displayed in some skins as the name
    # of the current section.
    xbmcplugin.setPluginCategory(_handle, 'My Video Collection')
    # Set plugin content. It allows Kodi to select appropriate views
    # for this type of content.
    xbmcplugin.setContent(_handle, 'videos')
    # Get video categories
    categories = get_categories()
    # Iterate through categories
    for category in categories:
        # Create a list item with a text label and a thumbnail image.
        list_item = xbmcgui.ListItem(label=category)
        # 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.
        list_item.setArt({'thumb': VIDEOS[category][0]['thumb'],
                          'icon': VIDEOS[category][0]['thumb'],
                          'fanart': VIDEOS[category][0]['thumb']})
        # Set additional info for the list item.
        # Here we use a category name for both properties for for simplicity's sake.
        # setInfo allows to set various information for an item.
        # For available properties see the following link:
        # https://codedocs.xyz/xbmc/xbmc/group__py...2888fb5f14
        # 'mediatype' is needed for a skin to display info for this ListItem correctly.
        list_item.setInfo('video', {'title': category,
                                    'genre': category,
                                    'mediatype': 'video'})
        # Create a URL for a plugin recursive call.
        # Example: plugin://plugin.video.example/?action=listing&category=Animals
        url = get_url(action='listing', category=category)
        # is_folder = True means that this item opens a sub-list of lower level items.
        is_folder = True
        # 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 list_videos(category):
    """
    Create the list of playable videos in the Kodi interface.

    :param category: Category name
    :type category: str
    """
    # Set plugin category. It is displayed in some skins as the name
    # of the current section.
    xbmcplugin.setPluginCategory(_handle, category)
    # Set plugin content. It allows Kodi to select appropriate views
    # for this type of content.
    xbmcplugin.setContent(_handle, 'videos')
    # Get the list of videos in the category.
    videos = get_videos(category)
    # Iterate through videos.
    for video in videos:
        # Create a list item with a text label and a thumbnail image.
        list_item = xbmcgui.ListItem(label=video['name'])
        # Set additional info for the list item.
        # 'mediatype' is needed for skin to display info for this ListItem correctly.
        list_item.setInfo('video', {'title': video['name'],
                                    'genre': video['genre'],
                                    'mediatype': 'video'})
        # 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.
        list_item.setArt({'thumb': video['thumb'], 'icon': video['thumb'], 'fanart': video['thumb']})
        # Set 'IsPlayable' property to 'true'.
        # This is mandatory for playable items!
        list_item.setProperty('IsPlayable', 'true')
        list_item.setProperty('inputstream','inputstream.adaptive')
        list_item.setProperty('inputstream.adaptive.manifest_type', 'mpd')
        # Create a URL for a plugin recursive call.
        # Example: plugin://plugin.video.example/?action=play&video=http://www.vidsplay.com/wp-content/uploads/2017/04/crab.mp4
        url = get_url(action='play', video=video['video'])
        # 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_video(path):
    """
    Play a video by the provided path.

    :param path: Fully-qualified video URL
    :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.
    #addonManager().enableAddon('inputstream.adaptive')
    #item.setProperty('inputstream.adaptive.manifest_type', 'mpd')
    
    xbmcplugin.setResolvedUrl(_handle, True, listitem=play_item)
    xbmc.log("COUCOU")
    #xbmcplugin.setResolvedUrl(_handle, True, listitem=play_item)


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:
        if params['action'] == 'listing':
            # Display the list of videos in a provided category.
            list_videos(params['category'])
        elif params['action'] == 'play':
            # Play a video from a provided URL.
            play_video(params['video'])
        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 paramstring: {0}!'.format(paramstring))
    else:
        # If the plugin is called from Kodi UI without any parameters,
        # display the list of video categories
        list_categories()


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
    router(sys.argv[2][1:])


Thks
Reply
#9
I'd move this section out of your main.py file and into your test.py tile:

def LoguerUpto():        

    xbmc.executebuiltin('Notification(Hello World,This is a simple example of notifications,5000,/script.hellow.world.png)')

if sys.argv [1] == 'show' : # modification du nombre de lectures cMost Recent    
    LoguerUpto()


What I'd suggest is try instrumenting sys.argv so you can see what is being passed.  I typically do something like at the top of my code, just after the import section:

For Kodi 18:

xbmc.log('Sysargv[0] is: ' + str(sys.argv[0]), xbmc.LOGNOTICE)
xbmc.log('Number of arguments: ' + str(len(sys.argv)), xbmc.LOGNOTICE)
xbmc.log('The arguments are: ' + str(sys.argv), xbmc.LOGNOTICE)

For Kodi 19:

xbmc.log('Sysargv[0] is: ' + str(sys.argv[0]), xbmc.LOGINFO)
xbmc.log('Number of arguments: ' + str(len(sys.argv)), xbmc.LOGINFO)
xbmc.log('The arguments are: ' + str(sys.argv), xbmc.LOGINFO)


This will help you see what is happening.


Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#10
Ok so,
I have move this line on ressources/lib/teste.py
Code:

def LoguerUpto():        

    xbmc.executebuiltin('Notification(Hello World,This is a simple example of notifications,5000,/script.hellow.world.png)')

if sys.argv [1] == 'show' : # modification du nombre de lectures cMost Recent    
    LoguerUpto()

Now the function is not working and the message error is yet here, and in the log file i see :
Code:
2022-03-23 12:08:27.024 T:14684    INFO <general>: Sysargv[0] is: main.py
2022-03-23 12:08:27.025 T:14684    INFO <general>: Number of arguments: 2
2022-03-23 12:08:27.025 T:14684    INFO <general>: The arguments are: ['main.py', 'show']

Thanks you
Reply
#11
(2022-03-23, 13:14)ronaldonizula Wrote: Ok so,
I have move this line on ressources/lib/teste.py
Code:

def LoguerUpto():        

    xbmc.executebuiltin('Notification(Hello World,This is a simple example of notifications,5000,/script.hellow.world.png)')

if sys.argv [1] == 'show' : # modification du nombre de lectures cMost Recent    
    LoguerUpto()

Now the function is not working and the message error is yet here, and in the log file i see :
Code:
2022-03-23 12:08:27.024 T:14684    INFO <general>: Sysargv[0] is: main.py
2022-03-23 12:08:27.025 T:14684    INFO <general>: Number of arguments: 2
2022-03-23 12:08:27.025 T:14684    INFO <general>: The arguments are: ['main.py', 'show']

Thanks you

Ok, so it looks like your main.py file is being called instead of ressources/lib/teste.py.  This is controlled in your addon.xml file.  Why don't you post your complete addon.xml file ?  You should have 2 extension point entries like:

  <extension point="xbmc.python.pluginsource"
               library="main.py">
        <provides>video</provides>
  </extension>

  <extension point="xbmc.python.library"
               library="resources/lib/teste.py"/>

Based upon the sys.argv output, I am guessing the second extension point is missing or formatted wrong.  I would add the same sys.argv logging commands to your teste.py file. 

Also the teste.py file doesn't need to be in resources/lib and can be in the same folder as your main.py file.  You would just change the extension point to:

  <extension point="xbmc.python.library"
               library="teste.py"/>

Mine is there due to the overall size and complexity of the addon.


Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#12
Hello, 
Thanks you for your help it seems  work now.
It was a bad format in my addon.xml
Thanks a lot for all your help and patience.
Reply
#13
(2022-03-24, 09:51)ronaldonizula Wrote: Hello, 
Thanks you for your help it seems  work now.
It was a bad format in my addon.xml
Thanks a lot for all your help and patience.

Glad it is working for you.  Like I said earlier,  I had very similar issues and head banging sessions to get it working for me.  


Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#14
Thanks, 
I have a new queston : I would like that my show function  be able to show what the user has entered in the text tag of the setting. (For example :
Code:
<setting label="Login : " type="text"   id="login" default=""/>
). The problem is that as long as the user has not left the configuration menu, the settings file is not updated on the disk, so the function "getSetting" is not be able to take the information. Would it be possible to force update the backup settings file before the user clicks ok and left the settings menu ?
Thanks again.
Reply
#15
(2022-03-24, 12:27)ronaldonizula Wrote: Thanks, 
I have a new queston : I would like that my show function  be able to show what the user has entered in the text tag of the setting. (For example :
Code:
<setting label="Login : " type="text"   id="login" default=""/>
). The problem is that as long as the user has not left the configuration menu, the settings file is not updated on the disk, so the function "getSetting" is not be able to take the information. Would it be possible to force update the backup settings file before the user clicks ok and left the settings menu ?
Thanks again.

I'll have to defer that one to the Kodi team on this question regarding the internals of how the setting functionality works.  I know there's been some discussion about updating the settings code and such.  If it was done outside of a setting with a keyboard GUI or similar then that would be easy.  I am not sure what the options are, if any, within a settings construct.


Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply

Logout Mark Read Team Forum Stats Members Help
Help for runscript in settings.xml0