"""
Update module
Nuka1195
"""
# main imports
import sys
import os
import xbmc
import xbmcgui
import xbmcplugin
import urllib
import re
from xml.sax.saxutils import unescape
from xbmcplugin_lib import *
__plugin__ = sys.modules["__main__"].__plugin__
__date__ = '15-10-2009'
log("Module: %s Dated: %s loaded!" % (__name__, __date__))
class Parser:
""" Parser Class: grabs all tag versions and urls """
# regexpressions
revision_regex = re.compile( '
.+?Revision ([0-9]*): ([^<]*)
' )
asset_regex = re.compile( '([^"]*)' )
def __init__( self, htmlSource ):
# set our initial status
self.dict = { "status": "fail", "revision": 0, "assets": [], "url": "" }
# fetch revision number
self._fetch_revision( htmlSource )
# if we were successful, fetch assets
if ( self.dict[ "revision" ] != 0 ):
self._fetch_assets( htmlSource )
def _fetch_revision( self, htmlSource ):
try:
# parse revision and current dir level
revision, url = self.revision_regex.findall( htmlSource )[ 0 ]
# we succeeded :), set our info
self.dict[ "url" ] = url
self.dict[ "revision" ] = int( revision )
except:
pass
def _fetch_assets( self, htmlSource ):
try:
assets = self.asset_regex.findall( htmlSource )
if ( len( assets ) ):
for asset in assets:
if ( asset[ 0 ] != "../" ):
self.dict[ "assets" ] += [ unescape( asset[ 0 ] ) ]
self.dict[ "status" ] = "ok"
except:
pass
class Main:
def __init__( self ):
log( "%s started!" % self.__class__ )
self.dialog = xbmcgui.DialogProgress()
if "update_all" in sys.argv[ 2 ]:
self.update_all()
else:
# parse sys.argv for our current url
self._parse_argv()
# get the repository info
self._get_repo_info()
self._create_title()
# get the list
self._download_item( forceInstall=True )
def _get_repo_info( self ):
# path to info file
# repopath = os.path.join( os.getcwd(), "resources", "repositories", self.args.repo, "repo.xml" )
repopath = os.path.join( HOME_DIR, "resources", "repositories", self.args.repo, "repo.xml" )
try:
# read file
info = readFile( repopath )
# repo's base url
self.REPO_URL = re.findall( '([^<]+)', info )[ 0 ]
log("_get_repo_info() repo_url=%s" % self.REPO_URL)
except:
# oops print error message
print "ERROR: %s::%s (%d) - %s" % ( self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
def _parse_argv( self ):
# call _Info() with our formatted argv to create the self.args object
exec "self.args = Info(%s)" % ( sys.argv[ 2 ][ 1 : ].replace( "&", ", " ), )
self.args.download_url = urllib.unquote_plus( self.args.download_url )
self.args.repo = urllib.unquote_plus( self.args.repo )
def _create_title( self ):
# create the script/plugin/skin title
parts = self.args.download_url.split( "/" )
version = ""
if ( self.args.voffset != 0 ):
version = " - %s" % ( parts[ self.args.voffset ].replace( "%20", " " ) )
del parts[ self.args.voffset ]
self.title = parts[ -2 ].replace( "%20", " " ) + version
log("_create_title() %s" % self.title)
def update_all( self ):
log("> _update_all()")
""" Download and install all new Addons as stored in update file """
# eg 'download_url="%2Ftrunk%2Fplugins%2Fmusic/iTunes%2F"&repo=\'xbmc-addons\'&install=""&ioffset=2&voffset=0'
# fn = os.path.join( os.getcwd(), "update_all.dat" )
fn = os.path.join( HOME_DIR, "update_all.dat" )
items = loadFileObj(fn)
if items:
if xbmcgui.Dialog().yesno( __plugin__, xbmc.getLocalizedString( 30019 ) + " ?", "", "", xbmc.getLocalizedString( 30020 ), xbmc.getLocalizedString( 30021 ) ):
# enumerate throu item to download & install
sz = len(items)
for url_args in items:
log("_update_all() updating: %s" % url_args)
# load item args
sys.argv[ 2 ] = url_args
# parse sys.argv for our current url
self._parse_argv()
# get the repository info
self._get_repo_info()
# create title
self._create_title()
# download & install
self._download_item( forceInstall=True )
self.dialog.close()
# force list refresh
# xbmc.executebuiltin('Container.Refresh')
else:
xbmcgui.Dialog().ok("update_all()", "'Update All' file missing/empty!", os.path.split(fn)[0], os.path.basename(fn))
log("< _update_all()")
def _download_item( self, forceInstall=False ):
log("> _download_item() forceInstall=%s" % forceInstall)
try:
if ( forceInstall or xbmcgui.Dialog().yesno( self.title, xbmc.getLocalizedString( 30000 ), "", "", xbmc.getLocalizedString( 30020 ), xbmc.getLocalizedString( 30021 ) ) ):
self.dialog.create( self.title, xbmc.getLocalizedString( 30002 ), xbmc.getLocalizedString( 30003 ) )
asset_files = []
folders = [ self.args.download_url.replace( " ", "%20" ) ]
while folders:
try:
htmlsource = readURL( self.REPO_URL + folders[ 0 ] )
if ( not htmlsource ): raise
items = self._parse_html_source( htmlsource )
if ( not items or items[ "status" ] == "fail" ): raise
files, dirs = self._parse_items( items )
for file in files:
asset_files.append( "%s/%s" % ( items[ "url" ], file, ) )
for folder in dirs:
folders.append( folders[ 0 ] + folder )
folders = folders[ 1 : ]
except:
folders = []
finished_path = self._get_files( asset_files )
self.dialog.close()
if finished_path and not forceInstall:
xbmcgui.Dialog().ok( self.title, xbmc.getLocalizedString( 30008 ), finished_path )
# force list refresh
# xbmc.executebuiltin('Container.Refresh')
except:
# oops print error message
print "ERROR: %s::%s (%d) - %s" % ( self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
self.dialog.close()
xbmcgui.Dialog().ok( self.title, xbmc.getLocalizedString( 30030 ) )
log("< _download_item()")
def _get_files( self, asset_files ):
""" fetch the files """
try:
finished_path = ""
for cnt, url in enumerate( asset_files ):
items = os.path.split( url )
# base path
drive = xbmc.translatePath( "/".join( [ "special://home", self.args.install ] ) )
# create the script/plugin/skin title
parts = items[ 0 ].split( "/" )
version = ""
if ( self.args.voffset != 0 ):
version = " - %s" % ( parts[ self.args.voffset ], )
del parts[ self.args.voffset ]
parts[ self.args.voffset - 1 ] = parts[ self.args.voffset - 1 ].replace( "%20", " " ) + version
path = os.path.join( drive, os.path.sep.join( parts[ self.args.ioffset : ] ).replace( "%20", " " ) )
if ( not finished_path ): finished_path = path
file = items[ 1 ].replace( "%20", " " )
pct = int( ( float( cnt ) / len( asset_files ) ) * 100 )
self.dialog.update( pct, "%s %s" % ( xbmc.getLocalizedString( 30005 ), url, ), "%s %s" % ( xbmc.getLocalizedString( 30006 ), path, ), "%s %s" % ( xbmc.getLocalizedString( 30007 ), file, ) )
if ( self.dialog.iscanceled() ): raise
if ( not os.path.isdir( path ) ): os.makedirs( path )
url = self.REPO_URL + url.replace( " ", "%20" )
fpath = os.path.join( path, file )
log("urlretrieve() %s -> %s" % (url, fpath))
urllib.urlretrieve( url, fpath )
except:
finished_path = ""
# oops print error message
print "ERROR: %s::%s (%d) - %s" % ( self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
raise
log("_get_files() finished_path=%s" % finished_path)
return finished_path
def _parse_html_source( self, htmlsource ):
""" parse html source for tagged version and url """
try:
parser = Parser( htmlsource )
return parser.dict
except:
return {}
def _parse_items( self, items ):
""" separates files and folders """
folders = []
files = []
for item in items[ "assets" ]:
if ( item.endswith( "/" ) ):
folders.append( item )
else:
files.append( item )
return files, folders