Python's driving me bonkers !!!!!
#1
I spent most of the afternoon (well the commercial breaks in the IPL, which is pretty much the same thing) trying to work out why my code would not work. After testing all the complicated bits I finally worked out what was wrong.
To do a look up on a wesite I want to capture Artist,Song to add to the end of a url.
I create a variable to capture the tag for artist and one for song and create a third to join them with a comma. But it appears that using
Code:
variable + "," + variable
is a no-go in python.
So, for example if :
Night = a
Mare = b
then the following happens:
Nightmare = Night + Mare returns ab
Nightmare = Night + "+" + Mare returns a+b
Nightmare = Night + "," + Mare returns a

Other things I've tried:
In one of the incomprehensible discussions on stackflow they said use a join function but trying this doesn't seem to work with variables. I even tried adding the comma to the end of one of the variables (name = xbmc.Player().getMusicInfoTag().getArtist() +","), but again this gives a script error.

I'm at a loss as to what else to try - any suggestions?
Reply
#2
It's probably because one or more of your variables are not strings and Python isn't sure what you want to do. The best solution is probably a format string, which uses %s as a place holder and replaces them by position:
Code:
"Now is the %s for all good %s to come to the %s of their %s" %("time", "men", "aid", "country")

In your example:
Code:
artist = "Eminem"
title = "Space Bound"
output = "The song %s was written by the artist %s" %(song, artist)
Reply
#3
Thanks Bstrdmkr. Overcome that obstacle, now I've hit the next. Sorry to pester but the next problem I've encountered is that when I'm trying to render the image I've scraped I'm getting the following script error:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 4-5: ordinal not in range(128)

Reading a bit about it I think I've got to use some kind of encode or decode command from ASCII to UTF-8, but I'm not sure how, and whether that's something built into XBMC. Have you ever had that problem?
Deep down I know I'm getting somewhere as 2 days ago I couldn't print Hello World.
Reply
#4
The crash course version is that xbmc supports utf-8. Every page on the internet has an "encoding" that tells web browsers how the millions of possible characters are represented. You need to find the encoding in the headers and decode it to it's un-encoded state (referred to as unicode). Once you've got that, re-encode it to utf-8 before use. I use a get_url() function so that every page I pull from the internet is in utf-8 by the time I try to use it. This will get you started:
Code:
import urllib2

req = urllib2.urlopen('http://www.example.com')
encoding=req.headers['content-type'].split('charset=')[-1]
content = req.read()
ucontent = unicode(content, encoding)
usable_content = ucontent.encode('utf-8')

This is one everyone has to deal with at some point lol
Reply
#5
I'm beginning to think this is some kind of python initiation test. Sorry to keep asking noddy questions but if you are feeling school-teacherish then where I'm stuck is:
The code I've done so far is here. I'm sure it's very illiterate but I when I "print Base_URL" and copy the result from my log into a browser it gets the correct image. So, if I'm playing Die Fledermaus and paste the output of Base_URL to my browser it goes straight to this image.
Image

I can't work out how to then display the image in XBMC. The image is a regular PNG. I've checked the headers which say:

Code:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8

So, how do I get the image from Base_URL to a window in XBMC? I've kept trying to set things equal to WebHTML but it always says it can't be string or null. I'm stumped.
Reply
#6
I'm not at home right now, but check out my post here: http://forum.xbmc.org/showthread.php?tid=163388
You want the same thing, but controlImage instead of controlButton.

No worries about the questions, I'm always trying to get ppl addicted either here or At xbmcHub lol
Reply
#7
Thanks again. Works perfectly for opening a blank window - beginning to understand.

I think I've realised my schoolboy error about capturing the image. The examples from the wiki and forums I've been using to write my script were all based on the api returning HTML so using WebHTML or BeautifulSoup to parse info. The api I'm trying to link to returns JSON. In fairness Vladimir (the guy who wrote the api) put "wrapped in JSON" all over his links, but I was too much of a spanner to understand what that meant. So, I now need to go and learn how to parse JSON responses.

Late for work now, so probably will come back with questions about JSON this evening,

Thanks (smacking forehead as I go).
Reply
#8
Well., it's been a good-news/bad news kind of evening.

Good news - with your help I can now display the image in a window in XBMC. I found out that one of the problems was that the url I was trying to capture had '?' and '=' signs in it. I found a thread that said these created problems. So, I then found this thread where I learned from you and Ronie how to save the download to a temp file in addons-data and then open that image in the XBMC window. Success, euphoria.

Bad news - because the api is wrapped in JSON the method I was using to split the returned data to get the info I wanted didn't work. One erroneous comma and I'd get a "can't find" failure. So, I've tried to learn how to extract the data with JSON commands. Blimey charlie, there seem to be a billion suggestions of commands to use on google and I can't get any of them to work.

My last attempt is the closest. I put the code in:
Code:
json_data=open(WebHTML)
j = json.load('json_data')
print j['scoreID']
full draft code here.

However, when it fails my log says:
Error Contents: (2, 'No such file or directory', '{\n "kind": "volumes#volumes",\n "query": "Johann Strauss II RV 503 Di ......... etc, etc to the end of the api returned data.

So, that's where I'm stuck tonight. Would appreciate any words of wisdom.

BTW - writing this a bit like a blog as it may help others who have the same barking mad idea of trying to learn python from scratch and who like me are in The IT Crowd terms more Jen than Moss.
Reply
#9
JSON is pretty easy once you get the hang of it. I'd need to see your code to give an exact answer, but basically json is a list of combinations of lists and key: value pairs of arbitrary depth, represented as a string. The two methods you'll want to get familiar with are json.dumps() and json.loads(). Note the s in those. Dumps() takes a python dict and turns it into a string. loads() takes a string and turns it into a dict. If you're using a json api, feed the result of the web request to json.loads() and you should get a usable dictionary out of it
Reply
#10
Sorted with some help from the stackoverflow guys. Amended code to:

Code:
scoreId = json.loads(WebHTML)
scoreId['items'][0]['scoreId']
print scoreId['items'][0]['scoreId']

and that now pulls out the correct item from my downloaded JSON list.
Reply
#11
Hi Bstrdsmkr (and anyone else who may be reading)

I'm afraid this is another picture heavy post - but they tell 1,000 words, blah, blah (or is it foo, foo in python).

So, in my home-made junior python class I've got to the stage where:
- script recognises what music is playing and extracts tag info
- it calls the api to find the appropriate image file and saves it to a temp file in addon_data
- I've now worked out how to get the script to load a new window (I created one called script-score.xml)

Now, when I'm playing a piece and I run the script from the Programs menu I get this (no photoshopping involved):
Image

I then created a new little icon in MusicOSD.xml (it's the one with the little semi-quaver icon):

Image

I added the following code to get it to point to my script.

Code:
            <control type="togglebutton" id="1001">
                <posx>0</posx>
                <posy>0</posy>
                <width>55</width>
                <height>55</height>
                <label>Score</label>
                <font>-</font>
                <texturefocus>special://home/addons/script.scores/Resources/OSDscoreFO.png</texturefocus>
                <texturenofocus>special://home/addons/script.scores/Resources/OSDscoreNF.png</texturenofocus>
                <onleft>607</onleft>
                <onright>500</onright>
                <onup>1000</onup>
                <ondown>1000</ondown>
                <onclick>Close</onclick>
                <onclick>XBMC.RunScript(special://home/userdata/addon_data/script.scores)</onclick>
            </control>

However, when I click on the little icon I get a script error as follows:
Quote:IOError: (13, 'Permission denied', 'C:\\Users\\Paul\\AppData\\Roaming\\XBMC\\userdata\\addon_data\\script.scores')

I think the permissions are all ok on my home folder, and I don't understand if it was a read/write problem why it would work when running the script directly but not when called from the .xml page. So, finally my question:
Do you know what's up with this?

N.B. - The page up and down buttons don't do anything right now. That's the next part of my learning curve - trying to execute the commands to move the script on a page. I can get the total number of pages from the api, I need to work out how to execute a command to + or - the page number and re-do the image call. I think the last big thing I then need to work out is how to get it to recognise a change in track so it will work on playlist rather than just from track select.

N.B.2 - I thought about a slideshow approach but that wouldn't work for repeat sections or codas so I think big buttons you can quickly hit works better. It can't be perfect because of the arrangement the conductor may have used in the recording you have, but this is for now just an exercise in learning python and coding for me.
Reply
#12
I'm not certain about this, because I mainly do plugins vs scripts, but I think XBMC.RunScript() needs the full path to the .py file like:
Code:
<onclick>XBMC.RunScript(special://home/userdata/addon_data/script.scores/default.py)</onclick>

When you're ready to change images, just call the ContolImage's setImage() method with the url for the new image: http://mirrors.xbmc.org/docs/python-docs...ntrolImage

To react to key presses, use the windows onAction() property: http://mirrors.xbmc.org/docs/python-docs...w-onAction
It receives an int (mapped to constants) which indicates what button was pressed or action occurred. A series of if statements will let you react appropriately. The docs are a little confusing on what you can react to, so take a look at this section of xbmc's source code to see a list of actions: https://github.com/xbmc/xbmc/blob/master...slator.cpp

I don't know how much information the the api provides, but if you know the timing and the number of bars per pages and etc, you should be able to calculate which image contains the appropriate bar based on the current playback time.
Reply
#13
Thanks, got it working. Idiotically in earlier post I had put path to addon_data rather than addons. (Note to self - must not code after bedtime). I found it works if you just put RunScript (addon name), presumably it's clever enough to check the installed scripts' addon.xmls.

Thanks for the info, I am struggling to understand the passing of info back to the scipt from the gui so hopefully your links will help.

For anyone else learning python from scratch and with no other programming experience I found this website really helpful and a lot easier to follow than the python docs tutorial - which I think presumes a bit of programming experience and intelligence. And it has video, which is good for those like me who avoid instruction manuals like the plague.
Reply
#14
to get info from the gui you need to do (as a rough example):

Code:
gui = MyDialogClass("xmlfile.xml", __addon__.getAddonInfo('path'))
gui.doModal()
#the code stops here until the gui is closed. So any variables set while the dialog is active can be retrieved after its closed.
if gui.my_variable == "foo"
    #if var was set while dialog active (button click?) do stuff.
    pass
del gui

a proper example can be found at: https://github.com/rectifyer/script.trak...ing.py#L93 and https://github.com/rectifyer/script.trak...ng.py#L166

if you look at that file, it pops up a rating dialog then waits for the user to press a button (rating). It sets the onClick variable then we can figure out what to do from there.
Image
Reply
#15
Thanks N3MIS15, that's really helpful. Amazing what you learn browsing other people's scripts. Having said that I'd better check if what I've learnt is correct.

Firstly, I think I should change the order of calling. Previously I had: click button in MusicOSD opens CustomWindow.xml which calls the output of my script (i.e the image file). Therefore there's no way of updating it. If I change the order to click button in MusicOSD calls the script which delivers GUI to the CustomWindow.xml, then I can use the subsequent 'GUI - if' statements you show in your example.

Secondly, a spincontrol won't work. If I've understood correctly in a script like Lyrics the whole text is downloaded to one file (or stored in a single variable). They can add a spincontrol to the window.xml because it just looks at the size of the text and determines how many pages it wil take to present. Because I'm calling individual images (score page 1, score page 2, etc) a spincontrol won't do anything because it's not opening a different file. Spincontrol also won't work with a 'Gui – if' function as you describe because it only sends one response (if it's been hit). So, I need to change from spincontrol to two separate buttons, one notifying a 'page-down' event and the other a 'page-up' event. I can then + or – the page number variable to call the new image accordingly.

Hopefully, I've understood correctly, in which case I've got my May Day bank holiday homework. Although I may spend a few days checking out Trakt as I'm tired of sneakily changing the .nfo IMDB ratings of all the Richard Curtis and Woody Allen romcoms so 'she' can't find them on a Friday evening.

Ripper!!
Reply

Logout Mark Read Team Forum Stats Members Help
Python's driving me bonkers !!!!!0