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