Changeset 1871

Show
Ignore:
Timestamp:
09/11/08 17:23:16 (2 months ago)
Author:
duncan
svm:headrev:

cc3e1ea1-1e01-0410-8d68-8b121e83a9d5:11153
Message:

Moved code about, makes a big diff

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • freevo/src/audio/plugins/lastfm2.py

    r1858 r1871  
    3939import rc 
    4040import version, revision 
    41 from event import PLAY_END 
     41from event import STOP, PLAY_END 
    4242from menu import MenuItem, Menu 
    43 from gui import AlertBox 
     43from gui import AlertBox, PopupBox 
    4444from audio.audioitem import AudioItem 
    4545from audio.player import PlayerGUI 
     
    6666    """ 
    6767    @benchmark(benchmarking, benchmarkcall) 
    68     def __init__(self, why): 
     68    def __init__(self, why, url=''): 
    6969        Exception.__init__(self) 
    70         self.why = str(why) 
     70        self.why = str(why) + ': ' + url 
    7171 
    7272    def __str__(self): 
     
    223223    def eventhandler(self, event, menuw=None): 
    224224        _debug_('LastFMItem.eventhandler(event=%s, menuw=%r)' % (event, menuw), 2) 
    225         print 'LastFMItem.eventhandler(event=%r, arg=%r)' % (event.name, event.arg) 
     225        _debug_('LastFMItem.eventhandler(event=%r, arg=%r)' % (event.name, event.arg), DWARNING) 
    226226        if event == 'STOP': 
    227227            self.stop(self.arg, self.menuw) 
    228228            return 
    229         if event == 'PLAY_END': 
     229        if event == 'PLAY_START': 
     230            pass 
     231        elif event == 'PLAY_END': 
    230232            if self.feed is not None and len(self.feed.entries) > 0: 
    231233                self.feed.entries.pop(0) 
     234            self.stop() 
    232235            self.play() 
    233236            return False 
     
    254257            self.menuw = menuw 
    255258 
    256         if self.feed is None or len(self.feed.entries) <= 0: 
    257             try: 
    258                 for i in range(3): 
    259                     xspf = self.webservices.request_xspf() 
    260                     if xspf != 'No recs :(': 
     259        pop = None 
     260        if self.feed is None: 
     261            pop = PopupBox(text=_('Downloading, please wait...')) 
     262            pop.show() 
     263 
     264        try: 
     265            if self.feed is None or len(self.feed.entries) <= 1: 
     266                try: 
     267                    for i in range(3): 
     268                        xspf = self.webservices.request_xspf() 
     269                        if xspf != 'No recs :(': 
     270                            break 
     271                        time.sleep(2) 
     272                    else: 
     273                        if menuw: 
     274                            AlertBox(text='No recs :(').show() 
     275                        traceback.print_stack() 
     276                        rc.post_event(STOP) 
     277                        return 
     278 
     279                    self.feed = self.xspf.parse(xspf) 
     280                    if self.feed is None: 
     281                        if menuw: 
     282                            AlertBox(text=_('Cannot get XSFP')).show() 
     283                        traceback.print_stack() 
     284                        rc.post_event(STOP) 
     285                        return 
     286                except LastFMError, why: 
     287                    _debug_(why, DWARNING) 
     288                    if menuw: 
     289                        AlertBox(text=str(why)).show() 
     290                    rc.post_event(STOP) 
     291                    return 
     292 
     293            entry = self.feed.entries[0] 
     294            _debug_('entry "%s / %s / %s" of %s' % (entry.artist, entry.album, entry.title, len(self.feed.entries))) 
     295            self.stream_name = urllib.unquote_plus(self.feed.title) 
     296            self.album = entry.album 
     297            self.artist = entry.artist 
     298            self.title = entry.title 
     299            self.location_url = entry.location_url 
     300            self.length = entry.duration 
     301            basename = os.path.join(config.LASTFM_DIR, self.stream_name, entry.artist, entry.album, entry.title) 
     302            self.basename = basename.lower().replace(' ', '_').\ 
     303                replace('.', '').replace('\'', '').replace(':', '').replace(',', '') 
     304            if not os.path.exists(os.path.dirname(self.basename)): 
     305                _debug_('make directory %r' % (os.path.dirname(self.basename),), DINFO) 
     306                os.makedirs(os.path.dirname(self.basename), 0777) 
     307            # url is changed, to include file:// 
     308            self.url = os.path.join(self.basename + os.path.splitext(entry.location_url)[1]) 
     309            self.trackpath = os.path.join(self.basename + os.path.splitext(entry.location_url)[1]) 
     310            self.track_downloader = self.webservices.download(self.location_url, self.trackpath) 
     311            if entry.image_url: 
     312                self.image = os.path.join(self.basename + os.path.splitext(entry.image_url)[1]) 
     313                self.image_downloader = self.webservices.download(entry.image_url, self.image) 
     314                # Wait three seconds for the image to be downloaded 
     315                for i in range(30): 
     316                    if not self.image_downloader.isrunning(): 
    261317                        break 
    262                     time.sleep(2) 
    263                 else: 
    264                     if menuw: 
    265                         AlertBox(text='No recs :(').show() 
     318                    time.sleep(0.1) 
     319            else: 
     320                self.image = None 
     321            #self.is_playlist = True 
     322            # Wait for a bit of the file to be downloaded 
     323            while self.track_downloader.filesize() < 1024 * 20: 
     324                if not self.track_downloader.isrunning(): 
    266325                    traceback.print_stack() 
    267                     rc.post_event(PLAY_END) 
     326                    rc.post_event(STOP) 
    268327                    return 
    269  
    270                 self.feed = self.xspf.parse(xspf) 
    271                 if self.feed is None: 
    272                     if menuw: 
    273                         AlertBox(text=_('Cannot get XSFP')).show() 
    274                     traceback.print_stack() 
    275                     rc.post_event(PLAY_END) 
    276                     return 
    277             except LastFMError, why: 
    278                 _debug_(why, DWARNING) 
     328                time.sleep(0.1) 
     329            self.player = PlayerGUI(self, menuw) 
     330            error = self.player.play() 
     331            if error: 
     332                _debug_('player play error=%r' % (error,), DWARNING) 
    279333                if menuw: 
    280                     AlertBox(text=str(why)).show() 
    281                 rc.post_event(PLAY_END) 
    282                 return 
    283  
    284         entry = self.feed.entries[0] 
    285         _debug_('entry "%s / %s / %s" of %s' % (entry.artist, entry.album, entry.title, len(self.feed.entries))) 
    286         self.stream_name = urllib.unquote_plus(self.feed.title) 
    287         self.album = entry.album 
    288         self.artist = entry.artist 
    289         self.title = entry.title 
    290         self.location_url = entry.location_url 
    291         self.length = entry.duration 
    292         basename = os.path.join(config.LASTFM_DIR, self.stream_name, entry.artist, entry.album, entry.title).lower() 
    293         self.basename = basename.replace(' ', '_').replace('.', '').replace('\'', '').replace(':', '').replace(',', '') 
    294         if not os.path.exists(os.path.dirname(self.basename)): 
    295             _debug_('make directory %r' % (os.path.dirname(self.basename),), DINFO) 
    296             os.makedirs(os.path.dirname(self.basename), 0777) 
    297         # url is changed, to include file:// 
    298         self.url = os.path.join(self.basename + os.path.splitext(entry.location_url)[1]) 
    299         self.trackpath = os.path.join(self.basename + os.path.splitext(entry.location_url)[1]) 
    300         self.track_downloader = self.webservices.download(self.location_url, self.trackpath) 
    301         if entry.image_url: 
    302             self.image = os.path.join(self.basename + os.path.splitext(entry.image_url)[1]) 
    303             self.image_downloader = self.webservices.download(entry.image_url, self.image) 
    304             # Wait three seconds for the image to be downloaded 
    305             for i in range(30): 
    306                 if not self.image_downloader.isrunning(): 
    307                     break 
    308                 time.sleep(0.1) 
    309         else: 
    310             self.image = None 
    311         #self.is_playlist = True 
    312         # Wait for a bit of the file to be downloaded 
    313         while self.track_downloader.filesize() < 1024 * 20: 
    314             if not self.track_downloader.isrunning(): 
     334                    AlertBox(text=error).show() 
    315335                traceback.print_stack() 
    316                 rc.post_event(PLAY_END) 
    317                 return 
    318             time.sleep(0.1) 
    319         self.player = PlayerGUI(self, menuw) 
    320         error = self.player.play() 
    321         if error: 
    322             _debug_('player play error=%r' % (error,), DWARNING) 
    323             if menuw: 
    324                 AlertBox(text=error).show() 
    325             traceback.print_stack() 
    326             rc.post_event(PLAY_END) 
     336                rc.post_event(STOP) 
     337        finally: 
     338            if pop is not None: 
     339                pop.destroy() 
    327340 
    328341 
     
    333346        """ 
    334347        _debug_('LastFMItem.stop(arg=%r, menuw=%r)' % (arg, menuw), 1) 
     348        if self.player: 
     349            self.player.stop() 
    335350 
    336351 
     
    355370        _debug_('ban()', 1) 
    356371        self.webservices.ban() 
    357  
    358  
    359  
    360  
    361 class SmartRedirectHandler(urllib2.HTTPRedirectHandler): 
    362     def http_error_301(self, req, fp, code, msg, headers): 
    363         print 'DJW:http_error_301' 
    364         result = urllib2.HTTPRedirectHandler.http_error_301(self, req, fp, code, msg, headers) 
    365         result.status = code 
    366         return result 
    367  
    368     def http_error_302(self, req, fp, code, msg, headers): 
    369         print 'DJW:http_error_302' 
    370         result = urllib2.HTTPRedirectHandler.http_error_302(self, req, fp, code, msg, headers) 
    371         result.status = code 
    372         return result 
    373  
    374  
    375  
    376 class LastFMDownloader(Thread): 
    377     """ 
    378     Download the stream to a file 
    379  
    380     There is a bad bug im mplayer that corrupts the url passed, so we have to 
    381     download it to a file and then play it 
    382     """ 
    383     @benchmark(benchmarking, benchmarkcall) 
    384     def __init__(self, url, filename, headers=None): 
    385         Thread.__init__(self) 
    386         self.url = url 
    387         self.filename = filename 
    388         self.headers = headers 
    389         self.running = True 
    390         self.size = 0 
    391  
    392  
    393     @benchmark(benchmarking, benchmarkcall) 
    394     def run(self): 
    395         """ 
    396         Execute a download operation. Stop when finished downloading or 
    397         requested to stop. 
    398         """ 
    399         request = urllib2.Request(self.url, headers=self.headers) 
    400         opener = urllib2.build_opener(SmartRedirectHandler()) 
    401         try: 
    402             f = opener.open(request) 
    403             fd = open(self.filename, 'wb') 
    404             while self.running: 
    405                 reply = f.read(1024 * 100) 
    406                 fd.write(reply) 
    407                 if len(reply) == 0: 
    408                     self.running = False 
    409                     print '%s downloaded' % self.filename 
    410                     # debugs fail during shutdown 
    411                     #_debug_('%s downloaded' % self.filename) 
    412                     # what we could do now is to add tags to track 
    413                     break 
    414                 self.size += len(reply) 
    415             else: 
    416                 print '%s download aborted' % self.filename 
    417                 #_debug_('%s download aborted' % self.filename) 
    418                 os.remove(self.filename) 
    419             fd.close() 
    420             f.close() 
    421         except ValueError, why: 
    422             _debug_('%s: %s' % (self.url, why), DWARNING) 
    423         except urllib2.HTTPError, why: 
    424             _debug_('%s: %s' % (self.url, why), DWARNING) 
    425  
    426  
    427     @benchmark(benchmarking, benchmarkcall) 
    428     def filesize(self): 
    429         """ 
    430         Get the downloaded file size 
    431         """ 
    432         return self.size 
    433  
    434  
    435     @benchmark(benchmarking, benchmarkcall) 
    436     def stop(self): 
    437         """ 
    438         Stop the download thead running 
    439         """ 
    440         # this does not stop the download thread 
    441         self.running = False 
    442  
    443  
    444     @benchmark(benchmarking, benchmarkcall) 
    445     def isrunning(self): 
    446         """ 
    447         See if the thread running 
    448         """ 
    449         return self.running 
    450  
    451  
    452  
    453 class LastFMWebServices: 
    454     """ 
    455     Interface to LastFM web-services 
    456     """ 
    457     _version = '1.1.2' 
    458     headers = { 
    459         'User-agent': 'Freevo-%s (r%s)' % (version.__version__, revision.__revision__) 
    460     } 
    461  
    462     @benchmark(benchmarking, benchmarkcall) 
    463     def __init__(self): 
    464         _debug_('LastFMWebServices.__init__()', 2) 
    465         self.logincachefilename = os.path.join(config.FREEVO_CACHEDIR, 'lastfm.session') 
    466         try: 
    467             self.cachefd = open(self.logincachefilename, 'r') 
    468             self.session = self.cachefd.readline().strip('\n') 
    469             self.stream_url = self.cachefd.readline().strip('\n') 
    470             self.base_url = self.cachefd.readline().strip('\n') 
    471             self.base_path = self.cachefd.readline().strip('\n') 
    472             self.downloader = None 
    473         except IOError, why: 
    474             self._login() 
    475  
    476  
    477     @benchmark(benchmarking, benchmarkcall) 
    478     def shutdown(self): 
    479         """ 
    480         Shutdown the lasf.fm webservices 
    481         """ 
    482         if self.downloader is not None: 
    483             self.downloader.stop() 
    484  
    485  
    486     @benchmark(benchmarking, benchmarkcall) 
    487     def _urlopen(self, url, lines=True): 
    488         """ 
    489         Wrapper to see what is sent and received 
    490         When lines is true then the reply is returned as a list of lines, 
    491         otherwise it is returned as a block. 
    492  
    493         @param url: Is the URL to read. 
    494         @param data: Is the POST data. 
    495         @param lines: return a list of lines, otherwise data block. 
    496         @returns: reply from request 
    497         """ 
    498         _debug_('url=%r, lines=%r' % (url, lines), 1) 
    499         request = urllib2.Request(url, headers=LastFMWebServices.headers) 
    500         opener = urllib2.build_opener(SmartRedirectHandler()) 
    501         try: 
    502             if lines: 
    503                 reply = [] 
    504                 f = opener.open(request) 
    505                 lines = f.readlines() 
    506                 if lines is None: 
    507                     return [] 
    508                 for line in lines: 
    509                     reply.append(line.strip('\n')) 
    510                 _debug_('reply=%r' % (reply,), 1) 
    511             else: 
    512                 reply = '' 
    513                 f = opener.open(request) 
    514                 reply = f.read() 
    515                 _debug_('len(reply)=%r' % (len(reply),), 1) 
    516             return reply 
    517         except urllib2.HTTPError, why: 
    518             _debug_('%s: %s' % (url, why)) 
    519             raise LastFMError(why) 
    520         except Exception, why: 
    521             _debug_('%s: %s' % (url, why)) 
    522             raise LastFMError(why) 
    523  
    524  
    525     @benchmark(benchmarking, benchmarkcall) 
    526     def _login(self, arg=None): 
    527         """Read session and stream url from ws.audioscrobbler.com""" 
    528         _debug_('login(arg=%r)' % (arg,), 2) 
    529         username = config.LASTFM_USER 
    530         password_txt = config.LASTFM_PASS 
    531         password = md5.new(config.LASTFM_PASS) 
    532         login_url='http://ws.audioscrobbler.com/radio/handshake.php' + \ 
    533             '?version=%s&platform=linux' % (LastFMWebServices._version) + \ 
    534             '&username=%s&passwordmd5=%s' % (config.LASTFM_USER, password.hexdigest()) + \ 
    535             '&debug=0&language=%s' % (config.LASTFM_LANG) 
    536         stream_url = '' 
    537  
    538         try: 
    539             lines = self._urlopen(login_url) 
    540             for line in lines: 
    541                 # this is a bit dangerous if a variable clashes 
    542                 exec('self.%s = "%s"' % tuple(line.split('=', 1))) 
    543             # Save the lastfm session information 
    544             fd = open(self.logincachefilename, 'w') 
    545             print >>fd, self.session 
    546             print >>fd, self.stream_url 
    547             print >>fd, self.base_url 
    548             print >>fd, self.base_path 
    549             fd.close() 
    550         except IOError, why: 
    551             self.session = '' 
    552             self.stream_url = '' 
    553             self.base_url = '' 
    554             self.base_path = '' 
    555  
    556  
    557     @benchmark(benchmarking, benchmarkcall) 
    558     def request_xspf(self): 
    559         """Request a XSPF (XML Shareable Playlist File)""" 
    560         _debug_('LastFMWebServices.request_xspf()', 1) 
    561         if not self.session: 
    562             self._login() 
    563         request_url = 'http://%s%s/xspf.php?sk=%s&discovery=0&desktop=%s' % \ 
    564             (self.base_url, self.base_path, self.session, LastFMWebServices._version) 
    565         return self._urlopen(request_url, lines=False) 
    566  
    567  
    568     @benchmark(benchmarking, benchmarkcall) 
    569     def adjust_station(self, station_url): 
    570         """Change Last FM Station""" 
    571         _debug_('adjust_station(station_url=%r)' % (station_url,), 2) 
    572         if not self.session: 
    573             self._login() 
    574         tune_url = 'http://ws.audioscrobbler.com/radio/adjust.php?session=%s&url=%s&lang=%s&debug=0' % \ 
    575             (self.session, station_url, config.LASTFM_LANG) 
    576         try: 
    577             for line in self._urlopen(tune_url): 
    578                 if re.search('response=OK', line): 
    579                     return True 
    580             return False 
    581         except AttributeError, why: 
    582             return None 
    583         except IOError, why: 
    584             return None 
    585  
    586  
    587     @benchmark(benchmarking, benchmarkcall) 
    588     def now_playing(self): 
    589         """ 
    590         Return Song Info and album Cover 
    591         """ 
    592         _debug_('now_playing()', 2) 
    593         if not self.session: 
    594             self._login() 
    595         info_url = 'http://ws.audioscrobbler.com/radio/np.php?session=%s&debug=0' % (self.session,) 
    596         reply = self._urlopen(info_url) 
    597         if not reply or reply[0] == 'streaming=false': 
    598             return None 
    599         return reply 
    600  
    601  
    602     @benchmark(benchmarking, benchmarkcall) 
    603     def download(self, url, filename): 
    604         """ 
    605         Download album cover or track to last.fm directory. 
    606  
    607         Add the session as a cookie to the request 
    608  
    609         @param url: location of item to download 
    610         @param filename: path to downloaded file 
    611         """ 
    612         _debug_('download(url=%r, filename=%r)' % (url, filename), 1) 
    613         if not self.session: 
    614             self._login() 
    615         headers = { 
    616             'Cookie': 'Session=%s' % self.session, 
    617             'User-agent': 'Freevo-%s (r%s)' % (version.__version__, revision.__revision__) 
    618         } 
    619         self.downloader = LastFMDownloader(url, filename, headers) 
    620         self.downloader.start() 
    621         return self.downloader 
    622  
    623  
    624     @benchmark(benchmarking, benchmarkcall) 
    625     def skip(self): 
    626         """Skip song""" 
    627         _debug_('skip()', 2) 
    628         if not self.session: 
    629             self._login 
    630         skip_url = 'http://ws.audioscrobbler.com/radio/control.php?session=%s&command=skip&debug=0' % \ 
    631             (self.session) 
    632         return self._urlopen(skip_url) 
    633  
    634  
    635     @benchmark(benchmarking, benchmarkcall) 
    636     def love(self): 
    637         """Send "Love" information to audioscrobbler""" 
    638         _debug_('love()', 2) 
    639         if not self.session: 
    640             self._login 
    641         love_url = 'http://ws.audioscrobbler.com/radio/control.php?session=%s&command=love&debug=0' % \ 
    642             (self.session) 
    643         return self._urlopen(love_url) 
    644  
    645  
    646     @benchmark(benchmarking, benchmarkcall) 
    647     def ban(self): 
    648         """Send "Ban" information to audioscrobbler""" 
    649         _debug_('ban()', 2) 
    650         if not self.session: 
    651             self._login 
    652         ban_url = 'http://ws.audioscrobbler.com/radio/control.php?session=%s&command=ban&debug=0' % \ 
    653             (self.session) 
    654         return self._urlopen(ban_url) 
    655  
    656  
    657     @benchmark(benchmarking, benchmarkcall) 
    658     def test_user_pass(self): 
    659         """ 
    660         Test User/Pass 
    661  
    662         This way you can check, whether a user/pass is valid. 
    663  
    664         http://ws.audioscrobbler.com/ass/pwcheck.php? 
    665             time=[TS]&username=[USER]&auth=[AUTH1]&auth2=[AUTH2]&defaultplayer=[PLAYER] 
    666  
    667         Variables: 
    668  
    669         * TS: Unix timestamp of the current time. 
    670         * USER: Username. 
    671         * AUTH1: md5( md5(password) + Timestamp), An md5 sum of an md5 sum of the password, plus the timestamp as salt. 
    672         * AUTH2: Second possible Password. The client uses md5( md5(toLower(password)) + Timestamp) 
    673         * PLAYER: See Appendix 
    674         """ 
    675         timestamp = time.strftime('%s', time.gmtime(time.time())) 
    676         username = config.LASTFM_USER 
    677         password = config.LASTFM_PASS 
    678         auth = md5.new(md5.new(password).hexdigest()+timestamp).hexdigest() 
    679         auth2 = md5.new(md5.new(password.lower()).hexdigest()+timestamp).hexdigest() 
    680         url = 'http://ws.audioscrobbler.com//ass/pwcheck.php?' + \ 
    681             'time=%s&' % timestamp + \ 
    682             'username=%s&' % username + \ 
    683             'auth=%s&' % auth + \ 
    684             'auth2=%s&' % auth2 + \ 
    685             'defaultplayer=fvo' 
    686         return self._urlopen(url) 
    687372 
    688373 
     
    741426 
    742427 
     428class LastFMWebServices: 
     429    """ 
     430    Interface to LastFM web-services 
     431    """ 
     432    _version = '1.1.2' 
     433    headers = { 
     434        'User-agent': 'Freevo-%s (r%s)' % (version.__version__, revision.__revision__) 
     435    } 
     436 
     437    @benchmark(benchmarking, benchmarkcall) 
     438    def __init__(self): 
     439        _debug_('LastFMWebServices.__init__()', 2) 
     440        self.logincachefilename = os.path.join(config.FREEVO_CACHEDIR, 'lastfm.session') 
     441        try: 
     442            self.cachefd = open(self.logincachefilename, 'r') 
     443            self.session = self.cachefd.readline().strip('\n') 
     444            self.stream_url = self.cachefd.readline().strip('\n') 
     445            self.base_url = self.cachefd.readline().strip('\n') 
     446            self.base_path = self.cachefd.readline().strip('\n') 
     447            self.downloader = None 
     448        except IOError, why: 
     449            self._login() 
     450 
     451 
     452    @benchmark(benchmarking, benchmarkcall) 
     453    def shutdown(self): 
     454        """ 
     455        Shutdown the lasf.fm webservices 
     456        """ 
     457        if self.downloader is not None: 
     458            self.downloader.stop() 
     459 
     460 
     461    @benchmark(benchmarking, benchmarkcall) 
     462    def _urlopen(self, url, lines=True): 
     463        """ 
     464        Wrapper to see what is sent and received 
     465        When lines is true then the reply is returned as a list of lines, 
     466        otherwise it is returned as a block. 
     467 
     468        @param url: Is the URL to read. 
     469        @param data: Is the POST data. 
     470        @param lines: return a list of lines, otherwise data block. 
     471        @returns: reply from request 
     472        """ 
     473        _debug_('url=%r, lines=%r' % (url, lines), 1) 
     474        request = urllib2.Request(url, headers=LastFMWebServices.headers) 
     475        opener = urllib2.build_opener(SmartRedirectHandler()) 
     476        try: 
     477            if lines: 
     478                reply = [] 
     479                f = opener.open(request) 
     480                lines = f.readlines() 
     481                if lines is None: 
     482                    return [] 
     483                for line in lines: 
     484                    reply.append(line.strip('\n')) 
     485                _debug_('reply=%r' % (reply,), 1) 
     486            else: 
     487                reply = '' 
     488                f = opener.open(request) 
     489                reply = f.read() 
     490                _debug_('len(reply)=%r' % (len(reply),), 1) 
     491            return reply 
     492        except urllib2.HTTPError, why: 
     493            _debug_('%s: %s' % (url, why)) 
     494            raise LastFMError(why, url) 
     495        except Exception, why: 
     496            _debug_('%s: %s' % (url, why)) 
     497            raise LastFMError(why, url) 
     498 
     499 
     500    @benchmark(benchmarking, benchmarkcall) 
     501    def _login(self, arg=None): 
     502        """Read session and stream url from ws.audioscrobbler.com""" 
     503        _debug_('login(arg=%r)' % (arg,), 2) 
     504        username = config.LASTFM_USER 
     505        password_txt = config.LASTFM_PASS 
     506        password = md5.new(config.LASTFM_PASS) 
     507        login_url='http://ws.audioscrobbler.com/radio/handshake.php' + \ 
     508            '?version=%s&platform=linux' % (LastFMWebServices._version) + \ 
     509            '&username=%s&passwordmd5=%s' % (config.LASTFM_USER, password.hexdigest()) + \ 
     510            '&debug=0&language=%s' % (config.LASTFM_LANG) 
     511        stream_url = '' 
     512 
     513        try: 
     514            lines = self._urlopen(login_url) 
     515            for line in lines: 
     516                # this is a bit dangerous if a variable clashes 
     517                exec('self.%s = "%s"' % tuple(line.split('=', 1))) 
     518            # Save the lastfm session information 
     519            fd = open(self.logincachefilename, 'w') 
     520            print >>fd, self.session 
     521            print >>fd, self.stream_url 
     522            print >>fd, self.base_url 
     523            print >>fd, self.base_path 
     524            fd.close() 
     525        except IOError, why: 
     526            self.session = '' 
     527            self.stream_url = '' 
     528            self.base_url = '' 
     529            self.base_path = '' 
     530 
     531 
     532    @benchmark(benchmarking, benchmarkcall) 
     533    def request_xspf(self): 
     534        """Request a XSPF (XML Shareable Playlist File)""" 
     535        _debug_('LastFMWebServices.request_xspf()', 1) 
     536        if not self.session: 
     537            self._login() 
     538        request_url = 'http://%s%s/xspf.php?sk=%s&discovery=0&desktop=%s' % \ 
     539            (self.base_url, self.base_path, self.session, LastFMWebServices._version) 
     540        return self._urlopen(request_url, lines=False) 
     541 
     542 
     543    @benchmark(benchmarking, benchmarkcall) 
     544    def adjust_station(self, station_url): 
     545        """Change Last FM Station""" 
     546        _debug_('adjust_station(station_url=%r)' % (station_url,), 2) 
     547        if not self.session: 
     548            self._login() 
     549        tune_url = 'http://ws.audioscrobbler.com/radio/adjust.php?session=%s&url=%s&lang=%s&debug=0' % \ 
     550            (self.session, station_url, config.LASTFM_LANG) 
     551        try: 
     552            for line in self._urlopen(tune_url): 
     553                if re.search('response=OK', line): 
     554                    return True 
     555            return False 
     556        except AttributeError, why: 
     557            return None 
     558        except IOError, why: 
     559            return None 
     560 
     561 
     562    @benchmark(benchmarking, benchmarkcall) 
     563    def now_playing(self): 
     564        """ 
     565        Return Song Info and album Cover 
     566        """ 
     567        _debug_('now_playing()', 2) 
     568        if not self.session: 
     569            self._login() 
     570        info_url = 'http://ws.audioscrobbler.com/radio/np.php?session=%s&debug=0' % (self.session,) 
     571        reply = self._urlopen(info_url) 
     572        if not reply or reply[0] == 'streaming=false': 
     573            return None 
     574        return reply 
     575 
     576 
     577    @benchmark(benchmarking, benchmarkcall) 
     578    def download(self, url, filename): 
     579        """ 
     580        Download album cover or track to last.fm directory. 
     581 
     582        Add the session as a cookie to the request 
     583 
     584        @param url: location of item to download 
     585        @param filename: path to downloaded file