Initial support for uploading subscriptions to my.gpodder.org
This allows us to create a podcast toplist in the future and to provide some other user-based services.
This commit is contained in:
parent
b398eb42f2
commit
daf98f5235
|
@ -424,7 +424,23 @@
|
|||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_item_email_subscriptions_activate" last_modification_time="Mon, 28 Apr 2008 17:50:23 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkSeparatorMenuItem" id="separatorUpload">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkMenuItem" id="itemUploadToMygpo">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Upload list to my.gpodder.org</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="on_upload_to_mygpo"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
|
|
@ -128,6 +128,10 @@ gPodderSettings = {
|
|||
# Hide the cover/pill from the podcast sidebar when it gets too small
|
||||
'podcast_sidebar_save_space': (bool, False),
|
||||
|
||||
# Settings for my.gpodder.org
|
||||
'my_gpodder_username': (str, ''),
|
||||
'my_gpodder_password': (str, ''),
|
||||
|
||||
# Paned position
|
||||
'paned_position': ( int, 200 ),
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ from gpodder import services
|
|||
from gpodder import sync
|
||||
from gpodder import download
|
||||
from gpodder import SimpleGladeApp
|
||||
from gpodder import my
|
||||
from gpodder.liblogger import log
|
||||
from gpodder.dbsqlite import db
|
||||
from gpodder import resolver
|
||||
|
@ -223,7 +224,7 @@ class GladeWidget(SimpleGladeApp.SimpleGladeApp):
|
|||
|
||||
return response == affirmative
|
||||
|
||||
def UsernamePasswordDialog( self, title, message ):
|
||||
def UsernamePasswordDialog( self, title, message, username=None, password=None, username_prompt=_('Username')):
|
||||
""" An authentication dialog based on
|
||||
http://ardoris.wordpress.com/2008/07/05/pygtk-text-entry-dialog/ """
|
||||
|
||||
|
@ -236,22 +237,29 @@ class GladeWidget(SimpleGladeApp.SimpleGladeApp):
|
|||
dialog.set_markup('<span weight="bold" size="larger">' + title + '</span>')
|
||||
dialog.set_title(title)
|
||||
dialog.format_secondary_markup(message)
|
||||
dialog.set_default_response(gtk.RESPONSE_OK)
|
||||
|
||||
username_entry = gtk.Entry()
|
||||
username_entry.set_width_chars(25)
|
||||
username_entry.set_activates_default(True)
|
||||
password_entry = gtk.Entry()
|
||||
password_entry.set_width_chars(25)
|
||||
password_entry.set_visibility(False)
|
||||
password_entry.set_activates_default(True)
|
||||
if username is not None:
|
||||
username_entry.set_text(username)
|
||||
if password is not None:
|
||||
password_entry.set_text(password)
|
||||
|
||||
username_hbox = gtk.HBox()
|
||||
username_label = gtk.Label()
|
||||
username_label.set_markup('<b>' + _('Username:') + '</b>')
|
||||
username_label.set_markup('<b>' + username_prompt + ':</b>')
|
||||
username_hbox.pack_start(username_label, False, 5, 5)
|
||||
username_hbox.pack_end(username_entry, False)
|
||||
|
||||
password_hbox = gtk.HBox()
|
||||
password_label = gtk.Label()
|
||||
password_label.set_markup('<b>' + _('Password:') + '</b>')
|
||||
password_label.set_markup('<b>' + _('Password') + ':</b>')
|
||||
password_hbox.pack_start(password_label, False, 5, 5)
|
||||
password_hbox.pack_end(password_entry, False)
|
||||
|
||||
|
@ -2098,6 +2106,25 @@ class gPodder(GladeWidget):
|
|||
|
||||
gPodderAddPodcastDialog(url_callback=add_google_video_search, custom_title=_('Add Google Video search'), custom_label=_('Search for:'))
|
||||
|
||||
def on_upload_to_mygpo(self, widget):
|
||||
if not gl.config.my_gpodder_username or not gl.config.my_gpodder_password:
|
||||
success, authentication = self.UsernamePasswordDialog(_('My gPodder Login'), _('Please enter your e-mail address as username and pick a password. If the account does not exist, it will automatically be created.'), username=gl.config.my_gpodder_username, password=gl.config.my_gpodder_password, username_prompt=_('E-Mail Address'))
|
||||
if success:
|
||||
gl.config.my_gpodder_username, gl.config.my_gpodder_password = authentication
|
||||
else:
|
||||
return
|
||||
|
||||
if gl.config.my_gpodder_username and gl.config.my_gpodder_password:
|
||||
client = my.MygPodderClient(gl.config.my_gpodder_username, gl.config.my_gpodder_password)
|
||||
save_channels(self.channels)
|
||||
success, messages = client.upload_subscriptions(gl.channel_opml_file)
|
||||
self.show_message('\n'.join(messages), _('Results of upload'))
|
||||
if not success:
|
||||
gl.config.my_gpodder_password = ''
|
||||
self.on_upload_to_mygpo(widget)
|
||||
else:
|
||||
self.show_message(_('Please set up your username and password first.'), _('Username and password needed'))
|
||||
|
||||
def on_itemAddChannel_activate(self, widget, *args):
|
||||
gPodderAddPodcastDialog(url_callback=self.add_new_channel)
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# gPodder - A media aggregator and podcast client
|
||||
# Copyright (c) 2005-2008 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/>.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# my.py -- "my gPodder" service client
|
||||
# Thomas Perl <thp@gpodder.org> 2008-12-08
|
||||
#
|
||||
|
||||
|
||||
########################################################################
|
||||
# Based on upload_test.py
|
||||
# Copyright Michael Foord, 2004 & 2005.
|
||||
# Released subject to the BSD License
|
||||
# Please see http://www.voidspace.org.uk/documents/BSD-LICENSE.txt
|
||||
# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
|
||||
# E-mail fuzzyman@voidspace.org.uk
|
||||
########################################################################
|
||||
|
||||
import urllib2
|
||||
import mimetypes
|
||||
import mimetools
|
||||
import webbrowser
|
||||
|
||||
def encode_multipart_formdata(fields, files, BOUNDARY = '-----'+mimetools.choose_boundary()+'-----'):
|
||||
""" Encodes fields and files for uploading.
|
||||
fields is a sequence of (name, value) elements for regular form fields - or a dictionary.
|
||||
files is a sequence of (name, filename, value) elements for data to be uploaded as files.
|
||||
Return (content_type, body) ready for urllib2.Request instance
|
||||
You can optionally pass in a boundary string to use or we'll let mimetools provide one.
|
||||
"""
|
||||
CRLF = '\r\n'
|
||||
L = []
|
||||
if isinstance(fields, dict):
|
||||
fields = fields.items()
|
||||
for (key, value) in fields:
|
||||
L.append('--' + BOUNDARY)
|
||||
L.append('Content-Disposition: form-data; name="%s"' % key)
|
||||
L.append('')
|
||||
L.append(value)
|
||||
for (key, filename, value) in files:
|
||||
filetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
||||
L.append('--' + BOUNDARY)
|
||||
L.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
|
||||
L.append('Content-Type: %s' % filetype)
|
||||
L.append('')
|
||||
L.append(value)
|
||||
L.append('--' + BOUNDARY + '--')
|
||||
L.append('')
|
||||
body = CRLF.join(L)
|
||||
content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
|
||||
return content_type, body
|
||||
|
||||
def build_request(theurl, fields, files, txheaders=None):
|
||||
"""Given the fields to set and the files to encode it returns a fully formed urllib2.Request object.
|
||||
You can optionally pass in additional headers to encode into the opject. (Content-type and Content-length will be overridden if they are set).
|
||||
fields is a sequence of (name, value) elements for regular form fields - or a dictionary.
|
||||
files is a sequence of (name, filename, value) elements for data to be uploaded as files.
|
||||
"""
|
||||
content_type, body = encode_multipart_formdata(fields, files)
|
||||
if not txheaders: txheaders = {}
|
||||
txheaders['Content-type'] = content_type
|
||||
txheaders['Content-length'] = str(len(body))
|
||||
return urllib2.Request(theurl, body, txheaders)
|
||||
|
||||
|
||||
class MygPodderClient(object):
|
||||
WEBSERVICE = 'http://my.gpodder.org'
|
||||
|
||||
def __init__(self, username, password):
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
||||
def upload_subscriptions(self, filename):
|
||||
theurl = self.WEBSERVICE+'/upload'
|
||||
action = 'update-subscriptions'
|
||||
fields = {'username': self.username, 'password': self.password, 'action': 'update-subscriptions', 'protocol': '0'}
|
||||
opml_file = ('opml', 'subscriptions.opml', open(filename).read())
|
||||
|
||||
result = urllib2.urlopen(build_request(theurl, fields, [opml_file])).read()
|
||||
messages = []
|
||||
|
||||
success = False
|
||||
|
||||
if '@NEWUSER' in result:
|
||||
messages.append(_('A new user account has been created.'))
|
||||
|
||||
if '@GOTOMYGPODDER' in result:
|
||||
webbrowser.open(self.WEBSERVICE, new=1)
|
||||
messages.append(_('Please have a look at the website for more information.'))
|
||||
|
||||
if '@SUCCESS' in result:
|
||||
messages.append(_('Subscriptions uploaded.'))
|
||||
success = True
|
||||
elif '@AUTHFAIL' in result:
|
||||
messages.append(_('Authentication failed.'))
|
||||
elif '@PROTOERROR' in result:
|
||||
messages.append(_('Protocol error.'))
|
||||
else:
|
||||
messages.append(_('Unknown response.'))
|
||||
|
||||
return success, messages
|
||||
|
Loading…
Reference in New Issue