On March 28, 2008 09:38:53 Thomas Perl wrote:
> Hello, Nick!
>
> On Thu, 2008-03-27 at 20:54 -0500, nikosapi wrote:
> > A new gPodder release is out so it's time to start adding features ;)
> >
> > If you have a player that is capable of running the Rockbox firmware[1]
> > you can enable logging everything you play to an audioscrobbler portable
> > player format logfile[2]. (Go to: Settings-->General
> > Settings-->Playback-->Last.fm Log and set it to "Yes")
> >
> > I wrote a patch that is able to use this logfile to mark episodes that
> > you've listened to as played in gPodder while you're syncing. For this to
> > work you must be using gPodder's tag update feature (set update_tags to
> > True) because the audioscrobbler logfile only reports the metadata of the
> > tracks you've listened to not an actual filename.
>
> Great work! I've looked through your patch and cleaned up some things
> (moved the find_mount_point function to gpodder.util, rename the config
> option, so people know this is related to mp3 players, re-structure some
> other parts of the code, move the list of possible file names to the
> class instead of having it per-instance, etc..). I have attached the
> updated patch, please have a look at it and try it out if it doesn't
> break anything.
>
> I'll merge the patch to SVN trunk if everything works and you are happy
> with the patch. I think this could really be an useful feature. One
> question remains, however: Which program is supposed to "clean" that
> file, or is Rockbox keeping it down to a maximum size, so it doesn't
> grow endlessly?
>
> Thanks,
> Thomas

Hello Thomas,

Thank you for looking over and improving my code :)  

I added one small thing, if find_mount_point() returns '/' then to prevent 
find_scrobbler_log() from os.walk()'ing your whole root filesystem we simply 
set mp3_player_mount_point to the the directory that we're syncing to. Appart 
from that I think the patch is ready.

Ideally the .scrobbler.log file should be cleaned by scrobbler software that 
submits tracks to last.fm. I wrote a small python module that can scrobble 
tracks but I don't really think that it belongs in gPodder. (Unless you 
really think otherwise...)

Have a good day,

nick
Index: src/gpodder/config.py
===================================================================
--- src/gpodder/config.py	(revision 643)
+++ src/gpodder/config.py	(working copy)
@@ -97,6 +97,7 @@
     'on_quit_systray': (bool, False),
     'create_m3u_playlists': (bool, False),
     'max_episodes_per_feed': (int, 200),
+    'mp3_player_use_scrobbler_log': (bool, False),
 
     # Window and paned positions
     'main_window_x': ( int, 100 ),
Index: src/gpodder/sync.py
===================================================================
--- src/gpodder/sync.py	(revision 643)
+++ src/gpodder/sync.py	(working copy)
@@ -390,6 +390,10 @@
 
 
 class MP3PlayerDevice(Device):
+    # if different players use other filenames besides
+    # .scrobbler.log, add them to this list
+    scrobbler_log_filenames = ['.scrobbler.log']
+
     def __init__(self):
         Device.__init__(self)
 
@@ -408,15 +412,25 @@
 
         self.destination = gl.config.mp3_player_folder
         self.buffer_size = 1024*1024 # 1 MiB
+        self.scrobbler_log = []
 
     def open(self):
         self.notify('status', _('Opening MP3 player'))
         if util.directory_is_writable(self.destination):
             self.notify('status', _('MP3 player opened'))
+            if gl.config.mp3_player_use_scrobbler_log:
+                mp3_player_mount_point = util.find_mount_point(self.destination)
+                # If a moint point cannot be found look inside self.destination for scrobbler_log_filenames
+                # this prevents us from os.walk()'ing the entire / filesystem
+                if mp3_player_mount_point == '/':
+                    mp3_player_mount_point = self.destination
+                log_location = self.find_scrobbler_log(mp3_player_mount_point)
+                if log_location is not None and self.load_audioscrobbler_log(log_location):
+                    log('Using Audioscrobbler log data to mark tracks as played', sender=self)
             return True
         else:
             return False
-    
+
     def add_track(self, episode):
         self.notify('status', _('Adding %s') % episode.title)
 
@@ -459,6 +473,11 @@
                 log('Cannot create folder on MP3 player: %s', folder, sender=self)
                 return False
 
+        if (gl.config.mp3_player_use_scrobbler_log and not episode.is_played()
+                and [episode.channel.title, episode.title] in self.scrobbler_log):
+            log('Marking "%s" from "%s" as played', episode.title, episode.channel.title, sender=self)
+            gl.history_mark_played(episode.url)
+
         if not os.path.exists(to_file):
             log('Copying %s => %s', os.path.basename(from_file), to_file.decode(self.enc), sender=self)
             return self.copy_file_progress(from_file, to_file)
@@ -545,3 +564,40 @@
         dotfiles = glob.glob(os.path.join(directory, '.*'))
         return len(files+dotfiles) == 0
 
+    def find_scrobbler_log(self, mount_point):
+        """ find an audioscrobbler log file from log_filenames in the mount_point dir """
+        for dirpath, dirnames, filenames in os.walk(mount_point):
+            for log_file in self.scrobbler_log_filenames:
+                filename = os.path.join(dirpath, log_file)
+                if os.path.isfile(filename):
+                    return filename
+
+        # No scrobbler log on that device
+        return None
+
+    def load_audioscrobbler_log(self, log_file):
+        """ Retrive track title and artist info for all the entries
+            in an audioscrobbler portable player format logfile
+            http://www.audioscrobbler.net/wiki/Portable_Player_Logging """
+        try:
+            log('Opening "%s" as AudioScrobbler log.', log_file, sender=self)
+            f = open(log_file, 'r')
+            entries = f.readlines()
+            f.close()
+        except IOError, ioerror:
+            log('Error: "%s" cannot be read.', log_file, sender=self)
+            return False
+
+        try:
+            # regex that can be used to get all the data from a scrobbler.log entry
+            entry_re = re.compile('^(.*)\t(.*)\t(.*)\t(.*)\t(.*)\t(.*)\t(.*)$')
+            for entry in entries:
+                match_obj = re.match(entry_re, entry)
+                # L means at least 50% of the track was listened to (S means < 50%)
+                if match_obj and match_obj.group(6).strip().lower() == 'l':
+                    # append [artist_name, track_name]
+                    self.scrobbler_log.append([match_obj.group(1), match_obj.group(3)])
+        except:
+            log('Error while parsing "%s".', log_file, sender=self)
+
+        return True
Index: src/gpodder/util.py
===================================================================
--- src/gpodder/util.py	(revision 643)
+++ src/gpodder/util.py	(working copy)
@@ -865,3 +865,20 @@
 
     return re.sub('[/|?*<>:+\[\]\"\\\]', '_', filename.strip().encode(enc, 'ignore'))
 
+
+def find_mount_point(directory):
+    """
+    Try to find the mount point for a given directory.
+    If the directory is itself a mount point, return
+    it. If not, remove the last part of the path and
+    re-check if it's a mount point. If the directory
+    resides on your root filesystem, "/" is returned.
+    """
+    while os.path.split(directory)[0] != '/':
+        if os.path.ismount(directory):
+            return directory
+        else:
+            (directory, tail_data) = os.path.split(directory)
+
+    return '/'
+
_______________________________________________
gpodder-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/gpodder-devel

Reply via email to