conduit r1439 - in trunk: . conduit/modules/ZotoModule data



Author: thomasvm
Date: Fri May  2 10:51:28 2008
New Revision: 1439
URL: http://svn.gnome.org/viewvc/conduit?rev=1439&view=rev

Log:
2008-05-02  Manuel J. Garrido <manuel garrido gmail com>

	* data/zoto.png:
	* conduit/modules/ZotoModule/*: Add two way Zoto 
	module



Added:
   trunk/conduit/modules/ZotoModule/
   trunk/conduit/modules/ZotoModule/Makefile.am
   trunk/conduit/modules/ZotoModule/ZotoModule.py
   trunk/conduit/modules/ZotoModule/zoto.glade
   trunk/data/zoto.png   (contents, props changed)
Modified:
   trunk/ChangeLog
   trunk/data/Makefile.am

Added: trunk/conduit/modules/ZotoModule/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/conduit/modules/ZotoModule/Makefile.am	Fri May  2 10:51:28 2008
@@ -0,0 +1,8 @@
+conduit_handlersdir = $(libdir)/conduit/modules/ZotoModule.py
+conduit_handlers_PYTHON = ZotoModule.py
+
+conduit_handlers_DATA = config.glade
+EXTRA_DIST = config.glade
+
+clean-local:
+	rm -rf *.pyc *.pyo

Added: trunk/conduit/modules/ZotoModule/ZotoModule.py
==============================================================================
--- (empty file)
+++ trunk/conduit/modules/ZotoModule/ZotoModule.py	Fri May  2 10:51:28 2008
@@ -0,0 +1,244 @@
+# -*- coding: utf-8 -*-
+
+"""
+Zoto Data Sink
+"""
+import logging
+log = logging.getLogger("modules.Zoto")
+
+import conduit
+import conduit.utils as Utils
+from conduit.datatypes import Rid
+import conduit.dataproviders.Image as Image
+import conduit.Exceptions as Exceptions
+import conduit.datatypes.Photo as Photo
+
+from gettext import gettext as _
+
+import xmlrpclib
+import md5
+import os
+
+MODULES = {
+        "ZotoSink" : {"type" : "dataprovider"},
+}
+
+class MyZotoAPI:
+    def __init__(self, username, password):
+        self.zapiKey = '588c270052e2157c4fa7e10b80b2c580'
+        self.username = username
+        self.password = md5.md5(password).hexdigest() # password
+        
+        self.zotoAuth = {'username': self.username, 'password': self.password}
+        self.server = xmlrpclib.Server('http://www.zoto.com/RPC2/')
+
+    def delete_photo(self, photoId):
+        self.server.images.delete(self.zapiKey, self.zotoAuth, photoId)
+
+    def create_album(self, albumName):
+        """
+        Creates a new album. Returns the id for it
+        """
+        return self.server.albums.create_album(self.zapiKey, self.zotoAuth,
+                                               {'title':albumName, 'description': albumName})[1]
+
+    def get_albums(self):
+        albums = {}
+        for al in self.server.sets.get_albums(self.zapiKey, self.zotoAuth, self.username, {}, 9999, 0)[1]:
+            albums[al['title']] = al['album_id']
+
+        return albums
+
+    def get_photos_album(self, albumId):
+        """
+        Gets all the photos from album albumId.
+        Returns a dict like this <photoId> : <Photo>
+        """
+
+        photosDict = {}
+        photos = self.server.albums.get_images(self.zapiKey, self.zotoAuth, albumId, {}, 9999, 0)[1]
+
+        for zf in photos:
+            photoId = zf['media_id']
+            # The extension is jpg even if in the original name was JPG or jpeg
+            photoUrl = 'http://www.zoto.com/%s/img/original/%s.jpg' % (self.username, photoId)
+
+            # construct photo
+            f = Photo.Photo(URI=photoUrl)
+            f.set_open_URI(photoUrl)
+            f.set_UID(photoId)
+            f.set_caption (zf['description'])
+            f.force_new_filename(zf['title'])
+            f.set_tags(self.get_photo_tags(photoId))
+
+            # add to dict
+            photosDict[photoId] = f
+
+        return photosDict        
+
+    def add_to_album(self, uploadInfo, albumId):
+        """
+        Adds a photo to the album. 
+        """
+        caption = uploadInfo.caption
+        if not caption:
+            caption = ''
+
+        f = open(uploadInfo.url,'r')
+        buf=f.read()                
+        f.close()
+        fotoId= md5.md5(buf).hexdigest()
+
+        self.server.images.add(self.zapiKey, self.zotoAuth, uploadInfo.name,
+                               uploadInfo.name, caption, xmlrpclib.Binary(buf))
+        self.server.albums.multi_add_image(self.zapiKey, self.zotoAuth,
+                                           albumId, [fotoId])
+        tags = []
+        for tag in uploadInfo.tags:
+            tags.append(tag)
+
+        if len(tags) > 0:
+            self.server.tags.multi_tag_image(self.zapiKey, self.zotoAuth,
+                                             self.username, [fotoId], tags)
+
+        return fotoId
+
+    def delete_from_album(self, photoId, albumId):
+        self.server.albums.multi_del_image(self.zapiKey, self.zotoAuth,
+                                           albumId, [photoId])
+
+    def get_photo_tags(self, photoId):
+        """
+        Returns a list with the photo's tags
+        """
+        tags=[]
+        for t in self.server.tags.get_image_tags(self.zapiKey, self.zotoAuth,
+                                                 self.username, photoId, 'owner'):
+            tags.append(t['tag_name'])    
+
+        return tags
+
+class ZotoSink(Image.ImageTwoWay):
+    _name_ = _("Zoto")
+    _description_ = _("Sync your Zoto photos")
+    _module_type_ = "twoway"
+    _icon_ = "zoto"
+    
+    def __init__(self, *args):
+        Image.ImageTwoWay.__init__(self)
+        self.username = ""
+        self.password = ""
+        self.albumName = ""
+        self.albumId = None
+        self.sphotos = None
+        self.zapi = None
+        self.albums = None
+
+    def _get_raw_photo_url(self, photoInfo):
+        return photoInfo.get_open_URI()
+
+    def _get_photo_info(self, id):
+        if self.sphotos.has_key(id):
+                return self.sphotos[id]
+        else:
+                return None
+        
+    def _get_photo_formats(self):
+        return ("image/jpeg", )
+        
+    def refresh(self):            
+        Image.ImageTwoWay.refresh(self)
+
+        try:
+            self.zapi = MyZotoAPI(self.username, self.password)
+            albums = self.zapi.get_albums()
+            if not albums.has_key(self.albumName):
+                self.albumId = self.zapi.create_album(self.albumName)
+            else:
+                self.albumId = albums[self.albumName]
+                
+            self.sphotos = self.zapi.get_photos_album(self.albumId)
+        except xmlrpclib.Fault, e:
+            log.debug("Error refreshing: %s" % e.faultString)
+            raise Exceptions.RefreshError (e.faultString)
+        
+    def get_all(self):
+        return self.sphotos.keys()
+
+    def get(self, LUID):
+        return self.sphotos[LUID]
+
+    def delete(self, LUID):
+        """
+        Delete a photo by ID
+        """
+        if not self.sphotos.has_key(LUID):
+            log.warn("Photo does not exist")
+            return
+
+        try:
+            self.zapi.delete_from_album(LUID, self.albumId)
+            del self.sphotos[LUID]
+        except xmlrpclib.Fault, e:
+            raise Exceptions.SyncronizeError("Zoto Delete Error: " +  e.faultString)
+
+    def _upload_photo(self, uploadInfo):
+        """
+        Upload to album
+        """
+        try:
+            fotoId = self.zapi.add_to_album(uploadInfo, self.albumId)
+        except Exception, e:
+            raise Exceptions.SyncronizeError("Zoto Upload Error.")
+        
+        return Rid(uid=fotoId)
+
+    def configure(self, window):
+        """
+        Configures the ZotoSink
+        """
+        widget = Utils.dataprovider_glade_get_widget(
+                __file__,
+                "zoto.glade",
+                "ZotoSinkConfigDialog")
+                
+        # Get configuration widgets
+        username = widget.get_widget("username")
+        password = widget.get_widget("password")
+        album = widget.get_widget("album")
+                
+        # Load the widgets with presets
+        username.set_text(self.username)
+        password.set_text(self.password)
+        album.set_text(self.albumName)
+                
+        dlg = widget.get_widget("ZotoSinkConfigDialog")
+        
+        response = Utils.run_dialog(dlg, window)
+                
+        if response == True:
+            self.username = username.get_text()
+            self.password = password.get_text()
+            self.albumName = album.get_text()
+                
+        dlg.destroy()
+        
+    def get_configuration(self):
+        return {
+                "username" : self.username, 
+                "password" : self.password, 
+                "albumName" : self.albumName
+                }
+        
+    def is_configured(self, isSource, isTwoWay):
+        if len(self.username) < 1:
+            return False
+        if len(self.password) < 1:
+            return False
+        if len(self.albumName) < 1:
+            return False
+
+        return True
+        
+    def get_UID(self):
+        return self.username+":"+self.albumName

Added: trunk/conduit/modules/ZotoModule/zoto.glade
==============================================================================
--- (empty file)
+++ trunk/conduit/modules/ZotoModule/zoto.glade	Fri May  2 10:51:28 2008
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+  <widget class="GtkDialog" id="ZotoSinkConfigDialog">
+    <property name="visible">True</property>
+    <property name="title" translatable="yes">Zoto</property>
+    <property name="resizable">False</property>
+    <property name="default_width">250</property>
+    <property name="default_height">350</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="vbox30">
+        <property name="visible">True</property>
+        <property name="spacing">5</property>
+        <child>
+          <widget class="GtkLabel" id="label74">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">&lt;b&gt;Account Details&lt;/b&gt;</property>
+            <property name="use_markup">True</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkLabel" id="label75">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Username:</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkEntry" id="username">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkLabel" id="label76">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Password:</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkEntry" id="password">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+		<property name="visibility">False</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">6</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkLabel" id="label78">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">&lt;b&gt;Saved Photo Settings&lt;/b&gt;</property>
+            <property name="use_markup">True</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">7</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkLabel" id="label77">
+            <property name="visible">True</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">Album:</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">8</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkEntry" id="album">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">9</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="hbuttonbox12">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button32">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="label">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button33">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="label">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-5</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Modified: trunk/data/Makefile.am
==============================================================================
--- trunk/data/Makefile.am	(original)
+++ trunk/data/Makefile.am	Fri May  2 10:51:28 2008
@@ -47,7 +47,8 @@
 	boxdotnet.png \
 	flickr.png \
 	shutterfly.png \
-	youtube.png
+	youtube.png \
+	zoto.png
 
 conduitbindir = $(libdir)/conduit
 

Added: trunk/data/zoto.png
==============================================================================
Binary file. No diff available.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]