Plugin configuration¶
Contents:
XDM provides a framework to store basic configuration and display there form fields on the settings page.
There are three types of plugins config “scopes”:
type/scope | access | defined in | meta defined in |
---|---|---|---|
normal | self.c |
_config | config_meta |
hidden | self.hc |
_hidden_config | hidden_config_meta |
element | self.e |
_config | config_meta |
Example¶
To create settings simply fill the _config attribute of your plugin class:
from xdm.plugins import *
class Printer(Notifier):
_config = {'add_message': 'my print plugin'}
# add_message: same key as in _config
config_meta = {'add_message': {'human': 'Additional text', # a more human friendly name
'desc': 'This text will be added after every printed message'}}
# the description will be a tooltip on the input field
def sendMessage(msg, element=None)
userAddition = self.c.add_message
print msg + userAddition
return True
By default settings are ordered alphabetically by name if you want to have a specific order
use an OrderedDict
from collections import OrderedDict
_config = OrderedDict([
('defaut_mt_select', ''),
('login_user', ''),
('login_password', ''),
('port', 8085)
])
Setting value types and resulting form fields¶
Values can be one of the the following type
type | Settings page field |
---|---|
str | Text input field |
bool | Checkbox |
int / float | Number input field |
Note
Only these type are allowed as config values!
Additionally if the following strings are found in the the config name additional modification are made to the input field
string | modification |
---|---|
path | Adds a folder browser |
filepath | Adds a file browser |
password | Makes the input field an obfuscated password input field |
Interaction between settings page and plugin¶
You can also interact from the settings page with your plugin.
- You can add generic buttons.
- You listen on events of the form fields.
- You can get the data from the config fields.
- You can send data back
- You can invoke custom javascript functions with your send data. See getConfigHtml
- You can trigger global actions
These are defined in the config_meta
dict:
Buttons¶
To define single action buttons use the plugin_buttons key this holds another dict with button definitions
Button example:
config_meta = {'plugin_buttons': {'testConnection': {'action': _testConnection,
'name': 'Test Connection',
'desc': 'Test the connection with credentials'}
}
}
This will create a button on the settings page with the text “Test Connection” on it and a greyed out text “Test the connection with credentials” behind it.
When clicked it will call the function _testConnection
Note
Since the “action” is a real python reference the config_meta should be at the end your your plugin class.
Events¶
To add “actions” to changes that are made with the input field (text is changed and focus is lost) you set the “on_live_change” tot the function you want to call
Event example:
config_meta = {'plugin_desc': 'Sabnzb downloader. Send Nzbs and check for status',
'plugin_buttons': {'test_connection': {'action': _testConnection, 'name': 'Test connection'}},
'host': {'on_live_change': _testConnection},
'port': {'on_live_change': _testConnection},
'apikey': {'on_live_change': _testConnection}
}
Now the function _testConnection called when either the field host, port or apikey is changed, or when the test_connection button is clicked
The functions¶
The functions that are called should always return a tuple of the following schema:
t = (bool, dict, str)
return t
# t[0] is the overal result status
# t[1] is data you want to send / it is converted into json
# t[2] is a human readable message
and to get data from the config page add a list named args with names of the config fields you want to the function (yes add it as an attribute to the function(object))
_config = {'host': 'http://nzbs2go.com',
'apikey': '',
'port': None,
'enabled': True,
'comment_on_download': False,
'retention': 900,
'verify_ssl_certificate': True
}
def _gatherCategories(self, host, port, verify_ssl_certificate):
return (True, {}, 'I found 3 categories')
_gatherCategories.args = ['host', 'port', 'verify_ssl_certificate'] # <- this is what i mean
Use the data in javascript¶
To make use of data in javascript / your function
you modify the data-dict (t[1]
) has to in the folowing structure:
dataWrapper = {'callFunction': 'javascript_function_name',
'functionData': data}
Note
since all plugins can have multiple instances the functions should be namespaced with the current instance name. See following example
Full example:
class Newznab(Indexer):
identifier = "de.lad1337.newznab"
_config = {'host': 'http://nzbs2go.com',
'apikey': '',
'port': None,
'enabled': True,
'comment_on_download': False,
'retention': 900,
'verify_ssl_certificate': True
}
def _gatherCategories(self, host, port, verify_ssl_certificate):
# some magic that does stuff
data = dict()
dataWrapper = {'callFunction': 'newsznab_' + self.instance + '_spreadCategories', # use the "namespaced" name
'functionData': data}
return (True, dataWrapper, 'I found %s categories' % len(data))
_gatherCategories.args = ['host', 'port', 'verify_ssl_certificate']
def getConfigHtml(self):
return """<script>
function newsznab_""" + self.instance + """_spreadCategories(data){ """ # this gives the function a "namespace"
"""console.log(data);
$.each(data, function(k,i){
$('#""" + helper.idSafe(self.name) + """ input[name$="'+k+'"]').val(i)
});
};
</script>
"""
config_meta = {'plugin_desc': 'Generic Newznab indexer. Categories are there numerical id of Newznab, use "Get categories"',
'plugin_buttons': {'gather_gategories': {'action': _gatherCategories, 'name': 'Get categories'},
'test_connection': {'action': _testConnection, 'name': 'Test connection'}},
}