gett-cli / gett_uploader.py

#!/usr/bin/env python

import sys, os, os.path
import argparse
import signal
import re

from gett import *
from time import sleep

url_re = re.compile(r'^(?:http://ge\.tt/|/)?(\w+)(?:/(?:v/(\d+)/?)?)?$')

def humanize(nbytes):
    for (exp, unit) in ((9, 'GB'), (6, 'MB'), (3, 'KB')):
       if nbytes >= 10**exp:
           return '%.2f %s' % (nbytes / 10**exp, unit)

    return '%.2f B' % nbytes

def print_status(upload, index, count):
        name = upload.file.name

        if len(name) > 15:
            name = name[:12] + '...'

        name = name.ljust(15)

        bar_size = int(50 * upload.percent_done / 100)
        bar = '[' + (bar_size * '#') + ((50 - bar_size) * '-') + ']'

        sys.stderr.write('\r%s (%d/%d) %s %d %%' % (name, index, count, bar, upload.percent_done))

def show_share(share):
    print('Share %s : %s (%d file(s))' % (share.name, share.title or 'Untitled', len(share.files)))

    for file in share.files.values():
        size = ''
        if file.size is not None:
            size = '[%s]' % humanize(file.size)

        print('--- %-20s %s [%s]' % (file.name, size, file.url))
    print()

def entry_point():
    try:
        main()
    except APIError as ex:
        print('API error : %s' % ex)

def main():
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    home = os.getenv('USERPROFILE') or os.getenv('HOME')

    parser = argparse.ArgumentParser(description="A command-line Ge.tt uploader and manager")
    parser.add_argument('-D', dest='debug', action='store_true', help='Debug API calls')

    upload_group = parser.add_argument_group('Upload options')
    upload_group.add_argument('file', nargs='*', type=argparse.FileType('rb'), help="Name of a file to upload")
    upload_group.add_argument('-t', dest='title', help='Title of the share (defaults to first file name)')
    upload_group.add_argument('-s', dest='share', help='Name or URL of the share to upload to (defaults to a newly created one)')
    upload_group.add_argument('-P', dest='parallel_upload', action='store_true', help='Upload files in parallel rather than sequentially, the progress bars are displayed in ascending file size order')

    other_group = parser.add_argument_group('Other actions')
    other_group.add_argument('--delete', nargs='+', dest='delete', metavar='SHARE_OR_FILE', help='Delete a share or a file (url or path)')
    other_group.add_argument('--list', nargs='*', dest='list', metavar='SHARE_NAME', help='List the files in the specified share. If no share is specified, list all your shares.')

    auth_group = parser.add_argument_group('Authentification')
    auth_group.add_argument('-L', dest='ignore_token', action='store_true', help='Log-in with a different account than the stored one (if any)')
    auth_group.add_argument('-e', dest='email', help='Email to login with')
    auth_group.add_argument('-p', dest='password', help='Password to login with')
    auth_group.add_argument('-k', dest='tokenfile', help='Ge.tt token file path (~/.gett-token)', default=os.path.join(home, '.gett-token'))

    args = parser.parse_args()

    if args.debug:
        import gett
        gett.DEBUG = True

    user = User()
    logged = False

    # If not logging-in with a different account

    if not args.ignore_token and not args.email:
        try:
            # Try to log-in with the token

            token = open(args.tokenfile, 'r').read()
            user.login_token(token)

            logged = True
        except:
            pass

    if not logged:
        if not args.email:
            args.email = input('Please enter your Ge.tt email: ')

        if not args.password:
            import getpass
            args.password = getpass.getpass('Please enter your Ge.tt password: ')

        try:
            user.login_auth(args.email, args.password)
        except Exception as ex:
            print('Unable to login: %s' % ex.args[0])
            sys.exit(1)

        reply = input('Do you wish to store the session token? (y/n): ')

        if reply.lower() == 'y':
            # Save the refreshtoken to the user's home directory (by default)

            with open(args.tokenfile, 'w') as file:
                file.write(user.rtoken)


    # --list command

    if args.list is not None:
        for name in args.list:
            share = Share(name)
            show_share(share)

        if not args.list:
            for share in user.list_shares():
                show_share(share)

    # --delete command

    if args.delete:
        for item in args.delete:
            match = url_re.match(item)

            if not match:
                parser.error('argument --delete: invalid format, please supply either file/share url or path')

            share = user.get_share(match.group(1))

            if match.group(2):
                id = match.group(2)
                file = share.files[id]
                file.destroy()

                print('Deleted file %s [%s]' % (file.name, file.url))
            else:
                print('Deleted share %s' % share.name)
                share.destroy()

    # File uploads

    if args.file:
        if args.share:
            # Upload to existing share

            match = url_re.match(args.share)

            if match:
                share = user.get_share(match.group(1))
            else:
                parser.error('argument --list: invalid share name, please supply either URL or name')
        else:
            # Upload to a new share

            if args.title:
                share = user.create_share(args.title)
            else:
                share = user.create_share(os.path.basename(args.file[0].name))

        uploads = []

        # Create the file URLs

        for fp in args.file:
            name = os.path.basename(fp.name)
            file = share.create_file(name)

            print('%s: %s' % (name, file.url))

            upload = FileUpload(file, fp)

            if args.parallel_upload:
                upload.start()

            uploads.append(upload)

        print()

        if args.parallel_upload:
            uploads.sort(key=lambda item: item.file_size)

        for i, upload in enumerate(uploads):
            if not args.parallel_upload:
                upload.start()

            while True:
                print_status(upload, i + 1, len(uploads))
                upload.join(0.5)

                if not upload.is_alive():
                    print_status(upload, i + 1, len(uploads))

                    if upload.ex:
                        sys.stderr.write(('\rError uploading %s: %s' % (upload.file.name, upload.ex)).ljust(80))

                    sys.stderr.write('\n')
                    break

    user.refresh()

    print('Storage used : %s out of %s (%d %%)' % (
            humanize(user.storage_used),
            humanize(user.storage_limit),
            int(100 * user.storage_used / user.storage_limit)))


if __name__ == '__main__':
    entry_point()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.