diff options
author | Nicholas Piper <nicholas@users.sourceforge.net> | 2007-03-26 14:00:54 +0000 |
---|---|---|
committer | Nicholas Piper <nicholas@users.sourceforge.net> | 2007-03-26 14:00:54 +0000 |
commit | 18dc3bfea7dbfea9cf07e12cdcf494d9e03b45dd (patch) | |
tree | c4636cb882f9f090c5eb210d0dfd70be3f6b42de /bindings/python | |
parent | 8dc33f0a34224afc1c69797e2a09c39635ea357b (diff) | |
download | libgpod-tmz-18dc3bfea7dbfea9cf07e12cdcf494d9e03b45dd.tar.gz libgpod-tmz-18dc3bfea7dbfea9cf07e12cdcf494d9e03b45dd.tar.xz libgpod-tmz-18dc3bfea7dbfea9cf07e12cdcf494d9e03b45dd.zip |
Add some PhotoDB reading features, thanks to John Carr for prompting.
git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1410 f01d2545-417e-4e96-918e-98f8d0dbbcb6
Diffstat (limited to 'bindings/python')
-rwxr-xr-x | bindings/python/examples/save_photos.py | 39 | ||||
-rw-r--r-- | bindings/python/gpod.i.in | 146 | ||||
-rw-r--r-- | bindings/python/ipod.py | 246 |
3 files changed, 428 insertions, 3 deletions
diff --git a/bindings/python/examples/save_photos.py b/bindings/python/examples/save_photos.py new file mode 100755 index 0000000..abf23ed --- /dev/null +++ b/bindings/python/examples/save_photos.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +## Copyright (C) 2007 Nick Piper <nick-gtkpod at nickpiper co uk> +## Part of the gtkpod project. + +## URL: http://www.gtkpod.org/ +## URL: http://gtkpod.sourceforge.net/ + +## The code contained in this file is free software; you can redistribute +## it and/or modify it under the terms of the GNU Lesser General Public +## License as published by the Free Software Foundation; either version +## 2.1 of the License, or (at your option) any later version. + +## This file is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## Lesser General Public License for more details. + +## You should have received a copy of the GNU Lesser General Public +## License along with this code; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# this file is just a little example to see how you could read photos + +import gpod + +photodb = gpod.PhotoDatabase("/mnt/ipod") + +print photodb +for album in photodb.PhotoAlbums: + print " ", album + for photo in album: + print " ", photo + for thumbnail, n in zip(photo.thumbnails, + range(0,len(photo.thumbnails))): + print " ", thumbnail + thumbnail.save_image("/tmp/%d-%d.png" % (photo['id'],n)) + +photodb.close() diff --git a/bindings/python/gpod.i.in b/bindings/python/gpod.i.in index a908e02..dce072b 100644 --- a/bindings/python/gpod.i.in +++ b/bindings/python/gpod.i.in @@ -1,7 +1,7 @@ /* File : gpod.i.in */ /* - Copyright (C) 2005 Nick Piper <nick-gtkpod at nickpiper co uk> + Copyright (C) 2007 Nick Piper <nick-gtkpod at nickpiper co uk> Part of the gtkpod project. URL: http://www.gtkpod.org/ @@ -46,7 +46,9 @@ interface." #include "db-itunes-parser.h" #include "db-parse-context.h" #include "itdb.h" +#include "itdb_device.h" #include "itdb_private.h" +#include <gdk-pixbuf/gdk-pixbuf.h> /* include prototypes for all functions so builds using * -Wmissing-prototypes don't fail. */ @@ -59,8 +61,17 @@ PyObject* sw_get_playlists(Itdb_iTunesDB *itdb); PyObject* sw_get_playlist_tracks(Itdb_Playlist *pl); PyObject* sw_set_track_userdata(Itdb_Track *track, PyObject *data); PyObject* sw_get_track_userdata(Itdb_Track *track); -PyObject *sw__track_extra_duplicate (PyObject *data); +PyObject* sw__track_extra_duplicate (PyObject *data); +PyObject* sw_get_photoalbums(Itdb_PhotoDB *db); +PyObject* sw_get_photoalbum(GList *list, gint index); +PyObject* sw_get_photos(Itdb_PhotoDB *db); +PyObject* sw_get_photo(GList *list, gint index); +PyObject* sw_get_artwork_thumbnails(Itdb_Artwork *artwork); +PyObject* sw_get_photoalbum_members(Itdb_PhotoAlbum *album); +PyObject* sw_ipod_device_to_dict(Itdb_Device *device); +PyObject* sw_save_itdb_thumb(Itdb_PhotoDB *itdb, Itdb_Thumb *thumb, const gchar *filename); void sw__track_extra_destroy (PyObject *data); +void hash_table_to_pydict(gpointer key, gpointer value, gpointer user_data); void SWIG_init(void); PyObject* sw_get_tracks(Itdb_iTunesDB *itdb) { @@ -169,8 +180,125 @@ PyObject* sw_get_playlists(Itdb_iTunesDB *itdb) { return Py_None; } } + + PyObject* sw_get_photoalbums(Itdb_PhotoDB *db) { + PyObject *list; + gint i; + GList *l; + list = PyList_New(g_list_length(db->photoalbums)); + for (l = db->photoalbums, i = 0; l; l = l->next, ++i) { + PyList_SET_ITEM(list, i, SWIG_NewPointerObj((void*)(l->data), +SWIGTYPE_p__Itdb_PhotoAlbum, 0)); + } + return list; + } + + PyObject* sw_get_artwork_thumbnails(Itdb_Artwork *artwork) { + PyObject *list; + gint i; + GList *l; + list = PyList_New(g_list_length(artwork->thumbnails)); + for (l = artwork->thumbnails, i = 0; l; l = l->next, ++i) { + PyList_SET_ITEM(list, i, SWIG_NewPointerObj((void*)(l->data), SWIGTYPE_p__Itdb_Thumb, 0)); + } + return list; + } + + +PyObject* sw_get_photoalbum(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_PhotoAlbum, 0); + } + + PyObject* sw_get_photoalbum_members(Itdb_PhotoAlbum *album) { + PyObject *list; + gint i; + GList *l; + list = PyList_New(g_list_length(album->members)); + for (l = album->members, i = 0; l; l = l->next, ++i) { + gint photo_id = GPOINTER_TO_INT(l->data); + PyList_SET_ITEM(list, i, PyInt_FromLong((long)photo_id)); + } + return list; + } + + PyObject* sw_get_photos(Itdb_PhotoDB *db) { + PyObject *list; + gint i; + GList *l; + list = PyList_New(g_list_length(db->photos)); + for (l = db->photos, i = 0; l; l = l->next, ++i) { + PyList_SET_ITEM(list, i, SWIG_NewPointerObj((void*)(l->data), +SWIGTYPE_p__Itdb_Artwork, 0)); + } + return list; + } + +PyObject* sw_get_photo(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_Artwork, 0); + } + + void hash_table_to_pydict(gpointer key, + gpointer value, + gpointer user_data) { + PyDict_SetItemString((PyObject *)user_data, + (char *)key, + PyString_FromString(value)); + } + + PyObject* sw_ipod_device_to_dict(Itdb_Device *device) { + PyObject* sysinfo; + if (device == NULL) { + Py_INCREF(Py_None); + return Py_None; + } else { + sysinfo = PyDict_New(); + g_hash_table_foreach(device->sysinfo, + hash_table_to_pydict, + (gpointer) sysinfo); + return Py_BuildValue("{s:s,s:i,s:i,s:O}", + "mountpoint", + device->mountpoint, + "musicdirs", + device->musicdirs, + "byte_order", + device->byte_order, + "sysinfo", + sysinfo); + } + } + + PyObject* sw_save_itdb_thumb(Itdb_PhotoDB *itdb, Itdb_Thumb *thumb, const gchar *filename) { + GdkPixbuf *pixbuf; + + pixbuf = itdb_thumb_get_gdk_pixbuf (itdb->device, thumb); + + if (pixbuf != NULL) { + gdk_pixbuf_save (pixbuf, filename, "png", NULL, NULL); + gdk_pixbuf_unref (pixbuf); + Py_INCREF(Py_True); + return Py_True; + } else { + Py_INCREF(Py_False); + return Py_False; + } + } - +%} + +%init %{ + g_type_init (); %} %include "gpod_doc.i" @@ -287,6 +415,10 @@ typedef char gchar; $result = PyLong_FromUnsignedLong($1); } +%typemap(out) gint16 { + $result = PyLong_FromLong($1); +} + %typemap(out) guint8 { $result = PyInt_FromLong($1); } @@ -306,5 +438,13 @@ PyObject* sw_get_playlists(Itdb_iTunesDB *itdb); PyObject* sw_get_playlist_tracks(Itdb_Playlist *pl); PyObject* sw_set_track_userdata(Itdb_Track *track, PyObject *data); PyObject* sw_get_track_userdata(Itdb_Track *track); +PyObject* sw_get_photoalbums(Itdb_PhotoDB *db); +PyObject* sw_get_photoalbum(GList *list, gint index); +PyObject* sw_get_photos(Itdb_PhotoDB *db); +PyObject* sw_get_photo(GList *list, gint index); +PyObject* sw_get_photoalbum_members(Itdb_PhotoAlbum *album); +PyObject* sw_get_artwork_thumbnails(Itdb_Artwork *artwork); +PyObject* sw_ipod_device_to_dict(Itdb_Device *device); +PyObject* sw_save_itdb_thumb(Itdb_PhotoDB *itdb, Itdb_Thumb *thumb, const gchar *filename); %include "@top_srcdir@/src/itdb.h" diff --git a/bindings/python/ipod.py b/bindings/python/ipod.py index af1c5e4..199efb1 100644 --- a/bindings/python/ipod.py +++ b/bindings/python/ipod.py @@ -13,6 +13,7 @@ import gtkpod import os import locale import socket +import datetime defaultencoding = locale.getpreferredencoding() @@ -24,6 +25,10 @@ class TrackException(RuntimeError): """Exception for track errors.""" pass +class PhotoException(RuntimeError): + """Exception for track errors.""" + pass + class Database: """An iTunes database. @@ -717,3 +722,244 @@ class Playlist: gpod.itdb_playlist_remove_track(self._pl, track._track) else: raise DatabaseException("Playlist %s does not contain %s" % (self, track)) + +class PhotoDatabase: + """An iTunes Photo database""" + def __init__(self, mountpoint="/mnt/ipod"): + """Create a Photo database object""" + self._itdb = gpod.itdb_photodb_parse(mountpoint, None) + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return "<PhotoDatabase Mountpoint:%s Albums:%s Photos:%s>" % ( + repr(self.device['mountpoint']), + gpod.sw_get_list_len(self._itdb.photoalbums), + len(self)) + + def close(self): + pass + + def __len__(self): + return gpod.sw_get_list_len(self._itdb.photos) + + 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 Photo(proxied_photo=gpod.sw_get_photo(self._itdb.photos, index), + ownerdb=self) + def get_device(self): + return gpod.sw_ipod_device_to_dict(self._itdb.device) + + def get_photoalbums(self): + """Get all photo albums.""" + return _PhotoAlbums(self) + + PhotoAlbums = property(get_photoalbums) + device = property(get_device) + +class _PhotoAlbums: + def __init__(self, db): + self._db = db + + def __len__(self): + return gpod.sw_get_list_len(self._db._itdb.photoalbums) + + def __nonzero__(self): + return True + + 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 PhotoAlbum(self._db, + proxied_photoalbum=gpod.sw_get_photoalbum(self._db._itdb.photoalbums, + index)) + + def __repr__(self): + return "<PhotoAlbums from %s>" % self._db + + def __call__(self, name): + if type(name) in (types.TupleType, types.ListType): + return [self.__call__(name=i) for i in name] + else: + pa = gpod.itdb_photodb_photoalbum_by_name(self._db._itdb, + name) + if pa: + return PhotoAlbum(self._db, + proxied_playlist=pa) + else: + raise KeyError("Album with name %s not found." % repr(name)) + + +class PhotoAlbum: + """A Photo Album in an iTunes database.""" + + def __init__(self, parent_db, title="New Album", + pos=-1, proxied_photoalbum=None): + + self._db = parent_db + if proxied_photoalbum: + self._pa = proxied_photoalbum + else: + raise NotImplemented("Can't create new Photo Albums yet") + + def get_name(self): + """Get the name of the photo album.""" + return self._pa.name + + def set_name(self, name): + """Set the name for the photo album.""" + self._pa.name = name + + def get_album_type(self): + return self._pa.album_type + + name = property(get_name, set_name) + album_type = property(get_album_type) + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return "<PhotoAlbum Title:%s Photos:%d Type:%d>" % ( + repr(self.name), + len(self), + self.album_type) + + 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 Photo(proxied_photo=gpod.sw_get_photo(self._pa.members, index), + ownerdb=self._db) + + def __len__(self): + return gpod.sw_get_list_len(self._pa.members) + + def __nonzero__(self): + return True + +class Photo: + """A photo in an iTunes Photo database.""" + + _proxied_attributes = ("id","creation_date","digitized_date","artwork_size") + + def __init__(self, filename=None, + proxied_photo=None, ownerdb=None): + """Create a Photo object.""" + + if filename: + # maybe use itdb_photodb_add_photo ? + raise NotImplemented("Can't create new Photos from files yet") + elif proxied_photo: + self._photo = proxied_photo + self._database = ownerdb + else: + self._photo = gpod.itdb_artwork_new() + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return "<Photo ID:%s Creation:'%s' Digitized:'%s' Size:%s>" % ( + repr(self['id']), + self['creation_date'].strftime("%c"), + self['digitized_date'].strftime("%c"), + repr(self['artwork_size'])) + + 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: + attr = getattr(self._photo, item) + if item.endswith("_date"): + try: + return datetime.datetime.fromtimestamp(attr) + except: + return datetime.datetime.fromtimestamp(0) + else: + return attr + else: + raise KeyError('No such key: %s' % item) + + def __setitem__(self, item, value): + if type(value) == types.UnicodeType: + value = value.encode('UTF-8','replace') + if item in self._proxied_attributes: + return setattr(self._photo, item, value) + else: + raise KeyError('No such key: %s' % item) + + def get_thumbnails(self): + return [Thumbnail(proxied_thumbnail=t, ownerphoto=self) for t in gpod.sw_get_artwork_thumbnails(self._photo)] + + thumbnails = property(get_thumbnails) + +class Thumbnail: + """A thumbnail in an Photo.""" + + _proxied_attributes = ("type","filename","rotation","offset","size","width","height", + "horizontal_padding", "vertical_padding") + + def __init__(self, proxied_thumbnail=None, ownerphoto=None): + """Create a thumbnail object.""" + + if not proxied_thumbnail: + raise NotImplemented("Can't create new Thumbnails from scratch, create Photos instead") + + self._thumbnail = proxied_thumbnail + self.__photo = ownerphoto # so the photo doesn't get gc'd + + def __str__(self): + return self.__repr__() + + def __repr__(self): + return "<Thumbnail Filename:%s Size:%d Width:%d Height:%d>" % ( + repr(self['filename']), + self['size'], + self['width'], + self['height']) + + 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._thumbnail, item) + else: + raise KeyError('No such key: %s' % item) + + def __setitem__(self, item, value): + if type(value) == types.UnicodeType: + value = value.encode('UTF-8','replace') + if item in self._proxied_attributes: + return setattr(self._thumbnail, item, value) + else: + raise KeyError('No such key: %s' % item) + + def save_image(self,filename): + return gpod.sw_save_itdb_thumb( + self.__photo._database._itdb, + self._thumbnail,filename) |