summaryrefslogtreecommitdiffstats
path: root/bindings
diff options
context:
space:
mode:
authorTodd Zullinger <tmzullinger@users.sourceforge.net>2007-07-31 20:42:54 +0000
committerTodd Zullinger <tmzullinger@users.sourceforge.net>2007-07-31 20:42:54 +0000
commit6dda4b59bb0f788da38823a035f28d4c515a38be (patch)
tree16f02c91b9efa543e3f4daab4b1bbcf3d88859f6 /bindings
parentbd2fc5d392af67e46ee0fe8bf31b4f9e457f2da3 (diff)
downloadlibgpod-6dda4b59bb0f788da38823a035f28d4c515a38be.tar.gz
libgpod-6dda4b59bb0f788da38823a035f28d4c515a38be.tar.xz
libgpod-6dda4b59bb0f788da38823a035f28d4c515a38be.zip
merge changes from the bug-1723660 branch
git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@1662 f01d2545-417e-4e96-918e-98f8d0dbbcb6
Diffstat (limited to 'bindings')
-rwxr-xr-xbindings/python/examples/coverart_fetch.py84
-rwxr-xr-xbindings/python/examples/save_photos.py6
-rw-r--r--bindings/python/gpod.i.in43
-rw-r--r--bindings/python/ipod.py97
-rw-r--r--bindings/python/tests/resources/tiny.pngbin0 -> 155 bytes
-rw-r--r--bindings/python/tests/tests.py104
6 files changed, 257 insertions, 77 deletions
diff --git a/bindings/python/examples/coverart_fetch.py b/bindings/python/examples/coverart_fetch.py
index f5bfa92..13b7929 100755
--- a/bindings/python/examples/coverart_fetch.py
+++ b/bindings/python/examples/coverart_fetch.py
@@ -27,14 +27,16 @@ import gpod
import sys
import amazon
import urllib
-import Image
-import tempfile
+import gtk
+from optparse import OptionParser
-ipod_mount = '/mnt/ipod'
-itdb = gpod.itdb_parse(ipod_mount, None)
-if not itdb:
- print "Failed to read ipod at mountpoint %s" % ipod_mount
- sys.exit(2)
+parser = OptionParser()
+parser.add_option("-m", "--mountpoint", dest="mountpoint",
+ default="/mnt/ipod",
+ help="use iPod at MOUNTPOINT", metavar="MOUNTPOINT")
+(options, args) = parser.parse_args()
+
+db = gpod.Database(options.mountpoint)
# set your key here, or see amazon.py for a list of other places to
# store it.
@@ -42,22 +44,21 @@ amazon.setLicense('')
images = {}
-for track in gpod.sw_get_tracks(itdb):
- print track.artist, track.album, track.title, " :",
-
- #gpod.itdb_track_remove_thumbnails(track)
-
- if track.artwork.artwork_size:
- print "Already has artwork, skipping."
+for track in db:
+ if track.get_coverart().thumbnails:
+ #print " Already has artwork, skipping."
+ # note we could remove it with track.set_coverart(None)
continue
- if not (track.artist and track.album):
- print "Need an artist AND album name, skipping."
+ print "%(artist)s, %(album)s, %(title)s" % track
+
+ if not (track['artist'] and track['album']):
+ print " Need an artist AND album name, skipping."
continue
# avoid fetching again if we already had a suitable image
- if not images.has_key((track.album,track.artist)):
- query = "%s + %s" % (track.artist, track.album)
+ if not images.has_key((track['album'],track['artist'])):
+ query = "%(album)s + %(artist)s" % track
# nasty hacks to get better hits. Is there a library out there
# for this? Note we take out double quotes too: Amazon place
# this string literally into their XML response, so can end up
@@ -65,10 +66,11 @@ for track in gpod.sw_get_tracks(itdb):
# name="KeywordSearch"> which is not well formed :-(
for term in ["Disk 1", "Disk 2", '12"', '12 "','"','&']:
query = query.replace(term,"")
- print "Searching for %s: " % query,
+ print " Searching for %s: " % query
try:
albums = amazon.searchByKeyword(query,
- type="lite",product_line="music")
+ type="lite",
+ product_line="music")
except amazon.AmazonError, e:
print e
albums = []
@@ -77,32 +79,26 @@ for track in gpod.sw_get_tracks(itdb):
continue
album = albums[0]
- hdle, filename = tempfile.mkstemp()
- i = urllib.urlopen(album.ImageUrlLarge)
- open(filename,"w").write(i.read())
- img = Image.open(filename)
- if not (img.size[0] > 10 or img.size[1] > 10):
- os.unlink(filename)
- else:
- print "Fetched image for %s, %s" % (track.album,track.artist)
- images[(track.album,track.artist)] = filename
+ try:
+ image_data = urllib.urlopen(album.ImageUrlLarge).read()
+ except:
+ print " Failed to download from %s" % album.ImageUrlLarge
+ continue
+ loader = gtk.gdk.PixbufLoader()
+ loader.write(image_data)
+ loader.close()
+ pixbuf = loader.get_pixbuf()
+ if (pixbuf.get_width() > 10 or pixbuf.get_height() > 10):
+ print " Fetched image"
+ images[(track['album'],track['artist'])] = pixbuf
try:
- r = gpod.itdb_track_set_thumbnails(track,images[(track.album,track.artist)])
- if r != 1:
- print "Failed to save image thumbnail to ipod."
- else:
- print "Added thumbnails for %s, %s" % (track.album,track.artist)
+ track.set_coverart(images[(track['album'],track['artist'])])
+ print " Added thumbnails"
except KeyError:
- print "No image available for %s, %s" % (track.album,track.artist)
-
-
-print "Writing ipod database..."
-gpod.itdb_write(itdb, None)
+ print " No image available"
-print "Cleaning up downloaded images..."
-# really, we should do this if any of the real work threw an exception
-# too. This is just a demo script :-)
-for filename in images.values():
- os.unlink(filename)
+print "Saving database"
+db.close()
+print "Saved db"
diff --git a/bindings/python/examples/save_photos.py b/bindings/python/examples/save_photos.py
index abf23ed..ec8079b 100755
--- a/bindings/python/examples/save_photos.py
+++ b/bindings/python/examples/save_photos.py
@@ -24,6 +24,10 @@
import gpod
+if not hasattr(gpod.Thumbnail, 'get_pixbuf'):
+ print 'Sorry, gpod was built without pixbuf support.'
+ raise SystemExit
+
photodb = gpod.PhotoDatabase("/mnt/ipod")
print photodb
@@ -34,6 +38,6 @@ for album in photodb.PhotoAlbums:
for thumbnail, n in zip(photo.thumbnails,
range(0,len(photo.thumbnails))):
print " ", thumbnail
- thumbnail.save_image("/tmp/%d-%d.png" % (photo['id'],n))
+ thumbnail.get_pixbuf().save("/tmp/%d-%d.png" % (photo['id'],n),"png")
photodb.close()
diff --git a/bindings/python/gpod.i.in b/bindings/python/gpod.i.in
index f8364eb..b7da152 100644
--- a/bindings/python/gpod.i.in
+++ b/bindings/python/gpod.i.in
@@ -47,6 +47,7 @@ version = '.'.join(map(str, version_info))
%module(docstring=DOCSTRING) gpod
%{
+#include "@top_builddir@/config.h"
#include "db-artwork-debug.h"
#include "db-artwork-parser.h"
#include "db-image-parser.h"
@@ -55,7 +56,12 @@ version = '.'.join(map(str, version_info))
#include "itdb.h"
#include "itdb_device.h"
#include "itdb_private.h"
+#ifdef HAVE_GDKPIXBUF
+#ifdef HAVE_PYGOBJECT
#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <pygobject.h>
+#endif
+#endif
/* include prototypes for all functions so builds using
@@ -77,7 +83,6 @@ 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);
@@ -287,29 +292,19 @@ PyObject* sw_get_photo(GList *list, gint index) {
}
}
- 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 %{
+#ifdef HAVE_GDKPIXBUF
+#ifdef HAVE_PYGOBJECT
g_type_init ();
+ init_pygobject ();
+#endif
+#endif
%}
%include "gpod_doc.i"
+%include "@top_builddir@/config.h"
# be nicer to decode these utf8 strings into Unicode objects in the C
# layer. Here we are leaving it to the Python side, and just giving
@@ -436,6 +431,19 @@ typedef long time_t;
typedef int gboolean;
typedef int gint;
+#ifdef HAVE_GDKPIXBUF
+#ifdef HAVE_PYGOBJECT
+%typemap(out) gpointer itdb_thumb_get_gdk_pixbuf {
+ $result = pygobject_new((GObject *)$1);
+ g_object_unref($1);
+}
+
+%typemap(in) gpointer pixbuf {
+ $1 = GDK_PIXBUF(pygobject_get($input));
+}
+#endif
+#endif
+
#define G_BEGIN_DECLS
#define G_END_DECLS
@@ -455,6 +463,5 @@ 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 64e7660..d088eba 100644
--- a/bindings/python/ipod.py
+++ b/bindings/python/ipod.py
@@ -15,6 +15,15 @@ import locale
import socket
import datetime
+if hasattr(gpod, 'HAVE_GDKPIXBUF') and hasattr(gpod, 'HAVE_PYGOBJECT'):
+ try:
+ import gtk
+ pixbuf_support = True
+ except ImportError:
+ pixbuf_support = False
+else:
+ pixbuf_support = False
+
defaultencoding = locale.getpreferredencoding()
class DatabaseException(RuntimeError):
@@ -364,10 +373,23 @@ class Track:
unicode_value = self['userdata']['%s_locale' % key].decode(self['userdata']['charset'])
return unicode_value.encode(defaultencoding)
- def set_thumbnail(self, filename):
+ def set_coverart_from_file(self, filename):
gpod.itdb_track_set_thumbnails(self._track, filename)
self._set_userdata_utf8('thumbnail', filename)
+ def set_coverart(self, pixbuf):
+ if pixbuf == None:
+ gpod.itdb_track_remove_thumbnails(self._track)
+ elif isinstance(pixbuf, Photo):
+ raise NotImplemented("Can't set coverart from existing coverart yet")
+ else:
+ gpod.itdb_track_set_thumbnails_from_pixbuf(self._track,
+ pixbuf)
+
+ def get_coverart(self):
+ return Photo(proxied_photo=self._track.artwork,
+ ownerdb=self._track.itdb)
+
def copy_to_ipod(self):
"""Copy the track to the iPod."""
self['userdata']['sha1_hash'] = gtkpod.sha1_hash(self._userdata_into_default_locale('filename'))
@@ -716,7 +738,9 @@ class PhotoDatabase:
def __init__(self, mountpoint="/mnt/ipod"):
"""Create a Photo database object"""
self._itdb = gpod.itdb_photodb_parse(mountpoint, None)
-
+ if self._itdb == None:
+ self._itdb = gpod.itdb_photodb_create(mountpoint)
+
def __str__(self):
return self.__repr__()
@@ -727,7 +751,8 @@ class PhotoDatabase:
len(self))
def close(self):
- pass
+ gpod.itdb_photodb_write(self._itdb, None)
+ gpod.itdb_photodb_free(self._itdb)
def __len__(self):
return gpod.sw_get_list_len(self._itdb.photos)
@@ -740,6 +765,33 @@ class PhotoDatabase:
index += len(self)
return Photo(proxied_photo=gpod.sw_get_photo(self._itdb.photos, index),
ownerdb=self)
+
+ def new_PhotoAlbum(self,**kwargs):
+ """Create a new PhotoAlbum.
+ """
+ album = PhotoAlbum(self, **kwargs)
+ return album
+
+ def new_Photo(self,**kwargs):
+ """Create a new Photo.
+ """
+ kwargs['ownerdb'] = self
+ photo = Photo(**kwargs)
+ return photo
+
+ def remove(self, item):
+ """Remove a photo or album from a database.
+
+ item is either a Photo or PhotoAlbum object.
+ """
+
+ if isinstance(item, PhotoAlbum):
+ gpod.itdb_photodb_photoalbum_remove(self._itdb, item._pa, False)
+ elif isinstance(item, Photo):
+ gpod.itdb_photodb_remove_photo(self._itdb, None, item._photo)
+ else:
+ raise DatabaseException("Unable to remove a %s from database" % type(item))
+
def get_device(self):
return gpod.sw_ipod_device_to_dict(self._itdb.device)
@@ -796,7 +848,14 @@ class PhotoAlbum:
if proxied_photoalbum:
self._pa = proxied_photoalbum
else:
- raise NotImplemented("Can't create new Photo Albums yet")
+ self._pa = gpod.itdb_photodb_photoalbum_create(self._db._itdb, title, pos)
+
+ def add(self, photo):
+ """Add photo to photo album."""
+ gpod.itdb_photodb_photoalbum_add_photo(self._db._itdb, self._pa, photo._photo, -1)
+
+ def remove(self, photo):
+ gpod.itdb_photodb_remove_photo(self._db._itdb, self._pa, photo._photo)
def get_name(self):
"""Get the name of the photo album."""
@@ -844,10 +903,11 @@ class Photo:
def __init__(self, filename=None,
proxied_photo=None, ownerdb=None):
"""Create a Photo object."""
+ error = None
if filename:
- # maybe use itdb_photodb_add_photo ?
- raise NotImplemented("Can't create new Photos from files yet")
+ self._photo = gpod.itdb_photodb_add_photo(ownerdb._itdb, filename, -1, 0, error)
+ self._database = ownerdb
elif proxied_photo:
self._photo = proxied_photo
self._database = ownerdb
@@ -895,8 +955,10 @@ class Photo:
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)]
-
+ return [Thumbnail(proxied_thumbnail=t,
+ ownerobject=self) for t in gpod.sw_get_artwork_thumbnails(
+ self._photo)]
+
thumbnails = property(get_thumbnails)
class Thumbnail:
@@ -904,14 +966,14 @@ class Thumbnail:
_proxied_attributes = [k for k in gpod._Itdb_Thumb.__dict__.keys() if not k.startswith("_")]
- def __init__(self, proxied_thumbnail=None, ownerphoto=None):
+ def __init__(self, proxied_thumbnail=None, ownerobject=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
+ self.__ownerobject = ownerobject
def __str__(self):
return self.__repr__()
@@ -946,7 +1008,14 @@ class Thumbnail:
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)
+ if pixbuf_support:
+ def get_pixbuf(self):
+ # this deals with coverart and photo albums
+ if hasattr(self.__ownerobject._database,"_itdb"):
+ return gpod.itdb_thumb_get_gdk_pixbuf(
+ self.__ownerobject._database._itdb.device,
+ self._thumbnail)
+ else:
+ return gpod.itdb_thumb_get_gdk_pixbuf(
+ self.__ownerobject._database.device,
+ self._thumbnail)
diff --git a/bindings/python/tests/resources/tiny.png b/bindings/python/tests/resources/tiny.png
new file mode 100644
index 0000000..0b34c35
--- /dev/null
+++ b/bindings/python/tests/resources/tiny.png
Binary files differ
diff --git a/bindings/python/tests/tests.py b/bindings/python/tests/tests.py
index bdae7cb..09c89bf 100644
--- a/bindings/python/tests/tests.py
+++ b/bindings/python/tests/tests.py
@@ -66,5 +66,109 @@ class TestiPodFunctions(unittest.TestCase):
def testVersion(self):
self.assertEqual(type(gpod.version_info),
types.TupleType)
+
+class TestPhotoDatabase(unittest.TestCase):
+ def setUp(self):
+ self.mp = tempfile.mkdtemp()
+ control_dir = os.path.join(self.mp,'iPod_Control')
+ photo_dir = os.path.join(control_dir, 'Photos')
+ shutil.copytree('resources',
+ control_dir)
+ os.mkdir(photo_dir)
+ self.db = gpod.PhotoDatabase(self.mp)
+ gpod.itdb_device_set_sysinfo (self.db._itdb.device, "ModelNumStr", "MA450");
+
+ def tearDown(self):
+ shutil.rmtree(self.mp)
+
+ def testClose(self):
+ self.db.close()
+
+ def testAddPhotoAlbum(self):
+ """ Test adding 5 photo albums to the database """
+ for i in range(0, 5):
+ count = len(self.db.PhotoAlbums)
+ album = self.db.new_PhotoAlbum(title="Test %s" % i)
+ self.failUnless(len(self.db.PhotoAlbums) == (count + 1))
+
+ def testAddRemovePhotoAlbum(self):
+ """ Test removing all albums but "Photo Library" """
+ self.testAddPhotoAlbum()
+ pas = [x for x in self.db.PhotoAlbums if x.name != "Photo Library"]
+ for pa in pas:
+ self.db.remove(pa)
+ self.assertEqual(len(self.db.PhotoAlbums), 1)
+
+ def testRenamePhotoAlbum(self):
+ bad = []
+ good = []
+
+ self.testAddPhotoAlbum()
+ pas = [x for x in self.db.PhotoAlbums if x.name != "Photo Library"]
+ for pa in pas:
+ bad.append(pa.name)
+ pa.name = "%s (renamed)" % pa.name
+ good.append(pa.name)
+
+ pas = [x for x in self.db.PhotoAlbums if x.name != "Photo Library"]
+ for pa in pas:
+ self.failUnless(pa.name in bad)
+ self.failUnless(pa.name not in good)
+
+ def testEnumeratePhotoAlbums(self):
+ [photo for photo in self.db.PhotoAlbums]
+
+ def testAddPhoto(self):
+ photoname = os.path.join(self.mp,
+ 'iPod_Control',
+ 'tiny.png')
+ self.failUnless(os.path.exists(photoname))
+ for n in range(1,5):
+ t = self.db.new_Photo(filename=photoname)
+ self.assertEqual(len(self.db), n)
+
+ def testAddPhotoToAlbum(self):
+ self.testAddPhoto()
+ pa = self.db.new_PhotoAlbum(title="Add To Album Test")
+ count = len(pa)
+ for p in self.db.PhotoAlbums[0]:
+ pa.add(p)
+ self.assertEqual(len(pa), len(self.db.PhotoAlbums[0]))
+ self.failUnless(len(pa) > count)
+
+ def testRemovePhotoFromAlbum(self):
+ self.testAddPhotoToAlbum()
+ pa = self.db.PhotoAlbums[1]
+ for p in pa[:]:
+ pa.remove(p)
+ # make sure we didn't delete the photo
+ self.failUnless(len(self.db.PhotoAlbums[0]) > 0)
+ # but that we did remove them from album
+ self.assertEqual(len(pa), 0)
+
+ def testAddRemovePhoto(self):
+ self.testAddPhoto()
+ self.failUnless(len(self.db) > 0)
+ for photo in self.db.PhotoAlbums[0][:]:
+ self.db.remove(photo)
+ self.assertEqual(len(self.db), 0)
+
+ def testAddCountPhotos(self):
+ count = len(self.db)
+ self.testAddPhoto()
+ self.failUnless(len(self.db) > count)
+
+ def testEnumeratePhotoAlbums(self):
+ [photo for photo in self.db.PhotoAlbums]
+
+ def testEnumeratePhotos(self):
+ for album in self.db.PhotoAlbums:
+ [photo for photo in album]
+
+ def testEnumeratePhotosThumbs(self):
+ for album in self.db.PhotoAlbums:
+ for photo in album:
+ [thumb for thumb in photo.thumbnails]
+
if __name__ == '__main__':
unittest.main()