2011-03-18, 13:03
I've made a module to emulate a boxee application on xbmc. To do this I constructed a mc module python module. Before I start I would like to note that there are some restrictions to this method:
I've made a template so that it is easy to get the new folder structure. You can download it here.
1. Copy your boxee skin files to:
2. If you have any python files/modules copy them to
3. Edit /plugin.video.template/addon.xml to your needs.
4. Edit /plugin.video.template/default.py to your needs.
5. Now becomes the difficult part. We need to split the python code from the skin xml files. To do this make a new .py file for every window file you have in '/plugin.video.template/resources/skin/Default/720p' and put it in /plugin.video.template/resources/libs/skin. An example you have a skin file called start.xml, this becomes start.py.
The new created skin .py files should be filled with the template code below:
I included the same code in /plugin.video.template/resources/libs/skin/template.py
We now have to delete the code out of the xml files (should be no python code left) and add them to the newly created skin .py files.
I will give some examples to make it clear how to proceed:
Example 1:
All the code in the onload section of the skin files can be put in the oninit function:
Becomes:
Example 2:
Code that is executed when you click on a button/list should be put in the onClick function:
Becomes:
Notice the 'if controlID == 100' command reffering to the control with id '100'
Example 3:
Code that is executed when you do a keyboard action should be put in the onAction function:
Becomes:
Notice the if statement 'if action.getId() == mc.ACTION_MOVE_DOWN and controlID == 101'. It refers to the id of the control and the action 'mc.ACTION_MOVE_DOWN'. You can find all the available actions in the end of the mc module file.
Things to keep in mind
This should provide you with the main functions you have in boxee. There are some minor differences with the mc module and boxee mc module that I should mention:
I allowed to pass variables to the new window if you for example want to fill a list. Example:
The varaiables can be retreived in the new window as
Usually in th skin file you determine a list item with:
Xbmc supports special info tags so you can write:
Also the custom property is called slightly different
Boxee way:
Xbmc way:
To prevent this and only execute the code after the last item in the list you can use the new function mc.ListEnd() and mc.Liststart() that gives true/false when you reached the end/start of a list. An example would look like this:
You can always find some reference files in my github repo:
Bartsidee Repo
And an updated mc module here
Tips and tricks:
- Prevent lists with id between [50-60], these are used by xbmc windowxml manager.
- Check your fonts and colors to correspond with the standard skin of xbmc
- remove any includes from the boxee skin from your skin.
- boxee window stacks are not supported (for now)
I used quite a lot of the mc module functions in my own app, so those are working, but some have not been tested. Meaning that there could be some minor bugs in it.
Good luck and I'm happy to answer any questions!
- No Flash Support
- No Rss support (at the moment)
- No support for Text Edit Control (and togglebutton setSelected)
I've made a template so that it is easy to get the new folder structure. You can download it here.
1. Copy your boxee skin files to:
Code:
/plugin.video.template/resources/skin/Default
2. If you have any python files/modules copy them to
Code:
/plugin.video.template/resources/libs/
3. Edit /plugin.video.template/addon.xml to your needs.
- Change the addon id (plugin.video.template)
- Change name/summery and discription
4. Edit /plugin.video.template/default.py to your needs.
- change 'id' to the addon id, same as you put in addons.xml
- change 'init' to th window id to start on application launch
- change 'windows', put here all the window id's with corresponding file name (so main.xml with id 14444, becomes {'14444' : 'main'})
5. Now becomes the difficult part. We need to split the python code from the skin xml files. To do this make a new .py file for every window file you have in '/plugin.video.template/resources/skin/Default/720p' and put it in /plugin.video.template/resources/libs/skin. An example you have a skin file called start.xml, this becomes start.py.
The new created skin .py files should be filled with the template code below:
Code:
import os, sys, mc
class skin(mc.Window):
#Leave this function as is it will initiate the window
def __init__(self, start, path, skin, var):
self.var = var
self.get = mc.Window.__init__(self, start, path, skin)
#The function resables the 'onload' section of boxee
#it will be executed on the window launch
def onInit(self):
mc.window = self
"""start your code"""
"""end your code"""
#This function should house the boxee code that should execute on keyboard actions
#For the boxee skin this could be an python action that was situated in <ondown><ondown> or <onup><onup>
#You can find all the keyboard shortcuts in the end of the mc file
def onAction(self, action):
controlID = self.getFocusId()
#makes sure the window closes when the user presses 'back'
if action.getId() in ( mc.ACTION_PARENT_DIR, mc.ACTION_PREVIOUS_MENU ):
self.close()
"""start your code"""
"""end your code"""
#This function will excute code when a control is clicked
#it passes the controls id as variable 'controlID'
#it would resemble th boxee code 'onclick'
def onClick(self, controlID):
"""start your code"""
"""end your code"""
#No equivilent in boxee code, but can execute code if a control is focussed
def onFocus(self, controlId):
"""start your code"""
"""end your code"""
I included the same code in /plugin.video.template/resources/libs/skin/template.py
We now have to delete the code out of the xml files (should be no python code left) and add them to the newly created skin .py files.
I will give some examples to make it clear how to proceed:
Example 1:
All the code in the onload section of the skin files can be put in the oninit function:
Code:
<onload lang="python">
<![CDATA[
import mc
from libs import main, ba
window = mc.GetWindow(14444)
config = mc.GetApp().GetLocalConfig()
main_obj = main.main_obj()
main_obj.Search_DB_Update(86400)
if window.GetControl(1200).IsVisible():
window.GetControl(1200).SetVisible(True)
window.GetControl(1300).SetVisible(False)
window.GetControl(1400).SetVisible(False)
]]>
</onload>
Becomes:
Code:
def onInit(self):
window = mc.GetWindow(14444)
config = mc.GetApp().GetLocalConfig()
main_obj = main.main_obj()
main_obj.Search_DB_Update(86400)
if window.GetControl(1200).IsVisible():
window.GetControl(1200).SetVisible(True)
window.GetControl(1300).SetVisible(False)
window.GetControl(1400).SetVisible(False)
Example 2:
Code that is executed when you click on a button/list should be put in the onClick function:
Code:
<control type="button" id="100">
<onclick lang="python">
<![CDATA[
window.GetLabel(10102).SetLabel('Example')
window.GetLabel(10103).SetLabel('Example2')
window.GetControl(1200).SetVisible(True)
window.GetControl(1300).SetVisible(False)
window.GetControl(1400).SetVisible(False)
]]>
</onclick>
Becomes:
Code:
def onClick(self, controlID):
window = mc.GetWindow(14444)
if controlID == 100:
window.GetLabel(10102).SetLabel('Example')
window.GetLabel(10103).SetLabel('Example2')
window.GetControl(1200).SetVisible(True)
window.GetControl(1300).SetVisible(False)
window.GetControl(1400).SetVisible(False)
Example 3:
Code that is executed when you do a keyboard action should be put in the onAction function:
Code:
<control type="button" id="101">
<ondown lang="python">
<![CDATA[
if window.GetControl(1200).IsVisible(): window.GetControl(1201).SetFocus()
if window.GetControl(1300).IsVisible(): window.GetControl(12).SetFocus()
if window.GetControl(1400).IsVisible(): window.GetControl(14).SetFocus()
]]>
</ondown>
</control>
Becomes:
Code:
def onAction(self, action):
window = mc.GetWindow(14444)
controlID = self.getFocusId()
if action.getId() == mc.ACTION_MOVE_DOWN and controlID == 101:
if window.GetControl(1200).IsVisible(): window.GetControl(1201).SetFocus()
if window.GetControl(1300).IsVisible(): window.GetControl(12).SetFocus()
if window.GetControl(1400).IsVisible(): window.GetControl(15).SetFocus()
Things to keep in mind
This should provide you with the main functions you have in boxee. There are some minor differences with the mc module and boxee mc module that I should mention:
- ShowDialogWait
Code:
wait = mc.ShowDialogWait()
#some code
mc.HideDialogWait(wait)
- ActivateWindow
I allowed to pass variables to the new window if you for example want to fill a list. Example:
Code:
mc.ActivateWindow(14446)
mc.ActivateWindow(14446, 'new list id')
mc.ActivateWindow(14446, ('a','b','c'))
The varaiables can be retreived in the new window as
Code:
self.var
- Global variables
Code:
def onInit(self):
self.main = 2
Code:
def onAction(self, action):
print self.main
# will print 2
- ListItem in xml
Usually in th skin file you determine a list item with:
Code:
<label>$INFO[ListItem.Thumb]</label>
Xbmc supports special info tags so you can write:
Code:
<label></label>
<info>ListItem.Thumb</info>
Also the custom property is called slightly different
Boxee way:
Code:
<label>$INFO[ListItem.property(costum:zender)]</label>
Code:
<label></label>
<info>ListItem.Property(zender)</info>
- List actions
Code:
def onAction(self, action):
window = mc.GetWindow(self)
controlID = self.getFocusId()
if action.getId() == mc.ACTION_MOVE_DOWN and controlID == 200:
To prevent this and only execute the code after the last item in the list you can use the new function mc.ListEnd() and mc.Liststart() that gives true/false when you reached the end/start of a list. An example would look like this:
Code:
def onAction(self, action):
window = mc.GetWindow(self)
controlID = self.getFocusId()
if action.getId() == mc.ACTION_MOVE_DOWN and controlID == 200 and mc.ListEnd(200):
You can always find some reference files in my github repo:
Bartsidee Repo
And an updated mc module here
Tips and tricks:
- Prevent lists with id between [50-60], these are used by xbmc windowxml manager.
- Check your fonts and colors to correspond with the standard skin of xbmc
- remove any includes from the boxee skin from your skin.
- boxee window stacks are not supported (for now)
I used quite a lot of the mc module functions in my own app, so those are working, but some have not been tested. Meaning that there could be some minor bugs in it.
Good luck and I'm happy to answer any questions!