diff options
-rw-r--r-- | bindings/python/Makefile.am | 9 | ||||
-rw-r--r-- | bindings/python/examples/Makefile.am | 4 | ||||
-rwxr-xr-x | bindings/python/examples/playwith_ipod_api.py | 14 | ||||
-rw-r--r-- | bindings/python/gpod.i | 32 | ||||
-rw-r--r-- | bindings/python/ipod.py | 147 |
5 files changed, 203 insertions, 3 deletions
diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am index af4e9e1..8dba92c 100644 --- a/bindings/python/Makefile.am +++ b/bindings/python/Makefile.am @@ -1,7 +1,8 @@ SUBDIRS = examples EXTRA_DIST = \ - gpod.i + gpod.i \ + ipod.py CLEANFILES = \ *.py* \ @@ -31,9 +32,13 @@ install-pythonDATA: $(python_DATA) $(mkinstalldirs) $(DESTDIR)$(pythondir) $(INSTALL_PROGRAM) _gpod.so $(DESTDIR)$(pythondir)/_gpod.so $(INSTALL_DATA) gpod.py $(DESTDIR)$(pythondir)/gpod.py + $(INSTALL_DATA) ipod.py $(DESTDIR)$(pythondir)/ipod.py $(PYTHON) -c 'from py_compile import compile; compile("$(DESTDIR)$(pythondir)/gpod.py")' $(PYTHON) -O -c 'from py_compile import compile; compile("$(DESTDIR)$(pythondir)/gpod.py")' + $(PYTHON) -c 'from py_compile import compile; compile("$(DESTDIR)$(pythondir)/ipod.py")' + $(PYTHON) -O -c 'from py_compile import compile; compile("$(DESTDIR)$(pythondir)/ipod.py")' uninstall-pythonDATA: $(python_DATA) - rm -f $(DESTDIR)$(pythondir)/_gpod.so $(DESTDIR)$(pythondir)/gpod.py + rm -f $(DESTDIR)$(pythondir)/_gpod.so + rm -f $(DESTDIR)$(pythondir)/gpod.py $(DESTDIR)$(pythondir)/ipod.py endif diff --git a/bindings/python/examples/Makefile.am b/bindings/python/examples/Makefile.am index 93cf41c..89f76fc 100644 --- a/bindings/python/examples/Makefile.am +++ b/bindings/python/examples/Makefile.am @@ -1,2 +1,4 @@ -EXTRA_DIST = coverart_fetch.py toy_around.py tag_genre_from_audioscrobber.py add_song.py +EXTRA_DIST = coverart_fetch.py toy_around.py \ + tag_genre_from_audioscrobber.py add_song.py \ + playwith_ipod_api.py diff --git a/bindings/python/examples/playwith_ipod_api.py b/bindings/python/examples/playwith_ipod_api.py new file mode 100755 index 0000000..544de5b --- /dev/null +++ b/bindings/python/examples/playwith_ipod_api.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +import ipod + +db = ipod.Database() + +for track in db[4:20]: + print track + print track['title'] + +filename = "/mp3/Blondie/No_Exit/Blondie_-_Maria.mp3" +t = ipod.Track(from_file=filename) +print t + diff --git a/bindings/python/gpod.i b/bindings/python/gpod.i index 1c0edc7..7103ecf 100644 --- a/bindings/python/gpod.i +++ b/bindings/python/gpod.i @@ -49,6 +49,20 @@ PyObject* sw_get_tracks(Itdb_iTunesDB *itdb) { return list; } +PyObject* sw_get_track(GList *list, gint index) { + GList *position; + if ( (index >= g_list_length(list)) || index < 0 ) { + PyErr_SetString(PyExc_IndexError, "Value out of range"); + return NULL; + } + position = g_list_nth(list, index); + return SWIG_NewPointerObj((void*)(position->data), SWIGTYPE_p__Itdb_Track, 0); + } + +PyObject* sw_get_list_len(GList *list) { + return PyInt_FromLong(g_list_length(list)); + } + PyObject* sw_get_playlist_tracks(Itdb_Playlist *pl) { PyObject *list; gint i; @@ -88,12 +102,28 @@ typedef char gchar; } } +%typemap(out) guint64 { + $result = PyLong_FromLong($1); +} + +%typemap(out) guint32 { + $result = PyInt_FromLong($1); +} + +%typemap(out) guint16 { + $result = PyInt_FromLong($1); +} + + %typemap(out) guint8 { $result = PyInt_FromLong($1); } typedef int gboolean; +typedef long gint64; typedef int gint32; +typedef int gint16; +typedef int gint; typedef unsigned int guint32; @@ -101,6 +131,8 @@ typedef unsigned int guint32; #define G_END_DECLS PyObject* sw_get_tracks(Itdb_iTunesDB *itdb); +PyObject* sw_get_track(GList *list, gint index); +PyObject* sw_get_list_len(GList *list); PyObject* sw_get_playlists(Itdb_iTunesDB *itdb); PyObject* sw_get_playlist_tracks(Itdb_Playlist *pl); %include "../../src/itdb.h" diff --git a/bindings/python/ipod.py b/bindings/python/ipod.py new file mode 100644 index 0000000..3e98310 --- /dev/null +++ b/bindings/python/ipod.py @@ -0,0 +1,147 @@ +# This isn't even really started. + +import gpod +import types +import eyeD3 + +class DatabaseException(RuntimeError): + pass + +class TrackException(RuntimeError): + pass + +class Database: + def __init__(self, mountpoint="/mnt/ipod"): + self._itdb = itdb = gpod.itdb_parse(mountpoint, + None) + if not self._itdb: + raise DatabaseException("Unable to parse iTunes database at mount point %s" % mountpoint) + else: + self._itdb.mountpoint = mountpoint + + def close(self): + if not gpod.itdb_write(self._itdb, None): + raise DatabaseException("Unable to save iTunes database at %s" % mountpoint) + + def __getitem__(self, index): + if type(index) == types.SliceType: + return [self[i] for i in xrange(*index.indices(len(self)))] + else: + if index < 0: + index += len(self) + return Track(proxied_track=gpod.sw_get_track(self._itdb.tracks, index)) + + def __len__(self): + return gpod.sw_get_list_len(self._itdb.tracks) + + def import_file(self, filename): + track = Track(filename) + track.copy_to_ipod() + gpod.itdb_playlist_add_track(gpod.itdb_playlist_mpl(self._itdb), + track._track, -1) + + +class Track: + _proxied_attributes = ("title","ipod_path","album","artist","genre","filetype", + "comment","category","composer","grouping","description", + "podcasturl","podcastrss","chapterdata","subtitle","id", + "size","tracklen","cd_nr","cds","track_nr","tracks", + "bitrate","samplerate","samplerate_low","year","volume", + "soundcheck","time_added","time_played","time_modified", + "bookmark_time","rating","playcount","playcount2", + "recent_playcount","transferred","BPM","app_rating", + "type1","type2","compilation","starttime","stoptime", + "checked","dbid","drm_userid","visible","filetype_marker", + "artwork_count","artwork_size","samplerate2", + "time_released","has_artwork","flag1","flag2","flag3","flag4", + "lyrics_flag","movie_flag","mark_unplayed","samplecount", + "chapterdata_raw","chapterdata_raw_length","artwork", + "usertype","userdata","userdata_duplicate","userdata_destroy") + + def __init__(self, from_file=None, proxied_track=None, podcast=False): + self._ondiskfilename = None + if from_file: + self._ondiskfilename = from_file + self._track = gpod.itdb_track_new() + audiofile = eyeD3.Mp3AudioFile(self._ondiskfilename) + tag = audiofile.getTag() + print dir(tag) + for func, attrib in (('getArtist','artist'), + ('getTitle','title'), + ('getBPM','BPM'), + ('getPlayCount','playcount'), + ('getAlbum','album')): + value = getattr(tag,func)() + if value: + self[attrib] = value + self['genre'] = tag.getGenre().name + disc, of = tag.getDiscNum() + if disc is not None: + self['cd_nr'] = disc + if of is not None: + self['cds'] = of + n, of = tag.getTrackNum() + if n is not None: + self['track_nr'] = n + if of is not None: + self['tracks'] = of + self['tracklen'] = audiofile.getPlayTime() * 1000 + elif proxied_track: + self._track = proxied_track + else: + self._track = gpod.itdb_track_new() + self.set_podcast(podcast) + + def copy_to_ipod(self): + if gpod.itdb_cp_track_to_ipod(self._track, self._ondiskfilename, None) != 1: + raise TrackException('Unable to copy %s to iPod as %s' % (self._ondiskfilename, + self)) + + def set_podcast(self, value): + if value: + self['flag1'] = 0x02 # unknown + self['flag2'] = 0x01 # skip when shuffling + self['flag3'] = 0x01 # remember playback position + self['flag4'] = 0x01 # Show Title/Album on the 'Now Playing' page + else: + self['flag1'] = 0x02 # unknown + self['flag2'] = 0x00 # do not skip when shuffling + self['flag3'] = 0x00 # do not remember playback position + self['flag4'] = 0x00 # Show Title/Album/Artist on the 'New Playing' page + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return "<Track Artist:%s Title:%s Album:%s>" % ( + repr(self['artist']), + repr(self['title']), + repr(self['album'])) + + def keys(self): + return list(self._proxied_attributes) + + def items(self): + return [self[k] for k in self._proxied_attributes] + + def pairs(self): + return [(k, self[k]) for k in self._proxied_attributes] + + def __getitem__(self, item): + if item in self._proxied_attributes: + return getattr(self._track, item) + else: + raise KeyError('No such key: %s' % item) + + def __setitem__(self, item, value): + #print item, value + if type(value) == types.UnicodeType: + value = value.encode() + if item in self._proxied_attributes: + return setattr(self._track, item, value) + else: + raise KeyError('No such key: %s' % item) + + +class Playlist: + pass |