[HOW TO] Boxee app to XBMC
#1
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:
  • 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)
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:
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()
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:
  • ShowDialogWait
This is contructied with a minor difference, you have to pass the function to the close statement. Example:
Code:
wait = mc.ShowDialogWait()
#some code
mc.HideDialogWait(wait)
  • ActivateWindow
The activate window will directly open the window and any code after it will be executed after the new window is closed!!

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
If you want to set a global variable that is for example set in the oninit function and want to retreive it in for example the onaction function you can make a variable global by adding 'self.' as prefix. This also counts for costum functions. Example:
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>
Xbmc way:
Code:
<label></label>
<info>ListItem.Property(zender)</info>
  • List actions
When you what to execute code when the user reaches the end of a list in boxee you could just add the code to the <ondown></ondown> tags. But when you put this in the new situation, xbmc will call the function on every item, see the example below:
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!
Reply
#2
That's look pretty amazing! I will give it a try. Thanks!
Image
_____________________________

Repositories Installer: select and install unofficial repositories / TAC.TV: watch videos on TAC.TV
Installer Passion-XBMC: Download and Install Add-ons (pre-Dharma only)

Image
Reply
#3
I'm giving this a shot following your instructions. I did as much as the main.xml/.py to see if I could at lest get the main window to load. But the plugin fails with this error:

Code:
13:25:32 T:140682917713664 M:2629791744  NOTICE: -->Python Interpreter Initialized<--
13:25:34 T:140682917713664 M:2633211904   ERROR: Error Type: exceptions.AttributeError
13:25:34 T:140682917713664 M:2633211904   ERROR: Error Contents: 'module' object has no attribute 'start'
13:25:34 T:140682917713664 M:2633211904   ERROR: Traceback (most recent call last):
                                              File "/home/theophile/.xbmc/addons/plugin.video.template/default.py", line 19, in ?
                                                mc.start(id, windows)
                                            AttributeError: 'module' object has no attribute 'start'

I have no doubt I've made some mistakes, but this seems like it's an error with the mc module, right? If it makes a difference, the Boxee plugin I'm trying to port doesn't have a start.xml.
Reply
#4
Strange, it looks almost if the file structure setup is not correct. Did you downloaded the template.zip?

Also it does not matter what the start file is called. As long as it is the file boxee starts with (for boxee the window id to start is in the discriptor.xml)

In your case make sure default.py is setup as follow:
Code:
id = 'plugin.video.template'             #addon id as stated in
init = '14444'                          #skin window id to start on application launch
windows = { '14444' : 'main' }

Where 14444 refers the that particular window id. I also must note that I just noticed that in the template the comment for the windows dict is within the dict tags, might be wise to delete. I will upload a new version now.

Final note: I made this all on python 2.4 basis as boxee is.

Have a look at my repo, I just added 2 more simpel examples that I ported:
https://github.com/bartsidee/Bartsidee-R...aster/xbmc
Reply
#5
Yes, I started with your template. Matter of fact, here's what I have so far:

http://dl.dropbox.com/u/5130251/mlbtest.zip

I copied the .xml to .py in the appropriate location and started to redact all the xml, putting the python in the correct functions as per your instructions. I've only done "main" so far. I'm also gathering that I have to remove the python from the xml in the skin folder, right?

I hope my fumbling isn't beneath you. Sad
Reply
#6
You somehow had an outdated mc file. I included the latest one. Also to get you started I included 2 extra modules (month and simplejson) that are needed. I got a quick look at the code and corrected it for main.py, you should be aware that you only need to declare onclick/onfocus/onaction etc once. You can that stack the 'if controlid ==' functions.

Also delete all the python code from the skin file
Xbmc will still try to execute it, but will fail.

Further some code like "App.Reset" and "clearstatestack" has to do with window control and window stacks. Unfortunatly this is not supported. So you have to hope that without it it will work the way you want.

You can download the corrected version here:
http://www.2shared.com/file/yDv-bDnq/plu...plate.html

Good luck!
Reply
#7
Thanks, bartsidee. I made a lot a progress and sent you a PM.
Reply

Logout Mark Read Team Forum Stats Members Help
[HOW TO] Boxee app to XBMC0