[kupfer] plugins: +gwibber (k) plugin (microblogging with gwibber).
- From: Ulrik Sverdrup <usverdrup src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [kupfer] plugins: +gwibber (k) plugin (microblogging with gwibber).
- Date: Sat, 5 Mar 2011 18:18:20 +0000 (UTC)
commit 384f824421879743439c1ccdbea884426942ea53
Author: Karol BÄ?dkowski <karol bedkowski gmail com>
Date: Fri Mar 4 14:45:14 2011 +0100
plugins: +gwibber (k) plugin (microblogging with gwibber).
Gwibber can send and receive messages from many social services.
Plugin show accounts defined in gwibber, show messages received
for all accounts and streams defined in Gwibber.
Plugin allow to post new messages (text leaves), delete own messages,
reply and retweet messages from other, open messages in browser.
Require gwibber-services for work and gwibber for configure services.
Communicate with gwibber by dbus.
kupfer/plugin/gwibber_k.py | 532 ++++++++++++++++++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
2 files changed, 533 insertions(+), 0 deletions(-)
---
diff --git a/kupfer/plugin/gwibber_k.py b/kupfer/plugin/gwibber_k.py
new file mode 100644
index 0000000..ff6701b
--- /dev/null
+++ b/kupfer/plugin/gwibber_k.py
@@ -0,0 +1,532 @@
+# -*- coding: UTF-8 -*-
+from __future__ import absolute_import
+__kupfer_name__ = _("Gwibber (K)")
+__kupfer_sources__ = ("HomeMessagesSource", "AccountsSource", "StreamsSource")
+__kupfer_actions__ = ("SendMessage", "SendMessageBy", "SendMessageTo")
+__description__ = _("Microblogging with Gwibber. Allow to send and receiving "
+ "messages from some social networks, like Twitter, Buzz etc. "
+ "Require gwibber-service package.")
+__version__ = "2011-03-04"
+__author__ = "Karol BÄ?dkowski <karol bedkowski gmail com>"
+
+import dbus
+import time
+try:
+ import cjson
+ json_decoder = cjson.decode
+ json_encoder = cjson.encode
+except ImportError:
+ import json
+ json_decoder = json.loads
+ json_encoder = json.dumps
+
+# quick test is gwibber-service installed
+import gwibber.microblog
+
+from kupfer import icons
+from kupfer import pretty
+from kupfer import plugin_support
+from kupfer.objects import Action, TextLeaf, Source, Leaf
+from kupfer.obj.objects import OpenUrl
+from kupfer.weaklib import dbus_signal_connect_weakly
+
+plugin_support.check_dbus_connection()
+
+DBUS_GWIBBER_SERVICE = ('com.Gwibber.Service', '/com/gwibber/Service')
+DBUS_GWIBBER_ACCOUNTS = ('com.Gwibber.Accounts', '/com/gwibber/Accounts')
+DBUS_GWIBBER_STREAMS = ('com.Gwibber.Streams', '/com/gwibber/Streams')
+DBUS_GWIBBER_MESSAGES = ('com.Gwibber.Messages', '/com/gwibber/Messages')
+DBUS_GWIBBER_SEARCH = ('com.Gwibber.Search', '/com/gwibber/Search')
+
+__kupfer_settings__ = plugin_support.PluginSettings(
+ {
+ 'key': 'load_limit',
+ 'label': _("Max messages to show"),
+ 'type': int,
+ 'value': 25,
+ }
+)
+
+
+def _get_dbus_iface(service_objname, activate=False):
+ interface = None
+ sbus = dbus.SessionBus()
+ service, objname = service_objname
+ try:
+ proxy_obj = sbus.get_object('org.freedesktop.DBus',
+ '/org/freedesktop/DBus')
+ dbus_iface = dbus.Interface(proxy_obj, 'org.freedesktop.DBus')
+ if activate or dbus_iface.NameHasOwner(service):
+ obj = sbus.get_object(service, objname)
+ if obj:
+ interface = dbus.Interface(obj, service)
+ except dbus.exceptions.DBusException, err:
+ pretty.print_debug(err)
+ return interface
+
+
+def _get_messages_for_account(stream, account, transient='0'):
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE, True)
+ if not conn:
+ return
+ services = json_decoder(conn.GetServices())
+ conn = _get_dbus_iface(DBUS_GWIBBER_STREAMS)
+ if not conn:
+ return
+ result = conn.Messages(stream, account, 0, '0', transient, 'time', 'desc',
+ __kupfer_settings__['load_limit'])
+ for msg in json_decoder(result):
+ yield Message(msg['text'], msg, services[msg['service']])
+
+
+def _gwibber_refresh(conn=None):
+ conn = conn or _get_dbus_iface(DBUS_GWIBBER_SERVICE, True)
+ if conn:
+ conn.Refresh()
+
+
+def _trunc_message(message):
+ return message[:139] + 'â?¦' if len(message) > 140 else message
+
+
+class Account(Leaf):
+ def __init__(self, account, service_name, show_content=True):
+ Leaf.__init__(self, account['id'], service_name)
+ self._show_content = show_content
+ self._description = _("%(user)s on %(service)s") % {
+ 'user': account.get('site_display_name') or account['username'],
+ 'service': account['service']}
+
+ def __repr__(self):
+ return 'Message: %r' % repr(self.__dict__)
+
+ def get_icon_name(self):
+ return 'gwibber'
+
+ def has_content(self):
+ return self._show_content
+
+ def content_source(self, alternate=False):
+ return MessagesSource(self.object, self.name)
+
+ def get_description(self):
+ return self._description
+
+
+class Stream(Leaf):
+ def __init__(self, name, id_, account):
+ Leaf.__init__(self, id_, name)
+ self.account = account
+
+ def __repr__(self):
+ return 'Message: %r' % repr(self.__dict__)
+
+ def get_icon_name(self):
+ return 'gwibber'
+
+ def has_content(self):
+ return True
+
+ def content_source(self, alternate=False):
+ return StreamMessagesSource(self)
+
+
+class Message(TextLeaf):
+ def __init__(self, text, msg, service):
+ TextLeaf.__init__(self, text)
+ self.id = msg['id']
+ self.msg_url = msg.get('url')
+ self.msg_sender = msg['sender']['nick'] if 'nick' in msg['sender'] \
+ else msg['sender']['name']
+ self._service_features = list(service['features'])
+ self._is_my_msg = bool(msg['sender']['is_me'])
+ sender = str(msg['sender'].get('name') or msg['sender']['nick'])
+ date = time.strftime('%x %X', time.localtime(msg['time']))
+ self._description = _("%(user)s %(when)s on %(where)s") % {
+ 'user': sender, 'when': date, 'where': service['name']}
+
+ def __repr__(self):
+ return 'Message: %r' % repr(self.__dict__)
+
+ def get_actions(self):
+ service_features = self._service_features
+ if self._is_my_msg:
+ if 'delete' in service_features:
+ yield DeleteMessage()
+ else:
+ if 'reply' in service_features:
+ yield Reply()
+ if 'send_private' in service_features:
+ yield SendPrivate()
+ if 'retweet' in service_features:
+ yield Retweet()
+ yield Retweet(True)
+ if self.msg_url:
+ yield OpenMessageUrl()
+
+ def get_description(self):
+ return self._description
+
+ def get_gicon(self):
+ return icons.ComposedIcon("gwibber", "stock_mail")
+
+
+class SendMessage(Action):
+ def __init__(self):
+ Action.__init__(self, _('Send Message'))
+
+ def activate(self, leaf):
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE, True)
+ if conn:
+ conn.SendMessage(_trunc_message(leaf.object))
+ _gwibber_refresh()
+
+ def item_types(self):
+ yield TextLeaf
+
+ def valid_for_item(self, item):
+ return bool(item.object)
+
+ def get_gicon(self):
+ return icons.ComposedIcon("gwibber", "mail-message-new")
+
+ def get_description(self):
+ return _("Send message to all Gwibber accounts")
+
+
+class SendMessageBy(Action):
+ def __init__(self):
+ Action.__init__(self, _("Send Message To..."))
+
+ def activate(self, leaf, iobj):
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE, True)
+ if conn:
+ msg = {'message': _trunc_message(leaf.object), 'accounts': [iobj.object]}
+ conn.Send(json_encoder(msg))
+ _gwibber_refresh()
+
+ def item_types(self):
+ yield TextLeaf
+
+ def valid_for_item(self, item):
+ return bool(item.object)
+
+ def requires_object(self):
+ return True
+
+ def object_types(self):
+ yield Account
+
+ def object_source(self, for_item=None):
+ return SendToAccountSource('send')
+
+ def get_gicon(self):
+ return icons.ComposedIcon("gwibber", "mail-message-new")
+
+ def get_description(self):
+ return _("Send message to one Gwibber account")
+
+
+class SendMessageTo(Action):
+ def __init__(self):
+ Action.__init__(self, _("Send Message..."))
+
+ def activate(self, leaf, iobj):
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE, True)
+ if conn:
+ msg = {'message': _trunc_message(iobj.object),
+ 'accounts': [leaf.object]}
+ conn.Send(json_encoder(msg))
+ _gwibber_refresh()
+
+ def item_types(self):
+ yield Account
+
+ def requires_object(self):
+ return True
+
+ def object_types(self):
+ yield TextLeaf
+
+ def get_gicon(self):
+ return icons.ComposedIcon("gwibber", "mail-message-new")
+
+ def get_description(self):
+ return _("Send message to selected Gwibber account")
+
+
+class Reply(Action):
+ def __init__(self):
+ Action.__init__(self, _("Reply"))
+
+ def activate(self, leaf, iobj):
+ conn = _get_dbus_iface(DBUS_GWIBBER_MESSAGES, True)
+ if not conn:
+ return
+ rmsg = json_decoder(conn.Get(leaf.id))
+ text = '@%s: %s' % (rmsg['sender']['nick'], iobj.object)
+ msg = {'message': _trunc_message(text), 'target': rmsg}
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE)
+ if conn:
+ conn.Send(json_encoder(msg))
+ _gwibber_refresh()
+
+ def item_types(self):
+ yield Message
+
+ def requires_object(self):
+ return True
+
+ def object_types(self):
+ yield TextLeaf
+
+ def get_gicon(self):
+ return icons.ComposedIcon("gwibber", "mail-reply-all")
+
+
+class DeleteMessage(Action):
+ def __init__(self):
+ Action.__init__(self, _("Delete Message"))
+
+ def activate(self, leaf):
+ conn = _get_dbus_iface(DBUS_GWIBBER_MESSAGES, True)
+ if not conn:
+ return
+ rmsg = json_decoder(conn.Get(leaf.id))
+ cmd = {'transient': False, 'account': rmsg['account'],
+ 'operation': 'delete', 'args': {'message': rmsg}}
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE)
+ if conn:
+ conn.PerformOp(json_encoder(cmd))
+ _gwibber_refresh(conn)
+
+ def item_types(self):
+ yield Message
+
+ def get_gicon(self):
+ return icons.ComposedIcon("gwibber", "stock_delete")
+
+
+class SendPrivate(Action):
+ def __init__(self):
+ Action.__init__(self, _("Send Private Message"))
+
+ def activate(self, leaf, iobj):
+ conn = _get_dbus_iface(DBUS_GWIBBER_MESSAGES, True)
+ if not conn:
+ return
+ rmsg = json_decoder(conn.Get(leaf.id))
+ msg = {'message': _trunc_message(iobj.object), 'private': rmsg}
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE)
+ if conn:
+ conn.Send(json_encoder(msg))
+ _gwibber_refresh()
+
+ def item_types(self):
+ yield Message
+
+ def requires_object(self):
+ return True
+
+ def object_types(self):
+ yield TextLeaf
+
+ def get_gicon(self):
+ return icons.ComposedIcon("gwibber", "mail-reply-sender")
+
+ def get_description(self):
+ return _("Send direct message to user")
+
+
+class Retweet(Action):
+ def __init__(self, retweet_to_all=False):
+ self._retweet_to_all = retweet_to_all
+ name = _("Retweet") if retweet_to_all else _("Retweet to...")
+ Action.__init__(self, name)
+
+ def activate(self, leaf, iobj=None):
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE, True)
+ if conn:
+ text = 'â?º @%s: %s' % (leaf.msg_sender, leaf.object)
+ if iobj:
+ msg = {'message': _trunc_message(text), 'accounts': [iobj.object]}
+ conn.Send(json_encoder(msg))
+ else:
+ conn.SendMessage(_trunc_message(text))
+ _gwibber_refresh()
+
+ def item_types(self):
+ yield Message
+
+ def requires_object(self):
+ return not self._retweet_to_all
+
+ def object_types(self):
+ yield Account
+
+ def object_source(self, for_item=None):
+ return SendToAccountSource('retweet')
+
+ def get_gicon(self):
+ return icons.ComposedIcon("gwibber", "mail-message-forward")
+
+ def get_description(self):
+ if self._retweet_to_all:
+ return _("Retweet message to all Gwibber accounts")
+ return _("Retweet message to one Gwibber account")
+
+
+class OpenMessageUrl(OpenUrl):
+ def __init__(self):
+ OpenUrl.__init__(self, _("Open in Browser"))
+
+ def activate(self, leaf):
+ self.open_url(leaf.msg_url)
+
+ def get_description(self):
+ return _("Open message in default web browser")
+
+
+class AccountsSource(Source):
+ source_user_reloadable = True
+
+ def __init__(self, name=_("Gwibber Accounts")):
+ Source.__init__(self, name)
+
+ def initialize(self):
+ session_bus = dbus.Bus()
+ for signal in ('Created', 'Updated', 'Deleted'):
+ dbus_signal_connect_weakly(session_bus, signal,
+ self._signal_update, dbus_interface=DBUS_GWIBBER_ACCOUNTS[0])
+
+ def _signal_update(self, *args):
+ self.mark_for_update()
+
+ def get_items(self):
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE, True)
+ if not conn:
+ return
+ services = json_decoder(conn.GetServices())
+ del conn
+ if not services:
+ return
+ conn = _get_dbus_iface(DBUS_GWIBBER_ACCOUNTS, True)
+ if conn:
+ accounts = json_decoder(conn.List())
+ for account in accounts:
+ service = services[account['service']]
+ yield Account(account, service['name'])
+
+ def get_icon_name(self):
+ return 'gwibber'
+
+ def get_description(self):
+ return _("Accounts configured in Gwibber")
+
+
+class SendToAccountSource(Source):
+ def __init__(self, required_feature=None, name=_("Gwibber Accounts")):
+ Source.__init__(self, name)
+ self._required_feature = required_feature
+
+ def get_items(self):
+ conn = _get_dbus_iface(DBUS_GWIBBER_SERVICE, True)
+ if not conn:
+ return
+ services = json_decoder(conn.GetServices())
+ conn = _get_dbus_iface(DBUS_GWIBBER_ACCOUNTS, True)
+ if conn:
+ for account in json_decoder(conn.List()):
+ aservice = account['service']
+ if aservice not in services:
+ continue
+ service = services[aservice]
+ if not self._required_feature or \
+ self._required_feature in service['features']:
+ yield Account(account, service['name'], False)
+
+
+class HomeMessagesSource(Source):
+ # we don't connect to "gwibber" app as long we only need "gwibber-service".
+ source_user_reloadable = True
+
+ def __init__(self, name=_("Gwibber Messages")):
+ Source.__init__(self, name)
+
+ def initialize(self):
+ session_bus = dbus.Bus()
+ dbus_signal_connect_weakly(session_bus, 'Message',
+ self._signal_update, dbus_interface=DBUS_GWIBBER_MESSAGES[0])
+ dbus_signal_connect_weakly(session_bus, 'LoadingComplete',
+ self._signal_update, dbus_interface=DBUS_GWIBBER_SERVICE[0])
+ for signal in ('Created', 'Updated', 'Deleted'):
+ dbus_signal_connect_weakly(session_bus, signal,
+ self._signal_update, dbus_interface=DBUS_GWIBBER_STREAMS[0])
+
+ def _signal_update(self, *args):
+ self.mark_for_update()
+
+ def get_items(self):
+ return _get_messages_for_account('messages', 'all')
+
+ def get_icon_name(self):
+ return 'gwibber'
+
+ def get_description(self):
+ return _("Recent messages received by Gwibber")
+
+
+class MessagesSource(Source):
+ def __init__(self, account, service):
+ Source.__init__(self, _("Gwibber Messages for %s") % service)
+ self.account = account
+
+ def get_items(self):
+ return _get_messages_for_account('messages', self.account)
+
+ def get_icon_name(self):
+ return 'gwibber'
+
+
+class StreamsSource(Source):
+ source_user_reloadable = True
+
+ def __init__(self, name=_("Gwibber Streams")):
+ Source.__init__(self, name)
+
+ def initialize(self):
+ session_bus = dbus.Bus()
+ for signal in ('Created', 'Updated', 'Deleted'):
+ dbus_signal_connect_weakly(session_bus, signal,
+ self._signal_update, dbus_interface=DBUS_GWIBBER_STREAMS[0])
+ _gwibber_refresh()
+
+ def _signal_update(self, *args):
+ self.mark_for_update()
+
+ def get_items(self):
+ conn = _get_dbus_iface(DBUS_GWIBBER_STREAMS, True)
+ if conn:
+ for stream in json_decoder(conn.List()):
+ yield Stream(stream['name'], stream['id'], stream['account'])
+
+ def get_icon_name(self):
+ return 'gwibber'
+
+ def get_description(self):
+ return _("Streams configured in Gwibber")
+
+
+class StreamMessagesSource(Source):
+ def __init__(self, stream):
+ Source.__init__(self, _("Gwibber Messages in %s") % stream.name)
+ self._account = stream.account
+ self._stream_id = stream.object
+
+ def get_items(self):
+ conn = _get_dbus_iface(DBUS_GWIBBER_STREAMS, True)
+ if conn:
+ return _get_messages_for_account('all', self._account, self._stream_id)
+
+ def get_icon_name(self):
+ return 'gwibber'
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c29ec5a..4957239 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -80,6 +80,7 @@ kupfer/plugin/google_search.py
kupfer/plugin/google_translate.py
kupfer/plugin/gtg.py
kupfer/plugin/gwibber.py
+kupfer/plugin/gwibber_k.py
kupfer/plugin/higherorder.py
kupfer/plugin/image.py
kupfer/plugin/kupfer_plugins.py
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]