summaryrefslogtreecommitdiffstats
path: root/bindings
diff options
context:
space:
mode:
authorJorg Schuler <jcsjcs@users.sourceforge.net>2007-02-12 08:29:36 +0000
committerJorg Schuler <jcsjcs@users.sourceforge.net>2007-02-12 08:29:36 +0000
commit1317814f69500ba3c3a17a6d292c326149c0b0f6 (patch)
tree5e9f22a9f83af2ffc79ac1e09663d1e6a19f0100 /bindings
parent046b624301519f63c6d313b3934915aef659d61d (diff)
downloadlibgpod-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-xbindings/python/examples/add_song.py1
-rwxr-xr-xbindings/python/examples/create_mp3_tags_from_itdb.py27
-rw-r--r--bindings/python/gtkpod.py85
-rw-r--r--bindings/python/ipod.py135
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