#!/usr/bin/python
#
# Upload a file to S3 and return a web URI to clipboard, indicating progress via desktop notifications
#
# Usage: $0 [file-path]
# If no file-path argument is given, URI is read from clipboard
#
# TODO:
# - add use of option parser to optionally support s3 key prefix
#
import notify2
import pyperclip
import mimetypes
import os
import sys
import urllib
import boto3
from botocore.exceptions import ClientError
min_size = (100 * 1000 * 1000) # minimum filesize to notify upload milestones for
thresholds = [25, 50, 75] # percentages of upload to notify on
aws_profile = ''
s3_bucket = ''
detect_type = True # store at s3 key prefix depending on mimetype or file extension
domain = '' # http(s)://domain.tld
notify2.init('S3 Uploader')
def notification(title, body):
n = notify2.Notification(title, body)
n.show()
class S3Upload:
def __init__(self):
self.total = 0
self.uploaded = 0
self.progress = 0
self.thresholds = thresholds
def upload_callback(self, size):
if self.total == 0:
return
self.uploaded += size
self.progress = int(self.uploaded / self.total * 100)
# if over 100MB and progress advanced to past a threshold percentage
if self.total >= min_size and [self.progress for t in self.thresholds if self.progress >= t]:
notification('S3 Upload', str(self.progress) + '% transferred')
self.thresholds.pop(0)
elif self.progress >= 100:
notification('S3 Upload', 'Completed successfully!')
def upload(self, bucket, key, file):
self.total = os.stat(file).st_size
with open(file, 'rb') as data:
try:
notification('S3 Upload', 'Starting!')
try:
aws_profile != ''
session = boto3.Session(profile_name = aws_profile)
s3 = session.client('s3')
except:
s3 = boto3.client('s3')
s3.upload_fileobj(data, bucket, key,
ExtraArgs={'ContentType': mimetype},
Callback=self.upload_callback)
except ClientError as e:
notify2.Notification('S3 Upload', e)
print(e)
try:
# if an argument is passed, use that as file to upload
sys.argv[1] and isinstance(sys.argv[1], str)
filepath = sys.argv[1]
except:
# otherwise, grab path from clipboard
filepath = pyperclip.paste()
# if the file doesnt exist, error out
try:
os.lstat(filepath)
except OSError as e:
notification('S3 Upload', e)
print(e)
filename = os.path.basename(filepath)
s3_key = ''
if detect_type:
mimetype = mimetypes.guess_type(filepath)[0]
mimens = mimetype.split('/')[0]
fileext = filename.split('.')[1]
# map file classifications to s3 key paths
if mimens == 'image':
s3_key = 'img'
elif mimens == 'audio' or [e for e in ['mp3','flac'] if fileext == e]:
s3_key = 'aud'
elif mimens == 'text' or mimetype == 'application/pdf':
s3_key = 'txt'
else:
notification('S3 Upload', 'Unknown file type')
print('Unknown file type')
u = S3Upload()
u.upload(s3_bucket, s3_key + '/' + filename, filepath)
# copy resulting web accessible uri to clipboard
access_uri = domain + '/' + s3_key + '/' + urllib.parse.quote_plus(filename)
print(access_uri)
pyperclip.copy(access_uri)