I'm having trouble with seemingly random chrashes of this script i'm making... The weird thing is that these chrases only occurs when i'm running the script on the xbox not when i'm running it on the emulator by alexpoet.
Another thing i'm trying is to use a ControlTextBox for displaying progess information (see the OpenUrl function). But it does not work ... It seems to me that the gui is not being updated while the script is running. Is there anyway of forcing a redraw of the screen?
Note if you try out the code you'll need to copy lyricspanel.png to the same folder as this script and create a cache subfolder also. Note this is my first python script ever so excuse any weirdness, but feel free to give advice :-).
# ScriptName : ooba.py (Browse using RegExp's, couldn't think of a good name)
# Version : 0.1 beta
# Author : Van der Phunck aka Aslak Grinsted.
[email protected] <- not cmo but com
# Desc : flexible browser for streams,images and rawtext.
#
# Based on many scripts but primarily GameSpotPlus & XBMCLyrics.
#
#
# My ambition with this script is that you can give it a list of urls and tell it
# what it should do with "that kind of url".
#
# E.g. mp3,pls&avi files should be played, jpg should be shown and
# http://www.bbc.co.uk/radio/aod/index_choose.shtml should result in a sub menu.
#
#
#
#
#
#
# Version 0.1 beta
# Initial Release
import urllib, re, random, os.path, time, stat, string
import xbmc, xbmcgui
import htmlentitydefs,socket,Image,ImageFile
ACTION_MOVE_LEFT = 1
ACTION_MOVE_RIGHT = 2
ACTION_MOVE_UP = 3
ACTION_MOVE_DOWN = 4
ACTION_PAGE_UP = 5
ACTION_PAGE_DOWN = 6
ACTION_SELECT_ITEM = 7
ACTION_HIGHLIGHT_ITEM = 8
ACTION_PARENT_DIR = 9
ACTION_PREVIOUS_MENU = 10
ACTION_SHOW_INFO = 11
ACTION_PAUSE = 12
ACTION_STOP = 13
ACTION_NEXT_ITEM = 14
ACTION_PREV_ITEM = 15
ScriptPath = os.getcwd()
if ScriptPath[-1]==';': ScriptPath=ScriptPath[0:-1]
if ScriptPath[-1]!='\\': ScriptPath=ScriptPath+'\\'
timeout=10.0 #socket timeout
try: Emulating = xbmcgui.Emulating #Thanks alot to alexpoet for the xbmc.py,xmbcgui.py emulator. Very useful!
except: Emulating = False
#######################
# FUNCTIONS #
#######################
entpat=re.compile("&#?([\w\d]+);", re.IGNORECASE)
#----------viewstates-------------
MENUSTATE=1
IMAGESTATE=2
TEXTSTATE=3
def HTMLDecode(name): #make titles look nicer in menu
nameout=''
name=string.replace(name,' ',' ') #nbsp looks ugly
lastidx=0
for match in entpat.finditer(name):
try:
ent=unichr(int(match.group(1)))
except:
try:
ent=unichr(htmlentitydefs.name2codepoint[match.group(1)])
except: ent='?'
nameout=nameout+name[lastidx:match.start()]+ent.encode('iso-8859-1')
lastidx=match.end()
nameout=nameout+name[lastidx:]
return nameout
##############################
def Play(url):
lowurl=string.lower(url)
if string.find(lowurl, '.asx')!=-1 or string.find(lowurl, 'www.dr.dk')!= -1:
data=OpenUrl(url)
rg = re.compile("
[]*href=[\"']([^\"'<>]*)", re.IGNORECASE)]
result = rg.findall(data)
n = len(result)
if n>0: url=result[0]
elif string.find(lowurl, '.rpm')==-1:
data=OpenUrl(url)
url=data
print("Playing:"+url)
xbmc.Player().play(url)
##############################
##############################
urlContext=['no context yet!'] #<- this is the url relative urls are evaluated against....
#it is in a list so that i can write to it. Stupid scope rules in python.. global did not help?
urlSplitter=re.compile('^([^/]*?//[^/]*)/[^#\?]*/?')
def GetFullUrl(url): #set urlContext before calling if it is a relative url
if string.find(url,'://')==-1: #then use urlContext
m=urlSplitter.match(urlContext[0])
if url[0]=='/':
url=m.group(1)+url
else:
url=m.group(0)+url
return url
def OpenUrl(url): #set urlContext before calling if it is a relative url
#progress = xbmcgui.DialogProgress()
#progress.create("Reading URL", url)
win.ShowText("Reading URL\n"+url)
url = GetFullUrl(url)
if Emulating: print("Opening URL:"+url)
try:
oldtimeout=socket.getdefaulttimeout()
socket.setdefaulttimeout(timeout)
f = urllib.urlopen(url)
urlContext[0]=f.geturl() #get the new url context
data = f.read()
f.close()
socket.setdefaulttimeout(oldtimeout)
except:
win.set_viewstate(MENUSTATE)
raise
#progress.close()
win.set_viewstate(MENUSTATE)
return data
extre=re.compile('\W?(jpg|jpeg|gif|png)\W?',re.IGNORECASE) #be very liberal with where extension is ... you never know with urls.
def getExtension(url):
result=extre.findall(url)
if len(result)>0:
result=string.lower(result[-1]) #prioritize the last match
if result=='jpeg': result='jpg'
return result
else:
return ''
def message(line1,line2='',line3=''):
dialog = xbmcgui.Dialog()
dialog.ok("Info", line1,line2,line3)
######################## ACTIONS
class ActionBase:
def open(self,url):
pass
return None
class SubMenuAction(ActionBase):
def __init__(self,repattern,titleidx,urlidx,linkprefix):
self.urlidx=urlidx
self.titleidx=titleidx
self.repattern=repattern
self.linkprefix=linkprefix
def open(self,url):
#TODO: get url contents, parse and return submenu
submenu=Menu()
data=OpenUrl(url)
submenu.set_url(urlContext[0])
x = re.compile(self.repattern, re.DOTALL|re.IGNORECASE)
result = x.findall(data)
n = len(result)
if n==0:
win.ShowText('No links in url: '+url+'\n\n'+str(data))
message('no links?')
return None
i = 0
for i in range(0,n):
try:
iurl=self.linkprefix % result[self.urlidx]
ititle=HTMLDecode(result[self.titleidx])
item=MenuItem(ititle, iurl)
submenu.append(item)
except:
#ignore all errors in parsing a page.... TODO:log something.
pass
return submenu
class PlayAction(ActionBase):
def open(self,url):
url=GetFullUrl(url)
Play(url)
return None #no sub menu
class ViewImageAction(ActionBase):
def open(self,url):
url=GetFullUrl(url)
print('Opening image:'+url)
win.ShowImage(url)
return None #no sub menu
class ViewTextAction(ActionBase):
def open(self,url):
url=GetFullUrl(url)
print('Opening text:'+url)
data=OpenUrl(url)
win.ShowText(data)
return None #no sub menu
class ActionList: #ties regexp patterns to desired actions....
def __init__(self):
self.items=[]
self.index=0
def append(self,urlpattern,action):
self.items.append([re.compile(urlpattern),action])
def open(self,url):
for i in range(0,len(self.items)):
item=self.items
if not(item[0].search(url) is None):
return item[1].open(url)
message('No actions found for url:',url)
print('No actions found for url:'+url)
return None
########################
class MenuItem: #for the mainmenu
def __init__(self, title, url):
self.url=url
self.title=title
def get_url(self): return self.url
def get_title(self): return self.title
class Menu:
def __init__(self,title="",url=""):
self.items=[]
self.index=0
self.title=title
self.url=url
def get_title(self): return self.title
def set_title(self,title): self.title=title
def get_url(self): return self.url #used as the urlContext for menuitems
def set_url(self,url): self.url=url
def append(self,item):
self.items.append(item)
def pop(self):
return self.items.pop()
def count(self):
return len(self.items)
def __iter__(self):
return self
def next(self):
if self.index >= len(self.items):
raise StopIteration
self.index = self.index + 1
return self.items[self.index-1]
def item(self,idx):
return self.items[idx]
################################################################################
####
################################################################################
####
################################################################################
####
################################################################################
####
class MainWin(xbmcgui.WindowDialog):
def __init__(self):
self.viewstate=MENUSTATE
if Emulating: xbmcgui.Window.__init__(self) #for emulator to work
self.menustack=[]
self.menustack.append(mainmenu)
#---------- SetUpControls ------------
self.player = xbmc.Player()
#PAL/NTSC Support - thanks to solexalex:
w=self.getWidth()
h=self.getHeight()
#Ratio - using PAL for reference:
self.xratio=float(w/720.0)
self.yratio=float(h/576.0)
self.panel = xbmcgui.ControlImage(int(self.xratio*140),int(self.yratio*25),int(self.xratio*580),int(self.yratio*500), ScriptPath+'lyricspanel.png')
self.addControl(self.panel)
self.title = xbmcgui.ControlFadeLabel(int(self.xratio*270),int(self.yratio*95),int(self.xratio*255),int(self.yratio*25), 'font14','0xFFFFFFFF')
self.addControl(self.title)
self.list = xbmcgui.ControlList(int(self.xratio*190),int(self.yratio*130),int(self.xratio*430),int(self.yratio*345))
self.addControl(self.list)
self.textbox = xbmcgui.ControlTextBox(int(self.xratio*190),int(self.yratio*130),int(self.xratio*430),int(self.yratio*345), 'font14', '0xFFFFFFFF')
self.image = None
self.updateMenu()
def get_viewstate(self):
return self.viewstate
def set_viewstate(self,state):
# xbmcgui.lock()
state2control={MENUSTATE:self.list,IMAGESTATE:self.image,TEXTSTATE:self.textbox}
control=state2control[state]
if self.viewstate==state:
self.setFocus(control)
return
try:
self.removeControl(state2control[self.viewstate])
except:
pass
self.viewstate=state
self.addControl(control)
if state==MENUSTATE:
self.updateMenu()
self.setFocus(control)
# xbmcgui.unlock()
def updateMenu(self):
if not (self.viewstate==MENUSTATE): return
menu=self.menustack[len(self.menustack)-1]
self.title.reset()
self.title.addLabel(menu.get_title())
self.list.reset()
for i in range(0,menu.count()):
item=menu.item(i)
self.list.addItem(item.get_title())
self.setFocus(self.list)
def ShowText(self,txt):
self.textbox.reset()
self.textbox.setText(txt)
self.set_viewstate(TEXTSTATE)
def ShowImage(self,url):
ext=getExtension(url);
localfile=ScriptPath+'cache\\imgtemp.'+ext
oldtimeout=socket.getdefaulttimeout()
socket.setdefaulttimeout(timeout)
loc = urllib.URLopener()
loc.retrieve(url, localfile)
socket.setdefaulttimeout(oldtimeout)
#-------------Resize Image-------------
im = Image.open(localfile)
scalex=float(self.getWidth())/float(im.size[0])
scaley=float(self.getHeight())/float(im.size[1])
if scalex>scaley: scalex=scaley #keep aspect ratio
if scaley>scalex: scaley=scalex
PicSize = (int(float(im.size[0])*scalex), int(float(im.size[1])*scaley))
if scalex<1:
im.thumbnail(PicSize, Image.ANTIALIAS)
localfile=ScriptPath+'cache\\imgtemp.png' #best choice for unknown graphics.
im.save(localfile)
PicSize=(im.size[0],im.size[1])
elif scalex<1.1:
PicSize = (im.size[0], im.size[1]) #dont stretch original size...
#-------------Display the image--------
self.image = xbmcgui.ControlImage((self.getWidth()-PicSize[0])/2, (self.getHeight()-PicSize[1])/2, PicSize[0], PicSize[1], localfile)
self.set_viewstate(IMAGESTATE)
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.close()
return
# try:
if self.viewstate==MENUSTATE:
if action == ACTION_SELECT_ITEM:
menu=self.menustack[len(self.menustack)-1]
item=menu.item(self.list.getSelectedPosition())
urlContext[0]=menu.get_url()
submenu=actions.open(GetFullUrl(item.get_url()))
if (not (submenu is None)):
if submenu.get_title() == '':
submenu.set_title(item.get_title())
self.menustack.append(submenu)
self.updateMenu()
if action == ACTION_PARENT_DIR:
self.menustack.pop()
if len(self.menustack)==0:
self.close()
return
self.updateMenu()
return
if self.viewstate==IMAGESTATE:
if action == ACTION_PARENT_DIR:
self.set_viewstate(MENUSTATE)
return
if self.viewstate==TEXTSTATE:
if (action == ACTION_PARENT_DIR) or (action == ACTION_SELECT_ITEM):
self.set_viewstate(MENUSTATE)
return
# except:
# message('Error?')
# self.close()
##############################
mainmenu=Menu('Choose thy destiny')
actions=ActionList();
actions.append('\.asx$', PlayAction())
actions.append('\.mp3$', PlayAction())
actions.append('\.wmv$', PlayAction())
actions.append('^mms:' , PlayAction())
actions.append('^rtsp:', PlayAction())
actions.append('\.rpm$', PlayAction())
actions.append('\.txt$', ViewTextAction())
actions.append('\W?(jpg|jpeg|gif|png)\W?', ViewImageAction())
mainmenu.items.append(MenuItem('comics.com', 'http://www.comics.com/categories/index.html'))
actions.append('www.comics.com/categories/index.html', \
SubMenuAction('