From: <nic...@us...> - 2007-07-16 16:50:20
|
Revision: 1651 http://gtkpod.svn.sourceforge.net/gtkpod/?rev=1651&view=rev Author: nicholas Date: 2007-07-16 09:50:19 -0700 (Mon, 16 Jul 2007) Log Message: ----------- libgpod-pixbuf-python-support-v4.diff + photo_python_2.diff Modified Paths: -------------- libgpod/branches/bug-1723660/ChangeLog libgpod/branches/bug-1723660/TROUBLESHOOTING libgpod/branches/bug-1723660/bindings/python/examples/coverart_fetch.py libgpod/branches/bug-1723660/bindings/python/examples/save_photos.py libgpod/branches/bug-1723660/bindings/python/gpod.i.in libgpod/branches/bug-1723660/bindings/python/ipod.py libgpod/branches/bug-1723660/bindings/python/tests/tests.py libgpod/branches/bug-1723660/configure.ac libgpod/branches/bug-1723660/m4/python.m4 Added Paths: ----------- libgpod/branches/bug-1723660/bindings/python/tests/resources/tiny.png Property Changed: ---------------- libgpod/branches/bug-1723660/bindings/python/ libgpod/branches/bug-1723660/bindings/python/tests/ Modified: libgpod/branches/bug-1723660/ChangeLog =================================================================== --- libgpod/branches/bug-1723660/ChangeLog 2007-07-16 16:48:20 UTC (rev 1650) +++ libgpod/branches/bug-1723660/ChangeLog 2007-07-16 16:50:19 UTC (rev 1651) @@ -1,3 +1,14 @@ +2007-07-13 Nicholas Piper <nicholas at users.sourceforge.net> + + * bindings/python/ipod.py (Track.set_coverart_from_file): Rename + set_thumbnail function to set_coverart_from_file + + * bindings/python/ipod.py Improve support for adding + Photos. Thanks to John Carr. + + * bindings/python/examples/coverart_fetch.py: Adjust to + demonstrate new gtk pixbuf based coverart API + 2007-07-12 Jorg Schuler <jcsjcs at users.sourceforge.net> * po/ro.po: nobody told me I forgot to actually add this file to Modified: libgpod/branches/bug-1723660/TROUBLESHOOTING =================================================================== --- libgpod/branches/bug-1723660/TROUBLESHOOTING 2007-07-16 16:48:20 UTC (rev 1650) +++ libgpod/branches/bug-1723660/TROUBLESHOOTING 2007-07-16 16:50:19 UTC (rev 1651) @@ -90,5 +90,9 @@ python-dev (e.g. python2.4-dev) python-mutagen +These are needed for full gdk-pixbuf support: +python-gobject +python-gtk2 + ------------------------------------------------------------ Property changes on: libgpod/branches/bug-1723660/bindings/python ___________________________________________________________________ Name: svn:ignore - Makefile Makefile.in .deps README gpod.i + Makefile Makefile.in .deps README gpod.i gpod.py gtkpod.pyc gpod.pyc ipod.pyc __init__.pyc gpod_wrap.c gpod_doc.i .libs tests/Makefile.in tests/Makefile Modified: libgpod/branches/bug-1723660/bindings/python/examples/coverart_fetch.py =================================================================== --- libgpod/branches/bug-1723660/bindings/python/examples/coverart_fetch.py 2007-07-16 16:48:20 UTC (rev 1650) +++ libgpod/branches/bug-1723660/bindings/python/examples/coverart_fetch.py 2007-07-16 16:50:19 UTC (rev 1651) @@ -27,37 +27,38 @@ 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. amazon.setLicense('') images = {} -for track in gpod.sw_get_tracks(itdb): - print track.artist, track.album, track.title, " :", +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 - #gpod.itdb_track_remove_thumbnails(track) + print "%(artist)s, %(album)s, %(title)s" % track - if track.artwork.artwork_size: - print "Already has artwork, skipping." + if not (track['artist'] and track['album']): + print " Need an artist AND album name, skipping." continue - - 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 @@ # 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 @@ 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 " No image available" -print "Writing ipod database..." -gpod.itdb_write(itdb, None) - -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" Modified: libgpod/branches/bug-1723660/bindings/python/examples/save_photos.py =================================================================== --- libgpod/branches/bug-1723660/bindings/python/examples/save_photos.py 2007-07-16 16:48:20 UTC (rev 1650) +++ libgpod/branches/bug-1723660/bindings/python/examples/save_photos.py 2007-07-16 16:50:19 UTC (rev 1651) @@ -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 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() Modified: libgpod/branches/bug-1723660/bindings/python/gpod.i.in =================================================================== --- libgpod/branches/bug-1723660/bindings/python/gpod.i.in 2007-07-16 16:48:20 UTC (rev 1650) +++ libgpod/branches/bug-1723660/bindings/python/gpod.i.in 2007-07-16 16:50:19 UTC (rev 1651) @@ -47,6 +47,7 @@ %module(docstring=DOCSTRING) gpod %{ +#include "@top_srcdir@/config.h" #include "db-artwork-debug.h" #include "db-artwork-parser.h" #include "db-image-parser.h" @@ -55,7 +56,12 @@ #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_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_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_srcdir@/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 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_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" Modified: libgpod/branches/bug-1723660/bindings/python/ipod.py =================================================================== --- libgpod/branches/bug-1723660/bindings/python/ipod.py 2007-07-16 16:48:20 UTC (rev 1650) +++ libgpod/branches/bug-1723660/bindings/python/ipod.py 2007-07-16 16:50:19 UTC (rev 1651) @@ -15,6 +15,15 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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,7 @@ 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 get_name(self): """Get the name of the photo album.""" @@ -844,10 +896,11 @@ 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 +948,10 @@ 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 +959,14 @@ _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 +1001,14 @@ 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) Property changes on: libgpod/branches/bug-1723660/bindings/python/tests ___________________________________________________________________ Name: svn:ignore + Makefile Makefile.in Added: libgpod/branches/bug-1723660/bindings/python/tests/resources/tiny.png =================================================================== (Binary files differ) Property changes on: libgpod/branches/bug-1723660/bindings/python/tests/resources/tiny.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Modified: libgpod/branches/bug-1723660/bindings/python/tests/tests.py =================================================================== --- libgpod/branches/bug-1723660/bindings/python/tests/tests.py 2007-07-16 16:48:20 UTC (rev 1650) +++ libgpod/branches/bug-1723660/bindings/python/tests/tests.py 2007-07-16 16:50:19 UTC (rev 1651) @@ -66,5 +66,90 @@ 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 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() Modified: libgpod/branches/bug-1723660/configure.ac =================================================================== --- libgpod/branches/bug-1723660/configure.ac 2007-07-16 16:48:20 UTC (rev 1650) +++ libgpod/branches/bug-1723660/configure.ac 2007-07-16 16:50:19 UTC (rev 1651) @@ -93,6 +93,26 @@ AM_CONDITIONAL(HAVE_GDKPIXBUF, test x"$have_gdkpixbuf" = xyes) dnl ************************************************** +dnl * PYGOBJECT is optional +dnl ************************************************** + +AC_ARG_ENABLE(pygobject, [AC_HELP_STRING([--disable-pygobject],[Python API will lack GdkPixbuf support without PyGOBJECT])], +[case "${enableval}" in + no) have_pygobject=no ;; + *) have_pygobject=yes;; +esac], have_pygobject=yes) +AH_TEMPLATE([HAVE_PYGOBJECT], [Whether pygobject is installed, Python API will lack GdkPixbuf support without PyGOBJECT]) +if test x$have_pygobject = xyes; then + PKG_CHECK_MODULES(PYGOBJECT, pygobject-2.0 >= 2.8.0, have_pygobject=yes, have_pygobject=no) + if test x"$have_pygobject" = xyes; then + AC_DEFINE_UNQUOTED(HAVE_PYGOBJECT, 1) + fi + LIBGPOD_CFLAGS="$LIBGPOD_CFLAGS $PYGOBJECT_CFLAGS" + LIBGPOD_LIBS="$LIBGPOD_LIBS $PYGOBJECT_LIBS" +fi +AM_CONDITIONAL(HAVE_PYGOBJECT, test x"$have_pygobject" = xyes) + +dnl ************************************************** dnl * internationalization support dnl ************************************************** ALL_LINGUAS="de es fr he it ja ro sv" @@ -115,6 +135,7 @@ PYTHON_MIN_VERSION=2.1.1 PYTHON_MUTAGEN_MIN_VERSION=1.8 +PYTHON_GTK_MIN_VERSION=2.0 SWIG_MIN_VERSION=1.3.24 LIBGPOD_CHECK_PYTHON($PYTHON_MIN_VERSION) @@ -195,6 +216,7 @@ Linker ...............: $CC $LDFLAGS $LIBS $LIBGPOD_LIBS ArtworkDB support ....: $have_gdkpixbuf Python bindings ......: $with_python + PyGObject support ....: $have_pygobject Now type 'make' to build $PACKAGE $VERSION, and then 'make install' for installation. Modified: libgpod/branches/bug-1723660/m4/python.m4 =================================================================== --- libgpod/branches/bug-1723660/m4/python.m4 2007-07-16 16:48:20 UTC (rev 1650) +++ libgpod/branches/bug-1723660/m4/python.m4 2007-07-16 16:50:19 UTC (rev 1651) @@ -126,6 +126,11 @@ dnl check for mutagen module >= $PYTHON_MUTAGEN_MIN_VERSION AM_CHECK_PYMOD(mutagen,$PYTHON_MUTAGEN_MIN_VERSION,mutagen.version_string,,with_python=no) + if test "X$have_gdkpixbuf" == "Xyes" -a "X$have_pygobject" == "Xyes"; then + dnl check for gtk module >= $PYTHON_GTK_MIN_VERSION + AM_CHECK_PYMOD(gtk,$PYTHON_GTK_MIN_VERSION,'.'.join(map(str, gtk.ver)),,with_python=no) + fi + dnl check for swig if test "X$with_python" == Xyes; then AC_PROG_SWIG($SWIG_MIN_VERSION) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |