summaryrefslogtreecommitdiffstats
path: root/bindings
diff options
context:
space:
mode:
authorNicholas Piper <nicholas@users.sourceforge.net>2007-03-26 14:00:54 +0000
committerNicholas Piper <nicholas@users.sourceforge.net>2007-03-26 14:00:54 +0000
commit18dc3bfea7dbfea9cf07e12cdcf494d9e03b45dd (patch)
treec4636cb882f9f090c5eb210d0dfd70be3f6b42de /bindings
parent8dc33f0a34224afc1c69797e2a09c39635ea357b (diff)
downloadlibgpod-18dc3bfea7dbfea9cf07e12cdcf494d9e03b45dd.tar.gz
libgpod-18dc3bfea7dbfea9cf07e12cdcf494d9e03b45dd.tar.xz
libgpod-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')
-rwxr-xr-xbindings/python/examples/save_photos.py39
-rw-r--r--bindings/python/gpod.i.in146
-rw-r--r--bindings/python/ipod.py246
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)