diff options
author | Jorg Schuler <jcsjcs@users.sourceforge.net> | 2007-02-12 08:29:36 +0000 |
---|---|---|
committer | Jorg Schuler <jcsjcs@users.sourceforge.net> | 2007-02-12 08:29:36 +0000 |
commit | 1317814f69500ba3c3a17a6d292c326149c0b0f6 (patch) | |
tree | 5e9f22a9f83af2ffc79ac1e09663d1e6a19f0100 /bindings | |
parent | 046b624301519f63c6d313b3934915aef659d61d (diff) | |
download | libgpod-tmz-1317814f69500ba3c3a17a6d292c326149c0b0f6.tar.gz libgpod-tmz-1317814f69500ba3c3a17a6d292c326149c0b0f6.tar.xz libgpod-tmz-1317814f69500ba3c3a17a6d292c326149c0b0f6.zip |
* ChangeLog
INSTALL_CVS
configure.ac
bindings/python/gtkpod.py
bindings/python/ipod.py
bindings/python/examples/add_song.py
bindings/python/examples/create_mp3_tags_from_itdb.py:
updates and fixes from Nicholas Piper.
git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1394 f01d2545-417e-4e96-918e-98f8d0dbbcb6
Diffstat (limited to 'bindings')
-rwxr-xr-x | bindings/python/examples/add_song.py | 1 | ||||
-rwxr-xr-x | bindings/python/examples/create_mp3_tags_from_itdb.py | 27 | ||||
-rw-r--r-- | bindings/python/gtkpod.py | 85 | ||||
-rw-r--r-- | bindings/python/ipod.py | 135 |
4 files changed, 118 insertions, 130 deletions
diff --git a/bindings/python/examples/add_song.py b/bindings/python/examples/add_song.py index c28fd4b..16c59f0 100755 --- a/bindings/python/examples/add_song.py +++ b/bindings/python/examples/add_song.py @@ -29,7 +29,6 @@ from optparse import OptionParser import urlparse, urllib2 import tempfile import shutil -import eyeD3 def download(path): print "Downloading %s" % path diff --git a/bindings/python/examples/create_mp3_tags_from_itdb.py b/bindings/python/examples/create_mp3_tags_from_itdb.py index 6315f2e..c33b7a8 100755 --- a/bindings/python/examples/create_mp3_tags_from_itdb.py +++ b/bindings/python/examples/create_mp3_tags_from_itdb.py @@ -29,7 +29,7 @@ # import gpod -import eyeD3 +import mutagen.mp3 # please specify your iPod mountpoint here.. IPOD_MOUNT = '/mnt/ipod/' @@ -51,22 +51,23 @@ for track in gpod.sw_get_tracks( itdb): filename = gpod.itdb_filename_on_ipod( track) try: - tag = eyeD3.Tag() - tag.link( filename) - if tag.link( filename) != True: + mp3 = mutagen.mp3.MP3(filename) + if not mp3.tags: print '' print '%s has no id3 tags' % ( filename ) print 'iTDB says: AR = %s, TI = %s, AL = %s' % ( track.artist, track.title, track.album ) - tag.setVersion( eyeD3.ID3_DEFAULT_VERSION) - tag.setArtist( track.artist) - tag.setAlbum( track.album) - tag.setTitle( track.title) - tag.addComment( 'tagged from itdb with libgpod') - tag.update() - counter_upd = counter_upd + 1 + mp3.add_tags() # create header + mp3.tags.add(mutagen.id3.TPE1(3,track.artist)) + mp3.tags.add(mutagen.id3.TALB(3,track.album)) + mp3.tags.add(mutagen.id3.TIT2(3,track.title)) + mp3.tags.add(mutagen.id3.TXXX(3,"Taggger","tagged from itdb with libgpod")) + mp3.save() + counter_upd += 1 print 'wrote tags to: %s' % ( filename ) - except: - print 'informative debug output: something went wrong.. :/' + else: + counter_left += 1 + except Exception, e: + print 'informative debug output: something went wrong.. : %s' % e counter_left = counter_left + 1 print '' diff --git a/bindings/python/gtkpod.py b/bindings/python/gtkpod.py index 09d222c..64e50f2 100644 --- a/bindings/python/gtkpod.py +++ b/bindings/python/gtkpod.py @@ -2,16 +2,11 @@ import sha import os -import socket import types -import locale # This file is originally stolen from pypod-0.5.0 # http://superduper.net/index.py?page=pypod -# I hope that's ok, both works are GPL. - -hostname = socket.gethostname() -defaultencoding = locale.getpreferredencoding() +# and reworked significantly since then. class ParseError(Exception): """Exception for parse errors.""" @@ -45,18 +40,9 @@ def write(filename, db, itunesdb_file): file = open(filename, "w") def write_pair(name, value): - if isinstance(value,types.UnicodeType): - # encode as UTF-8 - value = value.encode("utf-8") - elif isinstance(value,types.StringType): - # assume it's in our default locale, so decode - # then re-encode as UTF-8 - value = unicode(value, - defaultencoding).encode("utf-8") - else: + if type(value) not in (types.StringType, types.UnicodeType): + # e.g., an integer value = str(value) - - file.write("=".join([name, value])) file.write('\n') @@ -67,23 +53,6 @@ def write(filename, db, itunesdb_file): write_pair("id", track['id']) if not track['userdata']: track['userdata'] = {} - if track['ipod_path']: - track['userdata']['filename_ipod'] = track['ipod_path'] - hash_name = 'sha1_hash' - try: - del track['userdata'][hash_name] - except KeyError: - # recent gpod uses sha1_hash, older uses md5_hash - try: - del track['userdata'][hash_name] - hash_name = 'md5_hash' - except KeyError: - # we'll just write a sha1_hash then - pass - if track['userdata'].has_key('filename_locale') and not track['userdata'].has_key(hash_name): - if os.path.exists(track['userdata']['filename_locale']): - track['userdata'][hash_name] = sha1_hash( - track['userdata']['filename_locale']) [write_pair(i[0],i[1]) for i in track['userdata'].items()] write_pair("id", "xxx") @@ -98,44 +67,42 @@ def parse(filename, db, itunesdb_file=None): """ - tracks_by_id = {} - tracks_by_sha = {} - id = 0 - ext_hash_valid = True - - for track in db: - track['userdata'] = {} - - for track in db: - tracks_by_id[track['id']] = track - - track = None - file = open(filename) + ext_hash_valid = False ext_data = {} - ext_block = None - for line in file: + + for line in open(filename).readlines(): parts = line.strip().split("=", 1) if len(parts) != 2: print parts name, value = parts if name == "id": - if ext_block: - ext_data[id] = ext_block - if value != 'xxx': - id = int(value) - ext_block = {} + if value == 'xxx': + break + id = int(value) + ext_data[id] = {} elif name == "version": pass elif name == "itunesdb_hash": - if itunesdb_file and sha1_hash(itunesdb_file) != value: - ext_hash_valid = False + if itunesdb_file and sha1_hash(itunesdb_file) == value: + ext_hash_valid = True else: - ext_block[name] = value + # value is a string of undetermined encoding at the moment + ext_data[id][name] = value + # now add each extended info block to the track it goes with + # equiv. of fill_in_extended_info() if ext_hash_valid: - for id,ext_block in ext_data.items(): - tracks_by_id[id]['userdata'] = ext_block + # the normal case + for track in db: + try: + track['userdata'] = ext_data[track['id']] + except KeyError: + # no userdata available... + track['userdata'] = {} else: + # the iTunesDB was changed, so id's will be wrong. + # match up using hash instead + tracks_by_sha = {} for track in db: # make a dict to allow us to find each track by the sha1_hash tracks_by_sha[sha1_hash(track.ipod_filename())] = track diff --git a/bindings/python/ipod.py b/bindings/python/ipod.py index c917bef..af1c5e4 100644 --- a/bindings/python/ipod.py +++ b/bindings/python/ipod.py @@ -7,9 +7,14 @@ classes and methods provided here. import gpod import types -import eyeD3 +from mutagen.mp3 import MP3 +import mutagen.id3 import gtkpod import os +import locale +import socket + +defaultencoding = locale.getpreferredencoding() class DatabaseException(RuntimeError): """Exception for database errors.""" @@ -159,7 +164,7 @@ class Database: pl.remove(item) if harddisk: try: - filename = item['userdata']['filename_locale'] + filename = item._userdata_into_default_locale('filename') except KeyError, e: raise TrackException("Unable to remove %s from hard disk, no filename available." % item) os.unlink(filename) @@ -238,7 +243,7 @@ class Database: for track in self: try: transferred = int(track['userdata']['transferred']) - except KeyError: + except (KeyError, TypeError): transferred = 1 if not transferred: to_copy.append(track) @@ -283,7 +288,7 @@ class Track: "chapterdata_raw","chapterdata_raw_length","artwork", "usertype") - def __init__(self, filename=None, from_file=None, + def __init__(self, filename=None, proxied_track=None, podcast=False, ownerdb=None): """Create a Track object. @@ -298,52 +303,44 @@ class Track: """ - # XXX couldn't from_file and filename be merged? - if from_file: - filename = from_file if filename: self._track = gpod.itdb_track_new() - self['userdata'] = {'filename_locale': filename, - 'transferred': 0} + self['userdata'] = {'transferred': 0, + 'hostname': socket.gethostname(), + 'charset':defaultencoding} + self['userdata']['pc_mtime'] = os.stat(filename).st_mtime + self._set_userdata_utf8('filename',filename) + possible_image = os.path.join(os.path.split(filename)[0],'folder.jpg') + if os.path.exists(possible_image): + self.set_thumbnail(possible_image) try: - audiofile = eyeD3.Mp3AudioFile(self['userdata']['filename_locale']) - except eyeD3.tag.InvalidAudioFormatException, e: + audiofile = MP3(self._userdata_into_default_locale('filename')) + except Exception, e: raise TrackException(str(e)) - tag = audiofile.getTag() - for func, attrib in (('getArtist','artist'), - ('getTitle','title'), - ('getBPM','BPM'), - ('getPlayCount','playcount'), - ('getAlbum','album')): + for tag, attrib in (('TPE1','artist'), + ('TIT2','title'), + ('TBPM','BPM'), + ('TCON','genre'), + ('TALB','album'), + ('TPOS',('cd_nr','cds')), + ('TRCK',('track_nr','tracks'))): try: - value = getattr(tag,func)() - if value: - self[attrib] = value - except AttributeError: + value = audiofile[tag] + if isinstance(value,mutagen.id3.NumericPartTextFrame): + parts = map(int,value.text[0].split("/")) + if len(parts) == 2: + self[attrib[0]], self[attrib[1]] = parts + elif len(parts) == 1: + self[attrib[0]] = parts[0] + elif isinstance(value,mutagen.id3.TextFrame): + self[attrib] = value.text[0].encode('UTF-8','replace') + except KeyError: pass if self['title'] is None: - self['title'] = os.path.splitext(os.path.split(filename)[1])[0] - try: - self['genre'] = tag.getGenre().name - except AttributeError: - pass - try: - disc, of = tag.getDiscNum() - if disc is not None: - self['cd_nr'] = disc - if of is not None: - self['cds'] = of - except AttributeError: - pass - try: - n, of = tag.getTrackNum() - if n is not None: - self['track_nr'] = n - if of is not None: - self['tracks'] = of - except AttributeError: - pass - self['tracklen'] = audiofile.getPlayTime() * 1000 + self['title'] = os.path.splitext( + os.path.split(filename)[1])[0].decode( + defaultencoding).encode('UTF-8') + self['tracklen'] = int(audiofile.info.length * 1000) self.set_podcast(podcast) elif proxied_track: self._track = proxied_track @@ -352,18 +349,47 @@ class Track: self._track = gpod.itdb_track_new() self.set_podcast(podcast) + def _set_userdata_utf8(self, key, value): + self['userdata']['%s_locale' % key] = value + try: + self['userdata']['%s_utf8' % key] = value.decode(self['userdata']['charset']).encode('UTF-8') + except UnicodeDecodeError, e: + # string clearly isn't advertised charset. I prefer to + # not add the _utf8 version as we can't actually generate + # it. Maybe we'll have to populate a close-fit though. + pass + + def _userdata_into_default_locale(self, key): + # to cope with broken filenames, we should trust the _locale version more, + # an even that may not really be in self['userdata']['charset'] + if self['userdata']['charset'] == defaultencoding: + # don't try translate it or check it's actually valid, in case it isn't. + return self['userdata']['%s_locale' % key] + # our filesystem is in a different encoding to the filename, so + # try to convert it. The UTF-8 version is likely best to try first? + if self['userdata'].has_key('%s_utf8' % key): + unicode_value = self['userdata']['%s_utf8' % key].decode('UTF-8') + else: + unicode_value = self['userdata']['%s_locale' % key].decode(self['userdata']['charset']) + return unicode_value.encode(defaultencoding) + + def set_thumbnail(self, filename): + gpod.itdb_track_set_thumbnails(self._track, filename) + self._set_userdata_utf8('thumbnail', filename) + def copy_to_ipod(self): """Copy the track to the iPod.""" - self['userdata']['md5_hash'] = gtkpod.sha1_hash( - self['userdata']['filename_locale']) + self['userdata']['sha1_hash'] = gtkpod.sha1_hash(self._userdata_into_default_locale('filename')) if not gpod.itdb_get_mountpoint(self._track.itdb): return False - self['userdata']['transferred'] = 1 if gpod.itdb_cp_track_to_ipod(self._track, - self['userdata']['filename_locale'], None) != 1: + self._userdata_into_default_locale('filename'), + None) != 1: raise TrackException('Unable to copy %s to iPod as %s' % ( - self['userdata']['filename_locale'], + self._userdata_into_default_locale('filename'), self)) + self['userdata']['transferred'] = 1 + self['userdata']['filename_ipod'] = self.ipod_filename() return True def ipod_filename(self): @@ -422,20 +448,17 @@ class Track: raise KeyError('No such key: %s' % item) def __setitem__(self, item, value): - #print item, value if item == "userdata": gpod.sw_set_track_userdata(self._track, value) return if type(value) == types.UnicodeType: - value = value.encode('UTF-8','ignore') + value = value.encode('UTF-8','replace') if item in self._proxied_attributes: return setattr(self._track, item, value) else: raise KeyError('No such key: %s' % item) -# XXX would this be better as a public variable so that the docs would -# list valid sort order values? -_playlist_sorting = { +playlist_sorting = { 1:'playlist', 2:'unknown2', 3:'songtitle', @@ -619,14 +642,12 @@ class Playlist: def get_sort(self): """Get the sort order for the playlist.""" - return _playlist_sorting[self._pl.sortorder] + return playlist_sorting[self._pl.sortorder] - # XXX how does one find out what values are allowed for order without - # poking into this file? (See similar question @ _playlist_order) def set_sort(self, order): """Set the sort order for the playlist.""" order = order.lower() - for k, v in _playlist_sorting.items(): + for k, v in playlist_sorting.items(): if v == order: self._pl.sortorder = v return |