home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 May / maximum-cd-2010-05.iso / DiscContents / boxee-0.9.20.10711.exe / scripts / Lyrics / resources / lib / gui.py < prev    next >
Encoding:
Python Source  |  2009-07-20  |  12.9 KB  |  310 lines

  1. """
  2.     Credits:    
  3.         EnderW:                    Original Author
  4.         Stanley87:                PM3 Integration and AD Removal
  5.         solexalex:
  6.         TomKun:
  7.         Thor918:                MyPlayer Class
  8.         Smuto:                    Skinning Mod
  9.         Spiff:                        Unicode support
  10.         Nuka1195:                lyricwiki & embedded Scraper and Modulization
  11.                 
  12. Please report any bugs: http://www.xboxmediacenter.com/forum/showthread.php?t=10187
  13. """
  14.  
  15. import sys
  16. import os
  17. import xbmc
  18. import xbmcgui
  19. import threading
  20.  
  21. from resources.lib.utilities import *
  22.  
  23. try:
  24.     current_dlg_id = xbmcgui.getCurrentWindowDialogId()
  25. except:
  26.     current_dlg_id = 0
  27. current_win_id = xbmcgui.getCurrentWindowId()
  28.  
  29. _ = sys.modules[ "__main__" ].__language__
  30. __scriptname__ = sys.modules[ "__main__" ].__scriptname__
  31. __version__ = sys.modules[ "__main__" ].__version__
  32. __svn_revision__ = sys.modules[ "__main__" ].__svn_revision__
  33.  
  34.  
  35. class GUI( xbmcgui.WindowXMLDialog ):
  36.     def __init__( self, *args, **kwargs ):
  37.         xbmcgui.WindowXMLDialog.__init__( self )
  38.  
  39.     def onInit( self ):
  40.         self.setup_all()#Start( function=self.setup_all ).start()
  41.  
  42.     def setup_all( self ):
  43.         self.setup_variables()
  44.         self.get_settings()
  45.         self.get_scraper()
  46.         self.getDummyTimer()
  47.         self.connThread = threading.Thread( target=self.getMyPlayer, args=() )
  48.         self.connThread.start()
  49.         #self.show_viz_window()
  50.  
  51.     def get_settings( self ):
  52.         self.settings = Settings().get_settings()
  53.         
  54.     def get_scraper( self ):
  55.         exec "import resources.scrapers.%s.lyricsScraper as lyricsScraper" % ( self.settings[ "scraper" ], )
  56.         self.LyricsScraper = lyricsScraper.LyricsFetcher()
  57.         self.scraper_title = lyricsScraper.__title__
  58.         self.scraper_exceptions = lyricsScraper.__allow_exceptions__
  59.  
  60.     def setup_variables( self ):
  61.         self.artist = None
  62.         self.song = None
  63.         self.Timer = None
  64.         self.controlId = -1
  65.         self.allow_exception = False
  66.  
  67.     def show_viz_window( self, startup=True ):
  68.         if ( self.settings[ "show_viz" ] ):
  69.             xbmc.executebuiltin( "XBMC.ActivateWindow(2006)" )
  70.         else:
  71.             if ( current_dlg_id != 9999 or not startup ):
  72.                 xbmc.executebuiltin( "XBMC.ActivateWindow(%s)" % ( current_win_id, ) )
  73.  
  74.     def show_control( self, controlId ):
  75.         self.getControl( 100 ).setVisible( controlId == 100 )
  76.         self.getControl( 110 ).setVisible( controlId == 110 )
  77.         self.getControl( 120 ).setVisible( controlId == 120 )
  78.         page_control = ( controlId == 100 )
  79.         xbmcgui.unlock()
  80.         xbmc.sleep( 5 )
  81.         try:
  82.             self.setFocus( self.getControl( controlId + page_control ) )
  83.         except:
  84.             self.setFocus( self.getControl( controlId ) )
  85.  
  86.     def get_lyrics(self, artist, song):
  87.         self.reset_controls()
  88.         self.getControl( 200 ).setLabel( "" )
  89.         self.menu_items = []
  90.         self.allow_exception = False
  91.         current_song = self.song
  92.         lyrics, kind = self.get_lyrics_from_file( artist, song )
  93.         if ( lyrics is not None ):
  94.             if ( current_song == self.song ):
  95.                 self.show_lyrics( lyrics )
  96.                 self.getControl( 200 ).setEnabled( False )
  97.                 self.getControl( 200 ).setLabel( _( 101 + kind ) )
  98.         else:
  99.             self.getControl( 200 ).setEnabled( True )
  100.             self.getControl( 200 ).setLabel( self.scraper_title )
  101.             lyrics = self.LyricsScraper.get_lyrics( artist, song )
  102.             if ( current_song == self.song ):
  103.                 if ( isinstance( lyrics, basestring ) ):
  104.                     self.show_lyrics( lyrics, True )
  105.                 elif ( isinstance( lyrics, list ) and lyrics ):
  106.                     self.show_choices( lyrics )
  107.                 else:
  108.                     self.getControl( 200 ).setEnabled( False )
  109.                     self.show_lyrics( _( 631 ) )
  110.                     self.allow_exception = True
  111.  
  112.     def get_lyrics_from_list( self, item ):
  113.         lyrics = self.LyricsScraper.get_lyrics_from_list( self.menu_items[ item ] )
  114.         self.show_lyrics( lyrics, True )
  115.  
  116.     def get_lyrics_from_file( self, artist, song ):
  117.         try:
  118.             xbmc.sleep( 60 )
  119.             if ( xbmc.getInfoLabel( "MusicPlayer.Lyrics" ) ):
  120.                 return unicode( xbmc.getInfoLabel( "MusicPlayer.Lyrics" ), "utf-8" ), True
  121.             self.song_path = make_legal_filepath( unicode( os.path.join( self.settings[ "lyrics_path" ], artist.replace( "\\", "_" ).replace( "/", "_" ), song.replace( "\\", "_" ).replace( "/", "_" ) + ( "", ".txt", )[ self.settings[ "use_extension" ] ] ), "utf-8" ), self.settings[ "compatible" ], self.settings[ "use_extension" ] )
  122.             lyrics_file = open( self.song_path, "r" )
  123.             lyrics = lyrics_file.read()
  124.             lyrics_file.close()
  125.             return unicode( lyrics, "utf-8" ), False
  126.         except IOError:
  127.             return None, False
  128.  
  129.     def save_lyrics_to_file( self, lyrics ):
  130.         try:
  131.             if ( not os.path.isdir( os.path.dirname( self.song_path ) ) ):
  132.                 os.makedirs( os.path.dirname( self.song_path ) )
  133.             lyrics_file = open( self.song_path, "w" )
  134.             lyrics_file.write( lyrics.encode( "utf-8", "ignore" ) )
  135.             lyrics_file.close()
  136.             return True
  137.         except IOError:
  138.             LOG( LOG_ERROR, "%s (rev: %s) %s::%s (%d) [%s]", __scriptname__, __svn_revision__, self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
  139.             return False
  140.  
  141.     def show_lyrics( self, lyrics, save=False ):
  142.         xbmcgui.lock()
  143.         if ( lyrics == "" ):
  144.             self.getControl( 100 ).setText( _( 632 ) )
  145.             self.getControl( 110 ).addItem( _( 632 ) )
  146.         else:
  147.             if ( "\r\n" in lyrics ):
  148.                 sep = "\r\n"
  149.             else:
  150.                 # XBMC textbox does not handle "\r", so replace it with "\n"
  151.                 sep = "\n"
  152.                 lyrics = lyrics.replace( "\r" , "\n" )
  153.             self.getControl( 100 ).setText( lyrics )
  154.             for x in lyrics.split( sep ):
  155.                 self.getControl( 110 ).addItem( x )
  156.             self.getControl( 110 ).selectItem( 0 )
  157.             if ( self.settings[ "save_lyrics" ] and save ): success = self.save_lyrics_to_file( lyrics )
  158.         self.show_control( 100 + ( self.settings[ "smooth_scrolling" ] * 10 ) )
  159.         
  160.     def show_choices( self, choices ):
  161.         xbmcgui.lock()
  162.         for song in choices:
  163.             self.getControl( 120 ).addItem( song[ 0 ] )
  164.         self.getControl( 120 ).selectItem( 0 )
  165.         self.menu_items = choices
  166.         self.show_control( 120 )
  167.     
  168.     def reset_controls( self ):
  169.         self.getControl( 100 ).reset()
  170.         self.getControl( 110 ).reset()
  171.         self.getControl( 120 ).reset()
  172.         
  173.     def change_settings( self ):
  174.         import resources.lib.settings as settings
  175.         settings = settings.GUI( "script-%s-settings.xml" % ( __scriptname__.replace( " ", "_" ), ), os.getcwd(), "Default" )
  176.         settings.doModal()
  177.         ok = False
  178.         if ( settings.changed ):
  179.             self.get_settings()
  180.             if ( settings.restart ):
  181.                 ok = xbmcgui.Dialog().yesno( __scriptname__, _( 240 ), "", _( 241 ) % ( __scriptname__, ), _( 271 ), _( 270 ) )
  182.             if ( not ok ):
  183.                 self.show_control( ( 100 + ( self.settings[ "smooth_scrolling" ] * 10 ), 120, )[ self.controlId == 120 ] )
  184.                 self.show_viz_window( startup=False )
  185.                 if ( settings.refresh ):
  186.                     self.myPlayerChanged( 2, True )
  187.             else: self.exit_script( True )
  188.         del settings
  189.  
  190.     def _show_credits( self ):
  191.         """ shows a credit window """
  192.         show_credits()
  193.  
  194.     def get_exception( self ):
  195.         """ user modified exceptions """
  196.         if ( self.scraper_exceptions ):
  197.             artist = self.LyricsScraper._format_param( self.artist, False )
  198.             alt_artist = get_keyboard( artist, "%s: %s" % ( _( 100 ), unicode( self.artist, "utf-8", "ignore" ), ) )
  199.             if ( alt_artist != artist ):
  200.                 exception = ( artist, alt_artist, )
  201.                 self.LyricsScraper._set_exceptions( exception )
  202.                 self.myPlayerChanged( 2, True )
  203.  
  204.     def exit_script( self, restart=False ):
  205.         if ( self.Timer is not None ): self.Timer.cancel()
  206.         self.connThread.join()
  207.         self.close()
  208.         if ( restart ): xbmc.executebuiltin( "XBMC.RunScript(%s)" % ( os.path.join( os.getcwd(), "default.py" ), ) )
  209.  
  210.     def onClick( self, controlId ):
  211.         if ( controlId == 120 ):
  212.             self.get_lyrics_from_list( self.getControl( 120 ).getSelectedPosition() )
  213.  
  214.     def onFocus( self, controlId ):
  215.         #xbmc.sleep( 5 )
  216.         #self.controlId = self.getFocusId()
  217.         self.controlId = controlId
  218.  
  219.     def onAction( self, action ):
  220.         actionId = action.getId()
  221.         if ( actionId in ACTION_EXIT_SCRIPT ):
  222.             self.exit_script()
  223.         elif ( actionId in ACTION_SETTINGS_MENU ):
  224.             self.change_settings()
  225.         #elif ( action.getButtonCode() in SHOW_CREDITS ):
  226.         #    self._show_credits()
  227.         elif ( self.allow_exception and actionId in ACTION_GET_EXCEPTION ):
  228.             self.get_exception()
  229.  
  230.     def get_artist_from_filename( self, filename ):
  231.         try:
  232.             artist = filename
  233.             song = filename
  234.             basename = os.path.basename( filename )
  235.             # Artist - Song.ext
  236.             if ( self.settings[ "filename_format" ] == 0 ):
  237.                 artist = basename.split( "-", 1 )[ 0 ].strip()
  238.                 song = os.path.splitext( basename.split( "-", 1 )[ 1 ].strip() )[ 0 ]
  239.             # Artist/Album/Song.ext or Artist/Album/Track Song.ext
  240.             elif ( self.settings[ "filename_format" ] in ( 1, 2, ) ):
  241.                 artist = os.path.basename( os.path.split( os.path.split( filename )[ 0 ] )[ 0 ] )
  242.                 # Artist/Album/Song.ext
  243.                 if ( self.settings[ "filename_format" ] == 1 ):
  244.                     song = os.path.splitext( basename )[ 0 ]
  245.                 # Artist/Album/Track Song.ext
  246.                 elif ( self.settings[ "filename_format" ] == 2 ):
  247.                     song = os.path.splitext( basename )[ 0 ].split( " ", 1 )[ 1 ]
  248.         except:
  249.             # invalid format selected
  250.             LOG( LOG_ERROR, "%s (rev: %s) %s::%s (%d) [%s]", __scriptname__, __svn_revision__, self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
  251.         return artist, song
  252.  
  253.     # getDummyTimer() and self.Timer are currently used for the Player() subclass so when an onPlayback* event occurs, 
  254.     # it calls myPlayerChanged() immediately.
  255.     def getDummyTimer( self ):
  256.         self.Timer = threading.Timer( 60*60*60, self.getDummyTimer,() )
  257.         self.Timer.start()
  258.     
  259.     def getMyPlayer( self ):
  260.         self.MyPlayer = MyPlayer( xbmc.PLAYER_CORE_PAPLAYER, function=self.myPlayerChanged )
  261.         self.myPlayerChanged( 2 )
  262.  
  263.     def myPlayerChanged( self, event, force_update=False ):
  264.         LOG( LOG_DEBUG, "%s (rev: %s) GUI::myPlayerChanged [%s]", __scriptname__, __svn_revision__, [ "stopped","ended","started" ][ event ] )
  265.         if ( event < 2 ): 
  266.             self.exit_script()
  267.         else:
  268.             for cnt in range( 5 ):
  269.                 song = xbmc.getInfoLabel( "MusicPlayer.Title" )
  270.                 artist = xbmc.getInfoLabel( "MusicPlayer.Artist" )
  271.                 if ( song and ( not artist or self.settings[ "use_filename" ] ) ):
  272.                     artist, song = self.get_artist_from_filename( xbmc.Player().getPlayingFile() )
  273.                 if ( song and ( self.song != song or self.artist != artist or force_update ) ):
  274.                     self.artist = artist
  275.                     self.song = song
  276.                     self.get_lyrics( artist, song )
  277.                     break
  278.                 xbmc.sleep( 50 )
  279.  
  280.  
  281. ## Thanks Thor918 for this class ##
  282. class MyPlayer( xbmc.Player ):
  283.     """ Player Class: calls function when song changes or playback ends """
  284.     def __init__( self, *args, **kwargs ):
  285.         xbmc.Player.__init__( self )
  286.         self.function = kwargs[ "function" ]
  287.  
  288.     def onPlayBackStopped( self ):
  289.         xbmc.sleep( 300 )
  290.         if ( not xbmc.Player().isPlayingAudio() ):
  291.             self.function( 1 )
  292.     
  293.     def onPlayBackEnded( self ):
  294.         xbmc.sleep( 300 )
  295.         if ( not xbmc.Player().isPlayingAudio() ):
  296.             self.function( 1 )
  297.     
  298.     def onPlayBackStarted( self ):
  299.         self.function( 2 )
  300.  
  301.  
  302. #class Start( threading.Thread ):
  303. #    """ Thread Class used to allow gui to show before all checks are done at start of script """
  304. #    def __init__( self, *args, **kwargs ):
  305. #        threading.Thread.__init__( self )
  306. #        self.function = kwargs[ "function" ]
  307. #
  308. #    def run(self):
  309. #        self.function()
  310.