#!/usr/bin/env python ''' NukeFS Ultimate (NFSU): twin-algorithm shortener-based file cloud storage for Python 2.6+ Full library and command-line implementation by Multiversum Usage as stand-alone application: see nukefs.py -h Usage as library: import nukefs //for master-chunk algorithm: key_of_file = nukefs.upload("file.zip") download(key_of_file, "downoaded.zip") //for streaming algorithm: key_of_file = nukefs.upload("file.zip", True) download(key_of_file, "downoaded.zip", True) Note: it gets damn slow and somewhat unstable on large files so plz don't upload >1M files ''' from requests import get from json import dumps, loads from urllib import quote_plus, unquote_plus CHUNKLEN=22000 #current TinyURL effective chunk length limitation def chunk_upload(localpath): filekeys = [] baseurl = 'http://tinyurl.com/api-create.php?url=' with open(localpath, 'rb') as fileobj: while 1: data = fileobj.read(CHUNKLEN) if not data: break encoded = quote_plus(''.join(data.encode('base64').splitlines())) key = get(baseurl+encoded).text[19:] filekeys.append(key) fileobj.close() return get(baseurl+quote_plus(dumps(filekeys))).text[19:] def chunk_download(filekey, localpath): filekeys = loads(unquote_plus(get('http://tinyurl.com/'+filekey, allow_redirects=False).headers['location'])) with open(localpath, 'wb') as fileobj: for key in filekeys: data = get('http://tinyurl.com/'+key, allow_redirects=False).headers['location'] if not data: break fileobj.write(unquote_plus(data).decode('base64')) fileobj.close() def stream_upload(localpath): chunks = [] with open(localpath, 'rb') as fileobj: while 1: data = fileobj.read(CHUNKLEN) if not data: break chunks.append(''.join(data.encode('base64').splitlines())) fileobj.close() baseurl = 'http://tinyurl.com/api-create.php?url=' key = None for i in xrange(len(chunks),0,-1): chunkobj = {'data' : chunks[i-1], 'next' : key} encoded = quote_plus(dumps(chunkobj)) key = get(baseurl+encoded).text[19:] return key def stream_download(key, localpath): with open(localpath, 'wb') as fileobj: while 1: data = get('http://tinyurl.com/'+key, allow_redirects=False).headers['location'] if not data: break chunkobj = loads(unquote_plus(data)) if not chunkobj['data']: break fileobj.write(chunkobj['data'].decode('base64')) if not chunkobj['next']: break key = chunkobj['next'] fileobj.close() #universal functions to be called outside #algo: False - master-chunk algorithm (default), True - streaming algorithm def upload(localpath, algo=None): ''' Upload a file from localpath to cloud and get its access key algo: False or None - master-chunk algorithm (default), True - streaming algorithm ''' if algo: return stream_upload(localpath) else: return chunk_upload(localpath) def download(filekey, localpath, algo=None): ''' Download a file to localpath by its access key algo: False or None - master-chunk algorithm (default), True - streaming algorithm ''' if algo: stream_download(filekey, localpath) else: chunk_download(filekey, localpath) #stand-alone app code if __name__ == '__main__': from optparse import OptionParser parser = OptionParser() parser.add_option("-u", dest="upfilename", help="upload FILE to cloud", metavar="FILE") parser.add_option("-d", dest="downfilename", help="download FILE from cloud", metavar="FILE") parser.add_option("-k", dest="accesskey", help="Access key to download a file") parser.add_option("-s", "--stream", action="store_true", dest="algo", help="Use streaming algorithm instead of chunked") (options, args) = parser.parse_args() if options.upfilename and options.downfilename: parser.error("You can either download or upload at the same time") if options.downfilename and not options.accesskey: parser.error("You must specify the access key (with -k option) to download a file") if options.upfilename: print 'Uploading...' accesskey = upload(options.upfilename, options.algo) print 'Done. File access key is', accesskey elif options.downfilename: print 'Downloading...' download(options.accesskey, options.downfilename, options.algo) print 'Done.' else: print "Please specify either the file to upload or the file to download. See nukefs.py -h for help."