[conduit] Add Shotwell support
- From: John Stowers <jstowers src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [conduit] Add Shotwell support
- Date: Wed, 8 Sep 2010 09:51:44 +0000 (UTC)
commit fb32c54745b9d48af2c673bf27f1e589ae71af46
Author: Nathaniel Harward <nharward gmail com>
Date: Wed Sep 8 21:31:36 2010 +1200
Add Shotwell support
conduit/modules/Makefile.am | 1 +
conduit/modules/ShotwellModule/Makefile.am | 7 +
conduit/modules/ShotwellModule/ShotwellModule.py | 100 +++++++++
.../modules/ShotwellModule/shotwell/Makefile.am | 5 +
.../modules/ShotwellModule/shotwell/__init__.py | 233 ++++++++++++++++++++
5 files changed, 346 insertions(+), 0 deletions(-)
---
diff --git a/conduit/modules/Makefile.am b/conduit/modules/Makefile.am
index c39932c..4e059a2 100644
--- a/conduit/modules/Makefile.am
+++ b/conduit/modules/Makefile.am
@@ -8,6 +8,7 @@ SUBDIRS = \
FlickrModule \
FspotModule \
iPodModule \
+ ShotwellModule \
SmugMugModule \
EvolutionModule \
GoogleModule \
diff --git a/conduit/modules/ShotwellModule/Makefile.am b/conduit/modules/ShotwellModule/Makefile.am
new file mode 100644
index 0000000..cb4f5c2
--- /dev/null
+++ b/conduit/modules/ShotwellModule/Makefile.am
@@ -0,0 +1,7 @@
+SUBDIRS = shotwell
+
+conduit_handlersdir = $(libdir)/conduit/modules/ShotwellModule
+conduit_handlers_PYTHON = ShotwellModule.py
+
+clean-local:
+ rm -rf *.pyc *.pyo
diff --git a/conduit/modules/ShotwellModule/ShotwellModule.py b/conduit/modules/ShotwellModule/ShotwellModule.py
new file mode 100644
index 0000000..b35a54d
--- /dev/null
+++ b/conduit/modules/ShotwellModule/ShotwellModule.py
@@ -0,0 +1,100 @@
+import conduit
+import conduit.dataproviders.DataProvider as DataProvider
+import conduit.datatypes.Photo as Photo
+import conduit.utils as Utils
+
+import logging
+log = logging.getLogger('modules.Shotwell')
+
+from gettext import gettext as _
+
+try:
+ import shotwell
+except ImportError:
+ Utils.dataprovider_add_dir_to_path(__file__)
+ import shotwell
+
+MODULES = {
+ "ShotwellDataProvider" : { "type": "dataprovider" }
+}
+
+# Why is this not in the standard library?
+def _flatten(lst):
+ for elem in lst:
+ if type(elem) in (tuple, list):
+ for i in _flatten(elem):
+ yield i
+ else:
+ yield elem
+
+class ShotwellDataProvider(DataProvider.DataSource):
+
+
+ _name_ = _('Shotwell')
+ _description_ = _('Sync from your Shotwell photo library')
+ _icon_ = 'shotwell'
+ _category_ = conduit.dataproviders.CATEGORY_PHOTOS
+ _module_type_ = 'source'
+ _configurable_ = True
+ _out_type_ = 'file/photo'
+
+ _enabled = False
+ _selected_tag_names = []
+ _shotwell_photos = []
+
+ def __init__(self, *args):
+ DataProvider.DataSource.__init__(self)
+ self.update_configuration(tags = ([], self.set_tags, self.get_tags))
+ try:
+ shotwell_db = shotwell.ShotwellDB()
+ shotwell_db.close()
+ self._enabled = True
+ except:
+ log.warn('Disabling Shotwell module, open of sqlite3 DB failed')
+ self._enabled = False
+
+ def initialize(self):
+ DataProvider.DataSource.initialize(self)
+ return self._enabled
+
+ def set_tags(self, tags):
+ self._selected_tag_names = map(lambda x: str(x), tags)
+
+ def get_tags(self):
+ return self._selected_tag_names
+
+ def config_setup(self, config):
+ shotwell_db = shotwell.ShotwellDB()
+ config.add_section(_('Tags'))
+ all_tag_names = map(lambda sTag: sTag.name, shotwell_db.tags())
+ config.add_item(_('Tags'), 'list', config_name = 'tags',
+ choices = all_tag_names)
+ shotwell_db.close()
+
+ def refresh(self):
+ DataProvider.DataSource.refresh(self)
+ shotwell_db = shotwell.ShotwellDB()
+ tags = filter(lambda sTag: sTag.name in self._selected_tag_names,
+ shotwell_db.tags())
+ tagged_photos = list(_flatten(map(lambda sTag: sTag.photoIDs, tags)))
+ self._shotwell_photos = filter(lambda sPhoto: str(sPhoto.id) in \
+ tagged_photos, shotwell_db.photos())
+ log.debug('Found %i photos to sync', len(self._shotwell_photos))
+ shotwell_db.close()
+
+ def get_all(self):
+ DataProvider.DataSource.get_all(self)
+ return map(lambda sPhoto: str(sPhoto.id), self._shotwell_photos)
+
+ def get(self, LUID):
+ DataProvider.DataSource.get(self, LUID)
+ sPhoto = filter(lambda sPhoto: str(sPhoto.id) == LUID,
+ self._shotwell_photos)[0]
+ photo = Photo.Photo('file://' + sPhoto.filename)
+ photo.set_UID(LUID)
+ photo.set_caption(sPhoto.title)
+ return photo
+
+ def get_UID(self):
+ return Utils.get_user_string()
+
diff --git a/conduit/modules/ShotwellModule/shotwell/Makefile.am b/conduit/modules/ShotwellModule/shotwell/Makefile.am
new file mode 100644
index 0000000..e370439
--- /dev/null
+++ b/conduit/modules/ShotwellModule/shotwell/Makefile.am
@@ -0,0 +1,5 @@
+conduit_handlersdir = $(libdir)/conduit/modules/ShotwellModule/shotwell
+conduit_handlers_PYTHON = __init__.py
+
+clean-local:
+ rm -rf *.pyc *.pyo
diff --git a/conduit/modules/ShotwellModule/shotwell/__init__.py b/conduit/modules/ShotwellModule/shotwell/__init__.py
new file mode 100644
index 0000000..4ef3434
--- /dev/null
+++ b/conduit/modules/ShotwellModule/shotwell/__init__.py
@@ -0,0 +1,233 @@
+import os.path
+import sqlite3
+import string
+import sys
+
+class Version(object):
+
+
+ def __init__(self, schemaVersion, appVersion, userData=None):
+ self._schemaVersion = schemaVersion
+ self._appVersion = appVersion
+ self._userData = userData
+
+ def __str__(self):
+ return 'Version(' + str(map(lambda key: str(key) + '=' +
+ str(self.__dict__[key]), self.__dict__.keys())) + ')'
+
+ @property
+ def schemaVersion(self):
+ return self._schemaVersion
+
+ @property
+ def appVersion(self):
+ return self._appVersion
+
+ @property
+ def userData(self):
+ return self._userData
+
+
+class Event(object):
+
+
+ def __init__(self, id, name):
+ self._id = id
+ self._name = name
+
+ def __str__(self):
+ return 'Event(' + str(map(lambda key: str(key) + '=' +
+ str(self.__dict__[key]), self.__dict__.keys())) + ')'
+
+ @property
+ def id(self):
+ return self._id
+
+ @property
+ def name(self):
+ return self._name
+
+
+class Tag(object):
+
+
+ def __init__(self, id, name, photo_id_list_csv):
+ self._id = id
+ self._name = name
+ self._photoIDs = filter(lambda x: x != None and len(x) > 0,
+ string.split(photo_id_list_csv, ','))
+
+ def __str__(self):
+ return 'Tag(id=' + str(self.id) + ';name=' + str(self.name) + \
+ ';num photos=' + str(len(self.photoIDs)) + ')'
+
+ @property
+ def id(self):
+ return self._id
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def photoIDs(self):
+ return self._photoIDs
+
+
+class Photo(object):
+
+
+ def __init__(self, id, filename, width=None, height=None, filesize=None,
+ timestamp=None, eventID=None, title=''):
+ self._id = id
+ self._filename = filename
+ self._width = width
+ self._height = height
+ self._filesize = filesize
+ self._timestamp = timestamp
+ self._eventID = eventID
+ self._title = title
+
+ def __str__(self):
+ return 'Photo(' + str(map(lambda key: str(key) + '=' +
+ str(self.__dict__[key]), self.__dict__.keys())) + ')'
+
+ @property
+ def id(self):
+ return self._id
+
+ @property
+ def filename(self):
+ return self._filename
+
+ @property
+ def width(self):
+ return self._width
+
+ @property
+ def height(self):
+ return self._height
+
+ @property
+ def filesize(self):
+ return self._filesize
+
+ @property
+ def timestamp(self):
+ return self._timestamp
+
+ @property
+ def eventID(self):
+ return self._eventID
+
+ @property
+ def title(self):
+ return self._title
+
+
+class _ReadOnlySqlite3Database(object):
+
+
+ def __init__(self, dbFile):
+ self._con = sqlite3.connect(dbFile)
+ self._con.row_factory = sqlite3.Row
+
+ def _selectOne(self, selectSQL, rowMapper):
+ return self._selectMany(selectSQL, rowMapper)[0]
+
+ def _selectMany(self, selectSQL, rowMapper):
+ cursor = self._con.cursor()
+ try:
+ cursor.execute(selectSQL)
+ return map(rowMapper, cursor.fetchall())
+ finally:
+ cursor.close()
+
+ def close(self):
+ if self._con != None:
+ self._con.close()
+ self._con = None
+
+
+class RowMapper:
+
+
+ @staticmethod
+ def version(row):
+ return Version(row['schema_version'], row['app_version'],
+ row['user_data'])
+
+ @staticmethod
+ def event(row):
+ return Event(row['id'], row['name'])
+
+ @staticmethod
+ def tag(row):
+ return Tag(row['id'], row['name'], row['photo_id_list'])
+
+ @staticmethod
+ def photo(row):
+ return Photo(row['id'], row['filename'], row['width'], row['height'],
+ row['filesize'], row['timestamp'], row['event_id'])
+
+ @staticmethod
+ def photo_with_title(row):
+ return Photo(row['id'], row['filename'], row['width'], row['height'],
+ row['filesize'], row['timestamp'], row['event_id'],
+ row['title'])
+
+
+class ShotwellDB(_ReadOnlySqlite3Database):
+
+
+ _PHOTO_SQL_NO_TITLE = 'select id, filename, width, height, filesize,' + \
+ ' timestamp, event_id from PhotoTable'
+ _PHOTO_SQL_WITH_TITLE = 'select id, filename, width, height, filesize,' + \
+ ' timestamp, event_id, title from PhotoTable'
+
+ def __init__(self, sqlitePath=os.path.join(os.path.expanduser('~'),
+ '.shotwell', 'data',
+ 'photo.db')):
+ _ReadOnlySqlite3Database.__init__(self, sqlitePath)
+
+ def __str__(self):
+ return 'ShotwellDB(' + str(map(lambda key: str(key) + '=' +
+ str(self.__dict__[key]), self.__dict__.keys())) + ')'
+
+ def version(self):
+ return self._selectOne('select schema_version, app_version,' +
+ ' user_data from VersionTable',
+ RowMapper.version)
+
+ def event(self, id):
+ return self._selectOne('select id, name from EventTable where id = ' +
+ str(id), RowMapper.event)
+
+ def events(self):
+ return self._selectMany('select id, name from EventTable',
+ RowMapper.event)
+
+ def tag(self, id):
+ return self._selectOne('select id, name, photo_id_list from' +
+ ' TagTable where id = ' + str(id),
+ RowMapper.tag)
+
+ def tags(self):
+ return self._selectMany('select id, name, photo_id_list from TagTable',
+ RowMapper.tag)
+
+ def photo(self, id):
+ if self.version().schemaVersion < 5:
+ return self._selectOne(self._PHOTO_SQL_NO_TITLE + ' where id = ' +
+ str(id), RowMapper.photo)
+ else:
+ return self._selectOne(self._PHOTO_SQL_WITH_TITLE +
+ ' where id = ' + str(id),
+ RowMapper.photo_with_title)
+
+ def photos(self):
+ if self.version().schemaVersion < 5:
+ return self._selectMany(self._PHOTO_SQL_NO_TITLE, RowMapper.photo)
+ else:
+ return self._selectMany(self._PHOTO_SQL_WITH_TITLE,
+ RowMapper.photo_with_title)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]