#!/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."