Esempio n. 1
0
    def run(self):
        # well this is just fugly.  call it "experimental"
        while Config.running:
            try:
                scrobble_item = self.queue.get(0)
                try:
                    song = scrobble_item.song
                    type = scrobble_item.type
                    error = scrobble_item.error
                    etime = scrobble_item.etime

                    try:
                        (tracknumber, artist, album, track) = [escape(item) for item in song.tags]
                    except ValueError:
                        log.info("skipping scrobble for {} (bad tags)".format(song.path))
                        continue

                    if type == NOW_PLAYING:
                        log.debug(u"scrobbling now playing %s %s %s" %
                                (artist, track, album))
                        self.login()
                        scrobbler.now_playing(
                                artist,
                                track)
                        # now_playing auto flushes, apparently.  don't call
                        # flush here or it will throw an exception, which is not
                        # what we want.
                    elif type == PLAYED:
                        # See: http://exhuma.wicked.lu/projects/python/scrobbler/api/public/scrobbler-module.html#login
                        # if mimetype is wrong, length == 0
                        if song.length < 30: log.warn(u"song length %s" % song.length)

                        # wait 60 seconds before re-trying
                        # submission
                        if error:
                            if (time.time() - etime) < 60:
                                break
                        log.debug(u"scrobbling played %s %s %s %s" %
                                (artist, track, album, song.length))
                        self.login()
                        scrobbler.submit(
                            artist,
                            track,
                            int(time.mktime(datetime.datetime.now().timetuple())),
                            source=escape(u'P'),
                            length=song.length,
                            album=album)
                        scrobbler.flush()
                except Exception as e:
                    log.exception(u"scrobble error: %s" % e)
                    # put it back
                    scrobble_item.error = True
                    scrobble_item.etime = time.time()
                    self.queue.put(scrobble_item)
            except Queue.Empty:
                pass

            # AS API enforced limit -- do not change.
            time.sleep(10)
Esempio n. 2
0
 def scrobble(self, media, end_time):
         if not self.authenticated:
                 return
         if media.length <= 30:
                 self.l.info("%s is too short to be scrobbled" % media)
                 return
         time_played = (media.length + time.time() -
                         time.mktime(end_time.timetuple()))
         if time_played < 240 and time_played < media.length * 0.5:
                 self.l.info("%s has not played long enough" % media)
                 return
         scrobbler.submit(media.artist, media.title,
                 int(time.mktime(end_time.timetuple()) - media.length),
                 length=int(media.length))
         scrobbler.flush()
Esempio n. 3
0
 def _flush(self):
     sb_success = False
     for tries in xrange(1, 4):
         try:
             sb_success = scrobbler.flush()
         except Exception, e:
             logger.error('Flush error: %s', e)
             log_traceback(e)
             sb_success = False
         if sb_success:
             break
         logger.error('Flush failed. try %d', tries)
Esempio n. 4
0
 def _flush(self):
     sb_success = False
     for tries in xrange(1, 4):
         try:
             sb_success = scrobbler.flush()
         except Exception, e:
             logger.error('Flush error: %s', e)
             log_traceback(e)
             sb_success = False
         if sb_success:
             break
         logger.error('Flush failed. try %d', tries)
Esempio n. 5
0
def main():
    import sys, os
    import plistlib
    from time import strftime

    # get modus operandi and additional arguments
    mode = None
    try:
        mode = sys.argv[1]
    except:
        mode = 'scrobble'
    if mode not in ('update', 'scrobble'):
        exit(__doc__)
        
    # load internal database
    dbPath = 'itunesScrobbler.sqlite3'
    print 'loading internal database...'
    db = openDatabase(dbPath)
    
    # load itunes media library
    print 'loading iTunes Media Library...'
    mediaLibPath = os.path.join(os.path.expanduser('~'), 'Music', 'iTunes', 'iTunes Music Library.xml')
    mediaLib = plistlib.readPlist(mediaLibPath)

    # synchronize libraries
    tracks = mediaLib['Tracks']
    tracksToScrobble = []
    print 'synchronizing databases...'
    for trackId, track in tracks.iteritems():
        try:
            if mode == 'update':
                updateDatabaseWithTrack(db, track)
            # gather scrobble data
            elif mode == 'scrobble':
                try:
                    count = playCountDiffWithDatabaseForTrack(db, track)
                except ValueError, e:
                    print 'Warning!', e.message
                else:
                    if count:
                        tracksToScrobble.append((count, track))
        except KeyError:
            pass
    # process gathered information
    if mode == 'update':
        print 'done! - internal database updated.'
    elif mode == 'scrobble':
        if not tracksToScrobble:
            print 'done! - nothing changed; nothing to scrobble.'
        else:
            # sort tracks
            tracksToScrobble.sort(key=lambda t:(t[1]['Artist']+t[1]['Name']).lower())
            # fix tracks' play time
            fauxPlayTime = datetime.now() # could be any datetime instance, like datetime(2012,1,1)
            patchAll = False
            for count, track in tracksToScrobble:
                if patchAll or 'Play Date UTC' not in track:
                    track['Play Date UTC'] = fauxPlayTime
                    trackLength = track.get('Total Time', 0) // 1000
                    fauxPlayTime = dateTimeWithOffsetFromDateTime(-count * trackLength, fauxPlayTime)
            # print what we want to scrobble
            print
            print 'This is what we\'ll send to last.fm:'
            print
            for count, track in tracksToScrobble:
                playDate = strftime('%Y-%m-%d %H:%M', track['Play Date UTC'].timetuple())
                print count, ('x %(Artist)s - %(Name)s' % track).encode('unicode-escape'), ('(%s)' % playDate)
            print
            okay = raw_input('is this okay with you? (y/N)  ')
            if okay != 'y':
                print 'alright, let\'s forget about it.'
            else:
                # try to load username and password and log in
                with open('.itunesScrobbler') as fd:
                    username = fd.readline().rstrip('\r\n')
                    password = fd.readline().rstrip('\r\n')
                print 'trying to log in to last.fm...'
                scrobbler.login(username, password)
                # scrobble!
                print 'scrobble ...',
                for count, track in tracksToScrobble:
                    trackDescription = ('%(Name)s by %(Artist)s' % track).encode('unicode-escape')
                    if len(trackDescription) > 69:
                        trackDescription = trackDescription[:67] + '..'
                    print '\rscrobble', trackDescription,
                    for i in xrange(count):
                        # need to compensate; we only know when the track was *last* played
                        if i is 0:
                            fixedTrack = track
                        else:
                            trackLength = track.get('Total Time', 0) // 1000
                            fixedTrack = track.copy()
                            fixedTrack['Play Date UTC'] = dateTimeWithOffsetFromDateTime(-i * trackLength, track['Play Date UTC'])
                        # send the fixed track information off to last.fm
                        if not scrobble(fixedTrack):
                            print
                            raise scrobbler.PostError('could not scrobble!')
                    updateDatabaseWithTrack(db, track)
                if not scrobbler.flush():
                    # Damn! Something went wrong right at the end.
                    # We could roll back our internal database now, which could lead to duplicate scrobbles,
                    # or we could just ignore this error, which could/will lead to tracks not being scrobbled at all;
                    # both scenarios suck donkey dick!
                    print 'b0rked hard; so sorry :f - you just lost some scrobbles due to bad caching.'
                else:
                    print
                    print 'all done! :)'
    
    db.commit()
    db.close()
Esempio n. 6
0
    def run(self):
        # well this is just fugly.  call it "experimental"
        while Config.running:
            try:
                scrobble_item = self.queue.get(0)
                try:
                    song = scrobble_item.song
                    type = scrobble_item.type
                    error = scrobble_item.error
                    etime = scrobble_item.etime

                    try:
                        (tracknumber, artist, album,
                         track) = [escape(item) for item in song.tags]
                    except ValueError:
                        log.info("skipping scrobble for {} (bad tags)".format(
                            song.path))
                        continue

                    if type == NOW_PLAYING:
                        log.debug(u"scrobbling now playing %s %s %s" %
                                  (artist, track, album))
                        self.login()
                        scrobbler.now_playing(artist, track)
                        # now_playing auto flushes, apparently.  don't call
                        # flush here or it will throw an exception, which is not
                        # what we want.
                    elif type == PLAYED:
                        # See: http://exhuma.wicked.lu/projects/python/scrobbler/api/public/scrobbler-module.html#login
                        # if mimetype is wrong, length == 0
                        if song.length < 30:
                            log.warn(u"song length %s" % song.length)

                        # wait 60 seconds before re-trying
                        # submission
                        if error:
                            if (time.time() - etime) < 60:
                                break
                        log.debug(u"scrobbling played %s %s %s %s" %
                                  (artist, track, album, song.length))
                        self.login()
                        scrobbler.submit(
                            artist,
                            track,
                            int(
                                time.mktime(
                                    datetime.datetime.now().timetuple())),
                            source=escape(u'P'),
                            length=song.length,
                            album=album)
                        scrobbler.flush()
                except Exception as e:
                    log.exception(u"scrobble error: %s" % e)
                    # put it back
                    scrobble_item.error = True
                    scrobble_item.etime = time.time()
                    self.queue.put(scrobble_item)
            except Queue.Empty:
                pass

            # AS API enforced limit -- do not change.
            time.sleep(10)