Wikipaste
What it does
It sends your graphical clipboard data to your wiki and copies a now valid {{attachment:...}} line to your clipboard so you can paste it in your wiki.
So now you can:
- take a screenshot and store it on your clipboard
- run wikipaste
- paste from the clipboard the wiki embed code in your moin editing session!
This might also help when migrating documents which contain images like word documents:
- copy the image from the source document
- run wikipaste
- paste the embed code in the wiki page where you are migrating the document.
Or, you could use this to locally store images you find on the web and not be depending on the original website to host them for eternity.
How it works
First it will try to find graphical clipboard data and if found will store that in a temporary PNG file, upload that file to your wiki using remote procedure calling and it will print the resulting wiki embed attachment text as well as start clip on windows to copy this text to your clipboard.
Requirements
This software requires PIL installed or available as with portablepython (this code is written for python 2.x)
Requires a moin with WikiRpc, i think it's 1.6 and up but i'm not sure. It sure works with 1.9.4
Requires the moin to accept xmlrpc! You need to configure this, otherwise it won't work. (see CHANGES document for 1.3)
- Requires some user to authenticate with, see hints
Requires a temp environment variable to point to a valid directory for writing temp files
Hints/configuration
use a special account for uploading that has only access to one attachment page, srvcMoinhulpproces in my code
- configure the app by changing the CONFIG class
- as stated above, configure you wiki to allow xmlrpc
find the line that uses os.system to use clip.exe to store the results on you clipboard and change it to something else if you are not on windows
- create a shortcut or sticky button for wikipaste for easy execution
Disclaimer and license
Though i have done my best to write clean code, it isn't. In fact, it's a bunch of code munched together in a few minutes to get it working and i didn't do any thing afterwards to improve it. You can use it as it is, it has the GPL2+ license applied (in accordance with Moin itself) and you are free to use it on your own risk. Don't shoot or sue me if it brakes anything, be aware. But it's GPL2+, so you can check to validate it, or improve when you have the time and patience. Feel free to reuse and republish but leave my name somewhere in your product and code. Also, in addition, i'd love to see a line here or in my mailbox when you do anything with it.
Leave me a note
use @SIG@ to include your signature
-- RemcoBoerma 2012-11-28 15:43:48
First public release, please share your thoughts and appreciation
The code
# VERSIE 1.0
# 2012-10-25
# Copyright Remco Boerma, Drenthecollege.nl
# GPL2+ license applies
#
from PIL import ImageGrab
import random, os.path, os, xmlrpclib
class CONFIG(object):
verbose = False
username = 'srvcMoinhulpproces'
password = 'somethingverydifficult'
url = "http://your-server-here/?action=xmlrpc2"
retrycount = 5
retrysleep = 1
class Server(object):
"A Server proxy for the xmlrpc with user validation and multicall."
def __init__(self, url, username, password):
self.url = url
self.username = username
self.password = password
self.auth_token = None
self.proxy = xmlrpclib.ServerProxy(self.url,
allow_none = True,
verbose = CONFIG.verbose)
self.auth_token = self.get_auth_token()
self.cached_calls = []
def get_auth_token(self):
if self.auth_token:
# we're done
return
retry = 0
while retry <CONFIG.retrycount:
try:
return self.proxy.getAuthToken(self.username,self.password)
except xmlrpclib.ProtocolError:
retry += 1
time.sleep(CONFIG.retrysleep)
raise Exception,'Problem connecting'
def get_multi_call(self):
mc = xmlrpclib.MultiCall(self.proxy)
mc.applyAuthToken(self.auth_token)
return mc
def call(self,method,params=()):
# get a new multicall
mc = self.get_multi_call()
# create a new call and evalute it to place the call in the
# multicall queue
#eval('mc.'+method+repr(params))
callable_method = getattr(mc,method)
callable_method(*params)
# apply the call
retry = 0
result = None
while retry <5:
try:
result = mc()
retry = 10
except xmlrpclib.ProtocolError:
print '#fail'
retry += 1
time.sleep(1)
if result:
# get the results, iterate over the results
result = [x for x in result]
# result 0 is success or not
# result 1 is the result of the cal
return result[1]
else:
return None
def flush_cached_calls(self):
# get a new multicall
mc = self.get_multi_call()
# create a new call and evaluate it to place the call in the
# multicall queue, do this for all cached calls
for method,params in self.cached_calls:
eval('mc.'+method+repr(params))
# apply the call
retry = 0
result = None
while retry <5:
try:
result = mc()
retry = 10
except xmlrpclib.ProtocolError:
print '#fail'
retry += 1
time.sleep(1)
self.cached_calls = []
if result:
# get the results, iterate over the results
result = [x for x in result]
# result 0 is success or not
# result 1 is the result of the cal
return result[1]
else:
return None
def searchPages(self, query):
return self.call('searchPages',(query, ))
def getPage(self, pagename):
return self.call('getPage', (pagename, ))
def putAttachment(self,pagename, attachname, payload):
return self.call('putAttachment',
(pagename,
attachname,
xmlrpclib.Binary(payload) ))
def putPage(self,pagename, patched):
return self.cached_call('putPage',(pagename, patched))
def cached_call(self, name, params):
self.cached_calls.append((name, params))
## this is where the fun starts
def main():
filename = grab_clipboard()
if not filename:
print 'No image data found on the clipboard'
return
wikiembedcode = send_image(filename)
print wikiembedcode
os.system('echo %s | clip.exe' % wikiembedcode)
def send_image(filename):
if CONFIG.verbose:
print 'Using username:',CONFIG.username
server = Server(CONFIG.url, CONFIG.username, CONFIG.password)
print filename
attachname = os.path.split(filename)[-1]
f = open(filename,'rb')
payload = f.read()
f.close()
server.putAttachment('Attachments',attachname,payload)
os.unlink(filename)
return '{{attachment:Attachments/%s}}' % attachname
def grab_clipboard():
image = ImageGrab.grabclipboard()
if image is None:
return
rnd = 100000000000000000000
fname = os.path.join(os.environ['temp'],str(random.randint(rnd,rnd*10-1))+'.png')
print fname
image.save(fname,'PNG')
return fname
if __name__== '__main__':
main()