====== Python Gallery 3 Library ======
===== What is it? =====
This is a library to wrap the new Gallery 3 REST API in a nice, handy Python library. This makes using accessing and manipulating your Gallery 3 site a breeze.
This is still an early release, but it functions quite well and has some nice features from a performance standpoint like //lazy// access to sub-items (the images in an album, for example).
===== License =====
This project is licensed under the GPLv3. A copy of the license is included in the source and is available at [[http://www.gnu.org/licenses/gpl-3.0.txt]].
===== Downloading =====
You can download the package here: {{:programming:python:pylibgal3-0.1.6.tar.gz|pylibgal3-0.1.6.tar.gz}}.
You can also track this project on [[https://github.com/crustymonkey/pylibgal3|github]]
===== Installing =====
Install is pretty easy if you've ever installed another Python package. It's the standard ''python setup.py install'' as root thing.
# tar -xvzf pylibgal3-*.tar.gz
# cd pylibgal3-*
# sudo python setup.py install
That's about it for the install.
===== Usage =====
==== Logging In ====
This is a pretty simple to use library. First, we'll go through the 2 ways you can log in.
First, and most directly, you can just instantiate a Gallery3 object by passing the hostname and api key into the constructor:
import libg3 # libg3 is the actual name of the installed library package
hostname = 'example.com'
apiKey = '111111111111111111'
g3Base = '/gallery3' # This is actually the default. This reflects the path
# as it would be after the host. For this example, your
# url would be http://example.com/gallery3
gal = libg3.Gallery3(hostname , apiKey , g3Base=g3Base)
# You can also set the port number in the constructor with port=num or specify ssl
# access with ssl=True. If you were running your gallery on an ssl connection on the
# standard ssl port of 443, you would use this for your constructor:
# gal = libg3.Gallery3(hostname , apiKey , g3Base=g3Base , port=443 , ssl=True)
We'll get to usage on the ''gal'' object in a minute. Before that, let's cover the other way to get your base Gallery3 object. You can use the ''login()'' function instead to pass in a username and password rather than your api key directly. This basically subs out the ''apiKey'' in the Gallery3 constructor with a username and password. You can still set the ''g3Base'', ''port'' and ''ssl'' options like you would in the Gallery3 constructor call.
import libg3
hostname = 'example.com'
g3Base = '/gallery3'
username = 'foo'
password = 'bar'
port = 80
ssl = False
gal = libg3.login(hostname , username , password , g3Base=g3Base , port=port , ssl=ssl)
Now that you have your Gallery3 object, let's get to what you can do with it.
==== Core Gallery Items ====
First, lets give you a brief explanation of the basic elements you will be dealing with, There are a total of five core Gallery elements that we will explore here.
- **Album** - Basically, this is a container to hold other items, including other albums. The root of your gallery is an album.
- **RemoteImage** - This pertains to an image in the remote gallery.
- **RemoteMovie** - This is essentially just a descendant, and very similar to, a RemoteImage. This will not be covered below since it is so similar to a RemoteImage
- **Tag** - Albums, images and movies can all be tagged in your gallery. You can access these via simple library calls.
- **Comment** - People can leave comments on images and movies. The library has simple calls to access these and add them.
==== Exploring the Root Album ====
As you may, or may not, be aware, the root of your gallery is considered to be an album just like any other album you create within it. This means that it is the base of a tree structure you create. The examples for the root album will actually apply to any other sub-albums with one exception, the root album does not have a parent.
Let's take a look at getting the root album and a dump of the root album dictionary.
from pprint import pprint
# Assume we are using the "gal" object we created in one of the previous examples
root = gal.getRoot()
# Note that after you call getRoot() initially, you can access the root element
# as a property of your base Gallery3 object with "gal.root"
print root
# Outputs:
pprint(root.__dict__)
# Outputs:
{'_album_cover': u'http://example.com:80/gallery3/index.php/rest/item/4',
'_members': [u'http://example.com:80/gallery3/index.php/rest/item/4',
u'http://example.com:80/gallery3/index.php/rest/item/10'],
'_weakGal': ,
'_weakParent': None,
'can_edit': True,
'captured': None,
'created': u'1289701744',
'description': u'',
'fh': None,
'height': None,
'id': u'1',
'level': u'1',
'mime_type': None,
'name': None,
'owner_id': u'2',
'rand_key': None,
'relationships': {u'comments': {u'url': u'http://example.com:80/gallery3/index.php/rest/item_comments/1'},
u'tags': {u'members': [],
u'url': u'http://example.com:80/gallery3/index.php/rest/item_tags/1'}},
'resize_height': None,
'resize_width': None,
'slug': None,
'sort_column': u'weight',
'sort_order': u'ASC',
'thumb_height': u'150',
'thumb_size': 16393,
'thumb_url': u'http://example.com:80/gallery3/index.php/rest/data/1?size=thumb',
'thumb_url_public': u'http://example.com:80/gallery3/var/thumbs//.album.jpg?m=1289704941',
'thumb_width': u'200',
'title': u'Gallery',
'type': u'album',
'updated': u'1289704941',
'url': u'http://example.com:80/gallery3/index.php/rest/item/1',
'view_1': u'1',
'view_2': u'1',
'view_count': u'101',
'web_url': u'http://example.com:80/gallery3/index.php/',
'width': None}
Those are all the basic, default properties that are pulled from the server for your gallery root. There are some other convenience properties that we can also access in that root Album (or any other album, for that matter) that will make your access to certain elements easier.
# Again, we are using the previously created "gal" object
root = gal.getRoot()
# We can access all the member items (children) of this album with the
# members property. This is a list of all children.
pprint(root.members)
# We can also get just the Albums, Images or Movies. Like "members", these
# are all lists of their respective types:
pprint(root.Albums)
pprint(root.Images)
pprint(root.Movies)
# We can get the image that is being used as the album cover.
pprint(root.album_cover)
# We can also get any tags associated with the root album. This will be a
# list of Tag objects
pprint(root.tags)
# There a couple of simple convenience methods to get ''datetime'' objects
# for the 2 timestamp fields:
creationDatetime = root.getCrDT()
updatedDatetime = root.getUpdDT()
An important thing to note with some of the above. All the "members", "tags", "album_cover", and as we will see with images, "comments", are created on the fly with a //lazy// pull from the server. If you are not familiar with what I mean by "lazy", it means that when, in your code, you access the "members" property of your album, a call will be made to the //at that time// to generate the objects for each member. It is an on-demand approach to object creation. It keeps the server access to a minimum so that there aren't calls being made to retrieve items that aren't going to be used. The calls to the server for these items are only made once and all the "members" will be stored in memory for access after that. **NOTE**: this also means that there will be a bit of a delay when you are first accessing properties like "members", "tags", "comments", etc.
==== Images ====
Now, let's take a look at a RemoteImage:
root = gal.getRoot()
firstImage = root.Images[0]
print firstImage
# Outputs:
pprint(firstImage.__dict__)
# Outputs:
{'_parent': u'http://example.com:80/gallery3/index.php/rest/item/1',
'_weakGal': ,
'_weakParent': ,
'can_edit': True,
'captured': None,
'created': u'1289704939',
'description': u'',
'fh': None,
'file_size': 3876980,
'file_url': u'http://example.com:80/gallery3/index.php/rest/data/4?size=full',
'file_url_public': u'http://example.com:80/gallery3/var/albums/mini-goobs-jumping.jpg?m=1289704941',
'height': u'2448',
'id': u'4',
'level': u'2',
'mime_type': u'image/jpeg',
'name': u'mini-goobs-jumping.jpg',
'owner_id': u'2',
'rand_key': u'0.506461',
'relationships': {u'comments': {u'url': u'http://example.com:80/gallery3/index.php/rest/item_comments/4'},
u'tags': {u'members': [],
u'url': u'http://example.com:80/gallery3/index.php/rest/item_tags/4'}},
'resize_height': u'480',
'resize_size': 59807,
'resize_url': u'http://example.com:80/gallery3/index.php/rest/data/4?size=resize',
'resize_url_public': u'http://example.com:80/gallery3/var/resizes/mini-goobs-jumping.jpg?m=1289704941',
'resize_width': u'640',
'slug': u'mini-goobs-jumping',
'sort_column': u'created',
'sort_order': u'ASC',
'thumb_height': u'150',
'thumb_size': 16393,
'thumb_url': u'http://example.com:80/gallery3/index.php/rest/data/4?size=thumb',
'thumb_url_public': u'http://example.com:80/gallery3/var/thumbs/mini-goobs-jumping.jpg?m=1289704941',
'thumb_width': u'200',
'title': u'Mini-goobs Jumping',
'type': u'photo',
'updated': u'1289704941',
'url': u'http://example.com:80/gallery3/index.php/rest/item/4',
'view_1': u'1',
'view_2': u'1',
'view_count': u'2',
'web_url': u'http://example.com:80/gallery3/index.php/mini-goobs-jumping',
'width': u'3264'}
Things look a bit different here, but there are some similarities. Like an Album, there are a few extras that you can do with a RemoteImage.
# Continuing with the "firstImage" object from above
# We have access to the parent object (in this example, the root album) via the "parent" property
print firstImage.parent
# Outputs:
# You can access the comments for this image with the "comments" property
# This will give you a list of all this image's comments
pprint(firstImage.comments)
# Again, you can access the tags
pprint(firstImage.tags)
# You can get the created and updated datetimes here too
pprint(firstImage.getCrDT())
pprint(firstImage.getUpdDT())
==== Comments ====
We will only look at comments (and tags) briefly.
Here is what a Comment object looks like:
# Again using the "firstImage" object we created above
firstComment = firstImage.comments[0]
print type(firstComment)
# Outputs:
pprint(firstComment.__dict__)
# Outputs:
{'_item': u'http://example.com:80/gallery3/index.php/rest/item/13',
'_parent': u'http://example.com:80/gallery3/index.php/rest/item/13',
'_weakGal': ,
'_weakParent': ,
'author_id': u'2',
'created': u'1292466908',
'fh': None,
'guest_email': None,
'guest_name': None,
'guest_url': None,
'id': u'5',
'relationships': [],
'state': u'published',
'text': u'test comment',
'updated': u'1292466908',
'url': u'http://example.com:80/gallery3/index.php/rest/comment/5'}
# You can also just print the comment "text" out by printing the comment
print firstComment
# Outputs: test comment
==== Tags ====
Tags are a bit like comments. We are going to cover these briefly as well.
# Again using the "firstImage" object we created above
firstTag = firstImage.tags[0]
print type(firstTag)
# Outputs:
pprint(firstTag.__dict__)
# Outputs:
{'_weakGal': ,
'_weakParent': ,
'count': 1,
'fh': None,
'id': u'2',
'name': u'dave',
'relationships': {u'items': {u'members': [u'http://example.com:80/gallery3/index.php/rest/tag_item/2,13'],
u'url': u'http://example.com:80/gallery3/index.php/rest/tag_items/2'}},
'type': 'tag',
'url': u'http://example.com:80/gallery3/index.php/rest/tag/2'}
print firstTag
# Outputs the name property: dave
==== Additional Info ====
That about finishes up with the basics of the readable attributes for each of the core items. You can access more documentation for each type on the command line with the ''pydoc'' command:
* pydoc libg3.G3Items.Album
* pydoc libg3.G3Items.RemoteImage
* pydoc libg3.G3Items.RemoteMovie
* pydoc libg3.G3Items.Comment
* pydoc libg3.G3Items.Tag
* pydoc libg3.Gallery3
Now, let's move on to working with our different items.
==== Working With Albums ====
This is about as easy as it gets. You just call the ''addAlbum()'' method on any album object.
# Assume we have our gallery object here
root = gal.getRoot()
albumName = 'test album 1' # this is the name that will show up in the url
albumTitle = 'A testing album' # this is the title of the album that will show up on the Gallery webpage
albumDesc = 'My description' # this is the album's description (optional)
newAlbumObject = root.addAlbum(albumName , albumTitle , albumDesc)
# That's it. You can now use that "newAlbumObject" to add other albums, images, etc
Now, let's "tag" this new album.
newTag = newAlbumObject.tag('awesome')
Let's change the title and description of this album
newAlbumObject.update(newTitle , newDesc)
If you don't want the album on your site anymore, just delete() it
newAlbumObject.delete()
Ok, we have this album, but now you probably want to add an image to it, right.
imagePath = '/path/to/image.jpg'
locImage = libg3.LocalImage(imagePath)
imageTitle = 'Foo'
imageDesc = 'The best image EVER'
# This will return the new RemoteImage instance
newRemoteImage = newAlbumObject.addImage(locImage , imageTitle , imageDesc)
# Since this is "the best image EVER", let's set it as the album cover
newAlbumObject.setCover(newRemoteImage)
To do the same with a movie, just use "LocalMovie" instead of "LocalImage".
==== Working With Images ====
Now, there are not as many things you can do with images (or movies) as you can with albums so this will be brief.
We can add a comment to an image
comment = 'I love cheese'
commentObj = newRemoteImage.addComment(comment)
Updates work just like albums.
newRemoteImage.update(newTitle , newDesc)
Downloading the image is also pretty easy, just use the read() method of the RemoteImage.
# You can also access and download this image with the read call:
binaryImage = ''
buf = newRemoteImage.read(4096)
while buf:
binaryImage += buf
buf = newRemoteImage.read(4096)
if not buf: break
# Or more simply
binaryImage = newRemoteImage.read()
# Then you can just write this out as a local file
open(newRemoteImage.name , 'wb').write(binaryImage)
# Get a handle to the resized image and download it
resized = firstImage.getResizeHandle()
outfile = open('resized.jpg' , 'w')
outfile.write(resized.read())
outfile.close()
# Get a handle to the resized image and download it
thumb = firstImage.getThumbHandle()
outfile = open('thumb.jpg' , 'w')
outfile.write(thumb.read())
outfile.close()
Of course, you can tag images too.
tag = 'Best image ever'
newTag = newRemoteImage.tag(tag)
You can perform all these same operations with a RemoteMovie object as well.
==== Another Item of Interest ====
It should also be pointed out that almost all of the functionality described above can also be done with different objects and method calls to your main Gallery3 object. This example will give you an idea of what I'm talking about:
gal = libg3.Gallery3(hostname , apiKey , g3Base=g3Base)
root = gal.getRoot()
firstAlbum = root.Albums[0]
# Now let's get the first image out of the first sub-album:
image = firstAlbum.Images[0]
# Now, we can always tag this image with the following:
image.tag('mytag')
# But, we can also tag an item (image or album) by using our main "gal" object, like so:
gal.tagItem(image , 'mytag')
# For another example, let's show the 2 ways we can set the cover for an album
# First is using an album object:
firstAlbum.setCover(image)
# But we can also use our main "gal" object
gal.setAlbumCover(firstAlbum , image)
It's worth noting that calling ''setCover()'' on album object is actually //exactly// the same as calling ''setAlbumCover()'' on the Gallery3 object. In fact, this is exactly what happens behind the scenes for consistency. This is the case with just about all the "item" object methods. Basically, use whatever code path works the best/easiest for you in your code.
==== The Future ====
As you can see, there is a good deal of functionality here, but it is by no means complete. Here are some of the plans I have for the future
* Make images and thumbnails resizable
* Reordering of members in an album
* Make all editable properties editable
If anyone has any problems, suggestions or whatever, feel free to email me directly at