Remove broken Flattr integration

This commit is contained in:
Thomas Perl 2016-02-03 20:15:41 +01:00
parent f5e7390d23
commit 24ec3e0a9d
14 changed files with 6 additions and 571 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--*- mode: xml -*-->
<interface>
<object class="GtkDialog" id="gPodderFlattrSignIn">
<property name="visible">True</property>
<property name="has_separator">False</property>
<property name="title" translatable="yes">Sign in to Flattr</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="modal">True</property>
<property name="default_width">700</property>
<property name="default_height">570</property>
<property name="destroy_with_parent">False</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<child internal-child="vbox">
<object class="GtkVBox" id="vbox_flattr">
<property name="visible">True</property>
<property name="spacing">0</property>
<property name="border_width">0</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow_web">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
</child>
</object>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="btn_close">
<property name="visible">True</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<signal handler="on_btn_close_clicked" name="clicked"/>
</object>
<packing>
<property name="padding">15</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -307,58 +307,6 @@
<property name="tab-label" translatable="yes">Extensions</property>
</packing>
</child>
<child>
<object class="GtkTable" id="flattr_config">
<property name="border_width">6</property>
<property name="column_spacing">6</property>
<property name="n_columns">3</property>
<property name="n_rows">3</property>
<property name="row_spacing">6</property>
<property name="visible">True</property>
<child>
<object class="GtkLabel" id="label_flattr">
<property name="label" translatable="yes">Please sign in with Flattr and Support Publishers</property>
<property name="use_markup">True</property>
<property name="visible">True</property>
</object>
<packing>
<property name="bottom_attach">2</property>
<property name="top_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_flattr_login">
<property name="label" translatable="yes">Sign in</property>
<property name="visible">True</property>
<signal handler="on_button_flattr_login" name="clicked"/>
</object>
<packing>
<property name="bottom_attach">3</property>
<property name="x_options">fill</property>
<property name="top_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="checkbutton_flattr_on_play">
<property name="label" translatable="yes">Automatically flattr episodes on playback</property>
<property name="visible">True</property>
<signal handler="on_check_flattr_on_play" name="toggled"/>
</object>
<packing>
<property name="bottom_attach">4</property>
<property name="top_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
</object>
<packing>
<property name="tab-label" translatable="no">Flattr</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkTable" id="mygpo_config">
<property name="border_width">6</property>

View File

@ -192,11 +192,6 @@ defaults = {
'extensions': {
'enabled': [],
},
'flattr': {
'token': '',
'flattr_on_play': False,
},
}
# The sooner this goes away, the better

View File

@ -28,7 +28,6 @@ from gpodder import config
from gpodder import dbsqlite
from gpodder import extensions
from gpodder import model
from gpodder import flattr
class Core(object):
@ -53,9 +52,6 @@ class Core(object):
# Update the current device in the configuration
self.config.mygpo.device.type = util.detect_device_type()
# Initialize Flattr integration
self.flattr = flattr.Flattr(self.config.flattr)
def shutdown(self):
# Notify all extensions that we are being shut down
gpodder.user_extensions.shutdown()

View File

@ -1,238 +0,0 @@
# -*- coding: utf-8 -*-
#
# gPodder - A media aggregator and podcast client
# Copyright (c) 2005-2016 Thomas Perl and the gPodder Team
#
# gPodder is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# gPodder is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
# flattr.py -- gPodder Flattr integration
# Bernd Schlapsi <brot@gmx.info> 2012-05-26
#
import atexit
import os
import urllib
import urllib2
import urlparse
import json
import logging
logger = logging.getLogger(__name__)
from gpodder import minidb
from gpodder import util
import gpodder
_ = gpodder.gettext
class FlattrAction(object):
__slots__ = {'url': str}
def __init__(self, url):
self.url = url
class Flattr(object):
STORE_FILE = 'flattr.cache'
KEY = 'DD2bUSu1TJ7voHz9yNgtC7ld54lKg29Kw2MhL68uG5QUCgT1UZkmXvpSqBtxut7R'
SECRET = 'lJYWGXhcTXWm4FdOvn0iJg1ZIkm3DkKPTzCpmJs5xehrKk55yWe736XCg9vKj5p3'
CALLBACK = 'http://gpodder.org/flattr/token.html'
GPODDER_THING = ('https://flattr.com/submit/auto?' +
'user_id=thp&url=http://gpodder.org/')
# OAuth URLs
OAUTH_BASE = 'https://flattr.com/oauth'
AUTH_URL_TEMPLATE = (OAUTH_BASE + '/authorize?scope=flattr&' +
'response_type=code&client_id=%(client_id)s&' +
'redirect_uri=%(redirect_uri)s')
OAUTH_TOKEN_URL = OAUTH_BASE + '/token'
# REST API URLs
API_BASE = 'https://api.flattr.com/rest/v2'
USER_INFO_URL = API_BASE + '/user'
FLATTR_URL = API_BASE + '/flattr'
THING_INFO_URL_TEMPLATE = API_BASE + '/things/lookup/?url=%(url)s'
def __init__(self, config):
self._config = config
self._store = minidb.Store(os.path.join(gpodder.home, self.STORE_FILE))
self._worker_thread = None
atexit.register(self._at_exit)
def _at_exit(self):
self._worker_proc()
self._store.close()
def _worker_proc(self):
self._store.commit()
if not self.api_reachable():
self._worker_thread = None
return
logger.debug('Processing stored flattr actions...')
for flattr_action in self._store.load(FlattrAction):
success, message = self.flattr_url(flattr_action.url)
if success:
self._store.remove(flattr_action)
self._store.commit()
self._worker_thread = None
def api_reachable(self):
reachable, response = util.website_reachable(self.API_BASE)
if not reachable:
return False
try:
content = response.readline()
content = json.loads(content)
if 'message' in content and content['message'] == 'hello_world':
return True
except ValueError as err:
pass
return False
def request(self, url, data=None):
headers = {'Content-Type': 'application/json'}
if url == self.OAUTH_TOKEN_URL:
# Inject username and password into the request URL
url = util.url_add_authentication(url, self.KEY, self.SECRET)
elif self._config.token:
headers['Authorization'] = 'Bearer ' + self._config.token
if data is not None:
data = json.dumps(data)
try:
response = util.urlopen(url, headers, data)
except urllib2.HTTPError, error:
return {'_gpodder_statuscode': error.getcode()}
except urllib2.URLError, error:
return {'_gpodder_no_connection': False}
if response.getcode() == 200:
return json.loads(response.read())
return {'_gpodder_statuscode': response.getcode()}
def get_auth_url(self):
return self.AUTH_URL_TEMPLATE % {
'client_id': self.KEY,
'redirect_uri': self.CALLBACK,
}
def has_token(self):
return bool(self._config.token)
def process_retrieved_code(self, url):
url_parsed = urlparse.urlparse(url)
query = urlparse.parse_qs(url_parsed.query)
if 'code' in query:
code = query['code'][0]
logger.info('Got code: %s', code)
self._config.token = self._request_access_token(code)
return True
return False
def _request_access_token(self, code):
request_url = 'https://flattr.com/oauth/token'
params = {
'code': code,
'grant_type': 'authorization_code',
'redirect_uri': self.CALLBACK,
}
content = self.request(self.OAUTH_TOKEN_URL, data=params)
return content.get('access_token', '')
def get_thing_info(self, payment_url):
"""Get information about a Thing on Flattr
Return a tuple (flattrs, flattred):
flattrs ... The number of Flattrs this thing received
flattred ... True if this user already flattred this thing
"""
if not self._config.token:
return (0, False)
quote_url = urllib.quote_plus(util.sanitize_encoding(payment_url))
url = self.THING_INFO_URL_TEMPLATE % {'url': quote_url}
data = self.request(url)
return (int(data.get('flattrs', 0)), bool(data.get('flattred', False)))
def get_auth_username(self):
if not self._config.token:
return ''
data = self.request(self.USER_INFO_URL)
return data.get('username', '')
def flattr_url(self, payment_url):
"""Flattr an object given its Flattr payment URL
Returns a tuple (success, message):
success ... True if the item was Flattr'd
message ... The success or error message
"""
params = {
'url': payment_url
}
content = self.request(self.FLATTR_URL, data=params)
if '_gpodder_statuscode' in content:
status_code = content['_gpodder_statuscode']
if status_code == 401:
return (False, _('Not enough means to flattr'))
elif status_code == 404:
return (False, _('Item does not exist on Flattr'))
elif status_code == 403:
return (True, _('Already flattred or own item'))
else:
return (False, _('Invalid request'))
if '_gpodder_no_connection' in content:
if not self._store.get(FlattrAction, url=payment_url):
flattr_action = FlattrAction(payment_url)
self._store.save(flattr_action)
return (False, _('No internet connection'))
if self._worker_thread is None:
self._worker_thread = util.run_in_background(lambda: self._worker_proc(), True)
return (True, content.get('description', _('No description')))
def is_flattr_url(self, url):
if 'flattr.com' in url:
return True
return False
def is_flattrable(self, url):
if self._config.token and self.is_flattr_url(url):
return True
return False

View File

@ -111,36 +111,6 @@ class OnSyncActionList(gtk.ListStore):
class gPodderFlattrSignIn(BuilderWidget):
def new(self):
import webkit
self.web = webkit.WebView()
self.web.connect('resource-request-starting', self.on_web_request)
self.main_window.connect('destroy', self.set_flattr_preferences)
auth_url = self.flattr.get_auth_url()
logger.info(auth_url)
self.web.open(auth_url)
self.scrolledwindow_web.add(self.web)
self.web.show()
def on_web_request(self, web_view, web_frame, web_resource, request, response):
uri = request.get_uri()
if uri.startswith(self.flattr.CALLBACK):
if not self.flattr.process_retrieved_code(uri):
self.show_message(query['error_description'][0], _('Error'),
important=True)
# Destroy the window later
util.idle_add(self.main_window.destroy)
def on_btn_close_clicked(self, widget):
util.idle_add(self.main_window.destroy)
class YouTubeVideoFormatListModel(gtk.ListStore):
C_CAPTION, C_ID = range(2)
@ -319,9 +289,6 @@ class gPodderPreferences(BuilderWidget):
# Disable mygpo sync while the dialog is open
self._config.mygpo.enabled = False
# Initialize Flattr settings
self.set_flattr_preferences()
# Configure the extensions manager GUI
self.set_extension_preferences()
@ -409,14 +376,8 @@ class gPodderPreferences(BuilderWidget):
menu.append(menu_item)
if container.metadata.payment:
if self.flattr.is_flattrable(container.metadata.payment):
menu_item = gtk.MenuItem(_('Flattr this'))
menu_item.connect('activate', self.flattr_extension,
container.metadata.payment)
else:
menu_item = gtk.MenuItem(_('Support the author'))
menu_item.connect('activate', self.open_weblink,
container.metadata.payment)
menu_item = gtk.MenuItem(_('Support the author'))
menu_item.connect('activate', self.open_weblink, container.metadata.payment)
menu.append(menu_item)
menu.show_all()
@ -428,37 +389,6 @@ class gPodderPreferences(BuilderWidget):
return True
def set_flattr_preferences(self, widget=None):
if not self._config.flattr.token:
self.label_flattr.set_text(_('Please sign in with Flattr and Support Publishers'))
self.button_flattr_login.set_label(_('Sign in to Flattr'))
else:
flattr_user = self.flattr.get_auth_username()
self.label_flattr.set_markup(_('Logged in as <b>%(username)s</b>') % {'username': flattr_user})
self.button_flattr_login.set_label(_('Sign out'))
self.checkbutton_flattr_on_play.set_active(self._config.flattr.flattr_on_play)
def on_button_flattr_login(self, widget):
if not self._config.flattr.token:
try:
import webkit
except ImportError, ie:
self.show_message(_('Flattr integration requires WebKit/Gtk.'),
_('WebKit/Gtk not found'), important=True)
return
gPodderFlattrSignIn(self.parent_window,
_config=self._config,
flattr=self.flattr,
set_flattr_preferences=self.set_flattr_preferences)
else:
self._config.flattr.token = ''
self.set_flattr_preferences()
def on_check_flattr_on_play(self, widget):
self._config.flattr.flattr_on_play = widget.get_active()
def on_extensions_cell_toggled(self, cell, path):
model = self.treeviewExtensions.get_model()
it = model.get_iter(path)
@ -498,11 +428,6 @@ class gPodderPreferences(BuilderWidget):
def open_weblink(self, w, url):
util.open_website(url)
def flattr_extension(self, w, flattr_url):
success, message = self.flattr.flattr_url(flattr_url)
self.show_message(message, title=_('Flattr status'),
important=not success)
def on_dialog_destroy(self, widget):
# Re-enable mygpo sync if the user has selected it
self._config.mygpo.enabled = self._enable_mygpo

View File

@ -303,38 +303,6 @@ def cairo_surface_to_pixbuf(s):
return pixbuf
def draw_flattr_button(widget, flattr_image, flattrs_count):
"""
Adds the flattrs count to the flattr button
"""
if isinstance(flattrs_count, int):
flattrs_count = str(flattrs_count)
pixbuf = gtk.gdk.pixbuf_new_from_file(flattr_image)
iwidth, iheight = pixbuf.get_width(), pixbuf.get_height()
pixmap, mask = pixbuf.render_pixmap_and_mask()
# get default-font
style = widget.rc_get_style()
font_desc = style.font_desc
#font_desc.set_size(12*pango.SCALE)
font_desc.set_size(9*pango.SCALE)
# set font and text
layout = widget.create_pango_layout(flattrs_count)
layout.set_font_description(font_desc)
fwidth, fheight = layout.get_pixel_size()
x = 95 - abs(fwidth / 2) # 95 is the center of the bubble
y = abs(iheight / 2) - abs(fheight / 2)
cm = pixmap.get_colormap()
red = cm.alloc_color('black')
gc = pixmap.new_gc(foreground=red)
pixmap.draw_layout(gc, x, y, layout)
widget.set_from_pixmap(pixmap, mask)
def progressbar_pixbuf(width, height, percentage):
COLOR_BG = (.4, .4, .4, .4)
COLOR_FG = (.2, .9, .2, 1.)

View File

@ -1,65 +0,0 @@
# -*- coding: utf-8 -*-
#
# gPodder - A media aggregator and podcast client
# Copyright (c) 2005-2016 Thomas Perl and the gPodder Team
#
# gPodder is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# gPodder is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import gtk
import gtk.gdk
import os.path
import gpodder
_ = gpodder.gettext
from gpodder.gtkui import draw
IMAGE_FLATTR = os.path.join(gpodder.images_folder, 'button-flattr.png')
IMAGE_FLATTR_GREY = os.path.join(gpodder.images_folder, 'button-flattr-grey.png')
IMAGE_FLATTRED = os.path.join(gpodder.images_folder, 'button-flattred.png')
def set_flattr_button(flattr, payment_url, widget_image, widget_button):
if not flattr.api_reachable() or not payment_url:
widget_image.hide()
widget_button.hide()
return False
elif not flattr.has_token():
badge = IMAGE_FLATTR_GREY
button_text = _('Sign in')
return False
flattrs, flattred = flattr.get_thing_info(payment_url)
can_flattr_this = False
if flattred:
badge = IMAGE_FLATTRED
button_text = _('Flattred')
else:
badge = IMAGE_FLATTR
button_text = _('Flattr this')
can_flattr_this = True
widget_button.set_label(button_text)
widget_button.set_sensitive(can_flattr_this)
widget_button.show()
draw.draw_flattr_button(widget_image, badge, flattrs)
widget_image.show()
return can_flattr_this

View File

@ -84,7 +84,6 @@ from gpodder.gtkui.desktop.podcastdirectory import gPodderPodcastDirectory
from gpodder.gtkui.interface.progress import ProgressIndicator
from gpodder.gtkui.desktop.sync import gPodderSyncUI
from gpodder.gtkui import flattr
from gpodder.gtkui import shownotes
from gpodder.dbusproxy import DBusPodcastsProxy
@ -118,7 +117,6 @@ class gPodder(BuilderWidget, dbus.service.Object):
self.config = self.core.config
self.db = self.core.db
self.model = self.core.model
self.flattr = self.core.flattr
self.options = options
BuilderWidget.__init__(self, None)
@ -1695,7 +1693,6 @@ class gPodder(BuilderWidget, dbus.service.Object):
episodes = self.get_selected_episodes()
any_locked = any(e.archive for e in episodes)
any_new = any(e.is_new for e in episodes)
any_flattrable = any(e.payment_url for e in episodes)
downloaded = all(e.was_downloaded(and_exists=True) for e in episodes)
downloading = any(e.downloading for e in episodes)
@ -1783,12 +1780,6 @@ class gPodder(BuilderWidget, dbus.service.Object):
item.connect('activate', lambda w: self.on_item_toggle_lock_activate( w, False, not any_locked))
menu.append(item)
if any_flattrable and self.config.flattr.token:
menu.append(gtk.SeparatorMenuItem())
item = gtk.MenuItem(_('Flattr this'))
item.connect('activate', self.flattr_selected_episodes)
menu.append(item)
menu.append(gtk.SeparatorMenuItem())
# Single item, add episode information menu item
item = gtk.ImageMenuItem(_('Episode details'))
@ -1913,13 +1904,6 @@ class gPodder(BuilderWidget, dbus.service.Object):
except Exception, e:
logger.error('Calling Panucci using D-Bus', exc_info=True)
# flattr episode if auto-flattr is enabled
if (episode.payment_url and self.config.flattr.token and
self.config.flattr.flattr_on_play):
success, message = self.flattr.flattr_url(episode.payment_url)
self.show_message(message, title=_('Flattr status'),
important=not success)
groups[player].append(filename)
# Open episodes with system default player
@ -2685,15 +2669,6 @@ class gPodder(BuilderWidget, dbus.service.Object):
episode.mark_old()
self.on_selected_episodes_status_changed()
def flattr_selected_episodes(self, w=None):
if not self.config.flattr.token:
return
for episode in [e for e in self.get_selected_episodes() if e.payment_url]:
success, message = self.flattr.flattr_url(episode.payment_url)
self.show_message(message, title=_('Flattr status'),
important=not success)
def on_item_toggle_played_activate( self, widget, toggle = True, new_value = False):
for episode in self.get_selected_episodes():
if toggle:
@ -2912,7 +2887,6 @@ class gPodder(BuilderWidget, dbus.service.Object):
def on_itemPreferences_activate(self, widget, *args):
gPodderPreferences(self.main_window, \
_config=self.config, \
flattr=self.flattr, \
user_apps_reader=self.user_apps_reader, \
parent_window=self.main_window, \
mygpo_client=self.mygpo_client, \
@ -2968,8 +2942,7 @@ class gPodder(BuilderWidget, dbus.service.Object):
cover_downloader=self.cover_downloader,
sections=set(c.section for c in self.channels),
clear_cover_cache=self.podcast_list_model.clear_cover_cache,
_config=self.config,
_flattr=self.flattr)
_config=self.config)
def on_itemMassUnsubscribe_activate(self, item=None):
columns = (

View File

@ -36,7 +36,6 @@ import logging
logger = logging.getLogger(__name__)
from gpodder.gtkui import draw
from gpodder.gtkui import flattr
import os
import gtk

View File

@ -51,15 +51,6 @@ import string
_ = gpodder.gettext
def get_payment_priority(url):
"""
at the moment we only support flattr.com as an payment provider, so we
sort the payment providers and prefer flattr.com ("1" is higher priority than "2")
"""
if 'flattr.com' in url:
return 1
return 2
class CustomFeed(feedcore.ExceptionWithData): pass
class gPodderFetcher(feedcore.Fetcher):
@ -205,11 +196,10 @@ class PodcastEpisode(PodcastModelObject):
# get the desired enclosure picked by the algorithm below.
filter_and_sort_enclosures = lambda x: x
# read the flattr auto-url, if exists
payment_info = [link['href'] for link in entry.get('links', [])
if link['rel'] == 'payment']
if payment_info:
episode.payment_url = sorted(payment_info, key=get_payment_priority)[0]
episode.payment_url = payment_info[0]
# Enclosures
for e in filter_and_sort_enclosures(enclosures):
@ -1029,11 +1019,11 @@ class PodcastChannel(PodcastModelObject):
elif hasattr(feed.feed, 'icon'):
cover_url = feed.feed.icon
# Payment URL (Flattr auto-payment) information
# Payment URL information
payment_info = [link['href'] for link in feed.feed.get('links', [])
if link['rel'] == 'payment']
if payment_info:
payment_url = sorted(payment_info, key=get_payment_priority)[0]
payment_url = payment_info[0]
else:
payment_url = None