Skip to content

Instantly share code, notes, and snippets.

@posativ
Created May 28, 2014 09:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save posativ/506bf4b66bf3779f5a28 to your computer and use it in GitHub Desktop.
Save posativ/506bf4b66bf3779f5a28 to your computer and use it in GitHub Desktop.
implement configurable CloudApp API url #51
commit 55e9f2635f8c5beb794f87592679e74daf1c4b6d
Author: posativ <info@posativ.org>
Date: Fri Aug 31 22:26:12 2012 +0200
remove orderedDict since poster can also use lists
diff --git a/src/cloud.py b/src/cloud.py
index 27ff0ea..b9d57bd 100644
--- a/src/cloud.py
+++ b/src/cloud.py
@@ -9,9 +9,6 @@ In order to have this fully functional you need:
- poster
This is needed as Python does not (yet) support
multipart/form-data-requests out of the box.
- - Python 2.7 or ordereddict
- Necessary because Amazon's S3 expects the file to be the last
- value in the upload request.
The following values are available:
- *cloud.__version_info__*
@@ -50,17 +47,6 @@ try:
except ImportError:
POSTER = False
-# We need ordereddicts as Amazon S3 expects 'file' to be the last param
-# in the request's body when uploading.
-ORDERED_DICT = True
-try:
- from collections import OrderedDict
-except ImportError:
- try:
- from ordereddict import OrderedDict
- except ImportError:
- ORDERED_DICT = False
-
USER_AGENT = 'Cloud API Python Wrapper/%s' % __version__
FILE_TYPES = ('image', 'bookmark', 'text', 'archive', 'audio', 'video', 'unknown')
@@ -221,9 +207,7 @@ class Cloud(object):
"""
if not POSTER:
raise CloudException('Poster is not installed')
- if not ORDERED_DICT:
- raise CloudException('Python 2.7 or ordereddict are not installed')
-
+
if self.auth_success == 0:
raise CloudException('Not authed')
@@ -236,8 +220,9 @@ class Cloud(object):
directives['params']['key'] = directives['params']['key'] \
.replace('${filename}',
os.path.split(path)[-1])
- upload_values = OrderedDict(sorted(directives['params'].items(), key=lambda t: t[0]))
- upload_values['file'] = open(path, 'rb')
+
+ upload_values = sorted(directives['params'].items())
+ upload_values.append(('file', open(path, 'rb')))
datagen, headers = poster.encode.multipart_encode(upload_values)
request = urllib2.Request(directives['url'], datagen, headers)
diff --git a/src/uploader.py b/src/uploader.py
index 12c0fd6..5dbd229 100644
--- a/src/uploader.py
+++ b/src/uploader.py
@@ -48,7 +48,7 @@ except ImportError:
try:
import cloud
- if cloud.POSTER and cloud.ORDERED_DICT:
+ if cloud.POSTER:
PROTO_LIST.append('CloudApp')
else:
print 'CloudApp support not available'
commit 8307e9d7d5f9607aefd511b957245796723b9482
Author: posativ <info@posativ.org>
Date: Fri Aug 31 22:16:34 2012 +0200
implement configurable CloudApp API url
With [regenwolken][1] – yes, a shameless self-promote – exists
an alternate implementation of the CloudApp API that is completely
open source and simple to install.
In addition the user can use HTTPS for secure transport. Actually
this is not a feature request of mine (I do not use a Linux Desktop),
but of a friend that needs a nice integrated tool like lookit is :)
I hope I made everything right with the GUI part. Unfortunately Unity
did not launch the GUI of lookit and I had to use `lookit --preferences`.
[1]: https://github.com/posativ/regenwolken/
diff --git a/src/cloud.py b/src/cloud.py
index 6cc92f4..27ff0ea 100644
--- a/src/cloud.py
+++ b/src/cloud.py
@@ -20,15 +20,6 @@ The following values are available:
- *cloud.__version__*
a string generated from __version_info__.
Format: 'major.minor.maintenance'
- - *cloud.PROTOCOL*
- a string specifying the protocol to be used.
- Default: '\'http://\''
- - *cloud.URI*
- a string containing the URL used by non-authed requests.
- Default: '\'cl.ly\''
- - *cloud.AUTH_URI*
- a string containg the URL used by authed requests.
- Default: '\'my.cl.ly\''
- *cloud.FILE_TYPES*
a tuple filled with available filetypes.
@@ -42,6 +33,7 @@ The following classes are available:
"""
+import urlparse
import urllib2
import urllib
import json
@@ -69,11 +61,7 @@ except ImportError:
except ImportError:
ORDERED_DICT = False
-PROTOCOL = 'http://'
-
-AUTH_URI = 'my.cl.ly'
USER_AGENT = 'Cloud API Python Wrapper/%s' % __version__
-
FILE_TYPES = ('image', 'bookmark', 'text', 'archive', 'audio', 'video', 'unknown')
@@ -98,6 +86,9 @@ class Cloud(object):
"""
The pythonic CloudApp API Wrapper.
+ - base_url is the current service API (defaults to my.cl.ly). The url
+ starts with either an http or an https prefix.
+
Public methods:
- auth(username, password)
Authenticates a user.
@@ -109,18 +100,24 @@ class Cloud(object):
Creates a bookmark with the given name and url.
- upload_file(path)
Upload a file.
-
"""
- def __init__(self):
+ def __init__(self, base_url):
"""
Init.
*opener* is for functions that do not need authentication.
-
+
"""
self.opener = urllib2.build_opener()
self.opener.addheaders = [('User-Agent', USER_AGENT),
('Accept', 'application/json'),]
+
+ if not urlparse.urlparse(base_url).netloc:
+ base_url = 'http://my.cl.ly/'
+ elif not base_url.startswith(('http://', 'https://')):
+ base_url = 'http://' + base_url
+
+ self.base_url = base_url.rstrip('/')
self.auth_success = 0
def auth(self, username, password):
@@ -132,9 +129,10 @@ class Cloud(object):
"""
if self.auth_success == 1:
return True
-
+
+ hostname = urlparse.urlparse(self.base_url).netloc
passwordmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
- passwordmgr.add_password(None, AUTH_URI, username, password)
+ passwordmgr.add_password(None, hostname, username, password)
auth = urllib2.HTTPDigestAuthHandler(passwordmgr)
self.auth_opener = urllib2.build_opener(auth)
@@ -153,7 +151,7 @@ class Cloud(object):
def _test_auth(self):
"""Test authentication."""
query = urllib.urlencode({'page': 1, 'per_page': 1})
- page = self.auth_opener.open('%s%s/items?%s' % (PROTOCOL, AUTH_URI, query))
+ page = self.auth_opener.open('%s/items?%s' % (self.base_url, query))
if page.code == 200:
self.auth_success = 1
return True
@@ -161,8 +159,7 @@ class Cloud(object):
def item_info(self, uri):
"""Get metadata about a cl.ly URL."""
- validator = '%s%s' % (PROTOCOL, AUTH_URI)
- if validator in uri:
+ if self.base_url in uri:
return json.load(self.opener.open(uri))
raise CloudException('URI not valid')
@@ -197,7 +194,7 @@ class Cloud(object):
params['deleted'] = bool(deleted)
query = urllib.urlencode(params)
- return json.load(self.auth_opener.open('%s%s/items?%s' % (PROTOCOL, AUTH_URI, query)),
+ return json.load(self.auth_opener.open('%s/items?%s' % (self.base_url, query)),
encoding='utf-8')
def create_bookmark(self, name, bookmark_uri):
@@ -207,7 +204,7 @@ class Cloud(object):
values = {'item': {'name': name, 'redirect_url': bookmark_uri}}
data = json.dumps(values, encoding='utf-8')
- request = urllib2.Request('%s%s/items' % (PROTOCOL, AUTH_URI), data)
+ request = urllib2.Request('%s/items' % self.base_url, data)
request.add_header('Content-Type', 'application/json')
return json.load(self.auth_opener.open(request))
@@ -235,7 +232,7 @@ class Cloud(object):
if not os.path.isfile(path):
raise CloudException('The given path does not point to a file')
- directives = json.load(self.auth_opener.open('%s%s/items/new' % (PROTOCOL, AUTH_URI)))
+ directives = json.load(self.auth_opener.open('%s/items/new' % self.base_url))
directives['params']['key'] = directives['params']['key'] \
.replace('${filename}',
os.path.split(path)[-1])
diff --git a/src/preferences.py b/src/preferences.py
index cc1d770..7277b4d 100644
--- a/src/preferences.py
+++ b/src/preferences.py
@@ -85,9 +85,9 @@ class PreferencesDialog:
for field in all_fields:
self.builder.get_object(field).set_sensitive(True)
elif proto in ['CloudApp']:
- for field in user_pass:
+ for field in user_pass + ('url', ):
self.builder.get_object(field).set_sensitive(True)
- for field in server_port_dir_url:
+ for field in ('server', 'port', 'directory'):
self.builder.get_object(field).set_sensitive(False)
elif proto in ['HTTP']:
for field in all_fields:
diff --git a/src/uploader.py b/src/uploader.py
index 3d09ce7..12c0fd6 100644
--- a/src/uploader.py
+++ b/src/uploader.py
@@ -183,11 +183,11 @@ def upload_file_imgur(f):
else:
return False, i.mapping.get('error_msg')
-def upload_file_cloud(f, username, password):
+def upload_file_cloud(f, baseurl, username, password):
if not 'CloudApp' in PROTO_LIST:
print 'Error: CloudApp not supported'
try:
- mycloud = cloud.Cloud()
+ mycloud = cloud.Cloud(baseurl)
mycloud.auth(username, password)
result = mycloud.upload_file(f)
data = {'original_image': result['url']}
@@ -256,6 +256,7 @@ def upload_file(image, existing_file=False):
f.close()
elif proto == 'CloudApp':
success, data = upload_file_cloud(image,
+ config.get('Upload', 'url'),
config.get('Upload', 'username'),
config.get('Upload', 'password'))
else:
commit a5f99a6055cd6d3754b37c63c35a3177ba8dd7b0
Author: posativ <info@posativ.org>
Date: Fri Aug 31 22:14:36 2012 +0200
fix incorrect usage of poster
Although cl.ly (or better: S3) can handle files without filenames,
it is sometimes nice to have a name (altough poster has issues
with non-ascii characters, so Arbeitsfläche becomes Arbeitsfl\xc3\xa4che.
In addition, this does not work with regenwolken.
diff --git a/src/cloud.py b/src/cloud.py
index 5b0618b..6cc92f4 100644
--- a/src/cloud.py
+++ b/src/cloud.py
@@ -240,7 +240,7 @@ class Cloud(object):
.replace('${filename}',
os.path.split(path)[-1])
upload_values = OrderedDict(sorted(directives['params'].items(), key=lambda t: t[0]))
- upload_values['file'] = open(path, 'rb').read()
+ upload_values['file'] = open(path, 'rb')
datagen, headers = poster.encode.multipart_encode(upload_values)
request = urllib2.Request(directives['url'], datagen, headers)
commit 2ec00557d7617c5bbbe059bc5ceb5edf016bd87f
Author: posativ <info@posativ.org>
Date: Fri Aug 31 20:59:08 2012 +0200
typo
diff --git a/src/cloud.py b/src/cloud.py
index 495f530..5b0618b 100644
--- a/src/cloud.py
+++ b/src/cloud.py
@@ -74,7 +74,7 @@ PROTOCOL = 'http://'
AUTH_URI = 'my.cl.ly'
USER_AGENT = 'Cloud API Python Wrapper/%s' % __version__
-FILE_TYPES = ('image', 'bookmark', 'test', 'archive', 'audio', 'video', 'unknown')
+FILE_TYPES = ('image', 'bookmark', 'text', 'archive', 'audio', 'video', 'unknown')
class CloudException(Exception):
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment