""" SVN Repo Installer Log Viewer """ import os import sys try: import xbmcgui import xbmc DEBUG = False except: DEBUG = True import urllib import re from xml.sax.saxutils import unescape def log(msg): xbmc.log("[%s]: %s" % (__plugin__, msg), xbmc.LOGDEBUG) class _Info: def __init__( self, *args, **kwargs ): self.__dict__.update( kwargs ) __plugin__ = sys.modules["__main__"].__plugin__ __date__ = '15-10-2009' log( "Module: %s Dated: %s loaded!" % (__name__, __date__ ) ) #HOME_DIR = os.getcwd() HOME_DIR = os.path.dirname(os.path.dirname(__file__)) # until XBMC getwd() bug fixed (affects linux) class ChangelogParser: # TODO: make these settings BASE_URL = "http://code.google.com/p/%s/updates/list?start=%d" PAGES = 3 def __init__( self, repo, category=None, revision=None, parse=True ): log( "%s __init__!" % (self.__class__)) if ( DEBUG ): self.log = "[B]%s: %s[/B]\n----\n" % ( category or repo, "ChangeLog" ) else: self.log = "[B]%s: %s[/B]\n----\n" % ( category or repo, xbmc.getLocalizedString( 30017 ) ) self.repo = repo self.category = category self.revision = revision self.parse = parse def fetch_changelog( self ): try: if ( DEBUG ): base_path = HOME_DIR else: base_path = os.path.join( xbmc.translatePath( "special://profile/" ), "plugin_data", "programs", HOME_DIR ) # make path if ( not os.path.isdir( base_path ) ): os.makedirs( base_path ) for page in range( self.PAGES ): path = os.path.join( base_path, "%s%d.txt" % ( self.repo, page, ) ) # open socket if ( os.path.isfile( path ) and self.revision is None): log( "%s path=%s" % (self.__class__.__name__, path) ) usock = open( path, "r" ) else: url = self.BASE_URL % ( self.repo, page * 50, ) log( "%s url=%s" % (self.__class__.__name__, url) ) usock = urllib.urlopen( url ) #read html source htmlSource = usock.read() # close socket usock.close() # save source for debugging if ( self.parse == False or not os.path.isfile( path ) ): file_object = open( path, "w" ) file_object.write( htmlSource ) file_object.close() # parse source if ( self.parse ): self._parse_html_source( htmlSource ) except Exception, e: print str( e ) self.log = str(e) return "" else: return self.log def _parse_html_source( self, htmlSource ): # regex's regex_items = re.compile( '
  • (.+?)
  • ', re.DOTALL ) regex_revisions = re.compile( '([^<]+)' ) regex_dates = re.compile( '([^<]+)' ) regex_details = re.compile( '
    (.+?)
    ', re.DOTALL ) if ( self.category is not None ): regex_subst = re.compile( "\[%s\]" % self.category, re.IGNORECASE ) # scrape info items = regex_items.findall( htmlSource ) # enumerate thru and scrape and combine all info for item in items: try: # scrape info revision = regex_revisions.findall( item )[ 0 ] date = regex_dates.findall( item )[ 0 ] author = regex_authors.findall( item )[ 0 ] detail = regex_details.findall( item )[ 0 ] # add to log if ( self.category is not None and re.findall( "\[.*%s.*\]" % self.category, detail, re.IGNORECASE ) ): if ( self.revision is not None and int( revision[ 1 : ] ) <= self.revision ): self.log += "[I]%s - %s - %s[/I]\n%s\n----\n" % ( revision, date, author, unescape( re.sub( regex_subst, "", detail ).strip(), { "'": "'", """: '"' } ), ) elif ( self.revision is None ): self.log += "[I]%s - %s - %s[/I]\n%s\n----\n" % ( revision, date, author, unescape( re.sub( regex_subst, "", detail ).strip(), { "'": "'", """: '"' } ), ) elif ( self.category is None ): pos = ( detail.find( "]" ) ) if ( pos >= 0 ): msg = unescape( "%s [I]%s - %s - %s[/I]\n%s\n----\n" % ( detail[ : pos + 1 ].strip(), revision, date, author, detail[ pos + 1 : ].strip() ), { "'": "'", """: '"' } ) else: msg = unescape( "[I]%s - %s - %s[/I]\n%s\n----\n" % ( revision, date, author, detail.strip(), ), { "'": "'", """: '"' } ) self.log += msg except: # not a valid log message pass if ( not DEBUG ): class GUI( xbmcgui.WindowXMLDialog ): # action codes ACTION_EXIT_SCRIPT = ( 9, 10, ) def __init__( self, *args, **kwargs ): log( "%s __init__!" % (self.__class__) ) xbmcgui.WindowXMLDialog.__init__( self ) self._parse_argv() def onInit( self ): self.dialog = xbmcgui.DialogProgress() self.dialog.create( __plugin__, xbmc.getLocalizedString( 30001 ) ) if ( self.args.repo is None ): log = self._fetch_readme() else: log = self._fetch_changelog() self.dialog.close() self._paste_log( log ) def _parse_argv( self ): # call _Info() with our formatted argv to create the self.args object exec "self.args = _Info(%s)" % ( urllib.unquote_plus( sys.argv[ 2 ][ 1 : ].replace( "&", ", " ) ), ) def _fetch_changelog( self ): if ( self.args.revision == True ): try: self.args.revision = int( re.findall( "\$Revision: ([0-9]+) \$", sys.modules[ "__main__" ].__svn_revision__ )[ 0 ] ) except: self.args.revision = None parser = ChangelogParser( self.args.repo, self.args.category, self.args.revision, self.args.parse ) return parser.fetch_changelog() def getReadmePath(self): home_dir = os.path.dirname(os.path.dirname(__file__)) base_path = os.path.join( home_dir, "resources", "language" ) path = os.path.join( base_path, xbmc.getLanguage(), "readme.txt" ) if not os.path.isfile(path): path = os.path.join( base_path, "English", "readme.txt" ) if not os.path.isfile(path): path = os.path.join( home_dir, "resources", "readme.txt" ) if not os.path.isfile(path): path = os.path.join( home_dir, "readme.txt" ) if not os.path.isfile(path): path = None return path def _fetch_readme( self ): try: self.args.category = "readme.txt" usock = None readme = None if ( self.args.readme is None ): # local readme - determine correct language path path = self.getReadmePath() if path: # open socket log("%s path=%s" % (self.__class__.__name__, path) ) usock = open( path, "r" ) else: log("%s url=%s" % (self.__class__.__name__, self.args.readme) ) usock = urllib.urlopen( self.args.readme ) #read html source if usock: readme = usock.read() # close socket usock.close() if not usock or not readme or "404 Not Found" in readme: readme = "Readme not found." except Exception, e: print str(e) readme = str(e) return readme def _paste_log( self, log ): try: title = ( self.args.category or self.args.repo ) self.getControl( 5 ).setText( log ) self.getControl( 3 ).setText( title ) except: pass def onClick( self, controlId ): pass def onFocus( self, controlId ): pass def onAction( self, action ): if ( action in self.ACTION_EXIT_SCRIPT ): self.close() def Main(): ui = GUI( "DialogScriptInfo.xml", HOME_DIR, "Default" ) ui.doModal() del ui if ( __name__ == "__main__" ): print "is logviewer __main__" if ( not DEBUG ): Main() else: parser = ChangelogParser( "xbmc-addons", "SVN Repo Installer" ) parser.fetch_changelog() print parser.log