#!/usr/bin/env python import argparse,json,sys,os from shutil import copyfile from tabulate import tabulate import hashlib def get_folder_size(path): total_size = 0 for dirpath, dirnames, filenames in os.walk(path): for f in filenames: fp = os.path.join(dirpath, f) total_size += os.path.getsize(fp) return total_size def get_or_no(key,d,no): if key in d: return d[key] return no def file_size_human(num): for x in ['B','KB','MB','GB','TB']: if num < 1024.0: if x=='B': return "%d %s" % (num, x) return "%3.1f %s" % (num, x) num /= 1024.0 def list_shares(shares,opts): table = [] table.append(('Name', 'Path','Public','Password','Upload','Overwrite','Direct','Expire')) for share in shares: public = get_or_no('public',share, False) password = 'pass_hash' in share or 'pass_plain' in share if opts.show_password: if 'pass_plain' in share: password = hashlib.sha1(share['pass_plain'].encode('utf-8')).hexdigest() if 'pass_hash' in share: password = share['pass_hash'] upload = get_or_no('upload',share, False) overwrite = get_or_no('overwrite',share, True) direct = get_or_no('direct_links',share, False) if password else False expire = get_or_no('expire',share, "-") table.append(( share['name'], share['path']+"/", public, password, upload, overwrite, direct, expire )) print(tabulate(table, headers = "firstrow")) def list_folders(shares,config): if 'data_folder' not in config: print("data_folder not defined in config") sys.exit(1) folders = sorted(os.listdir(config['data_folder'])) table = [] table.append( ('Path','Share','Size','Unit') ) for folder in folders: full_path = os.path.join(config['data_folder'], folder) if not os.path.isdir(full_path): continue share_name = "[unused by any share]" for share in shares: share_path = os.path.join(config['data_folder'], share['path']) if os.path.samefile(full_path, share_path): share_name = share['name'] break (size_num, size_unit) = file_size_human(get_folder_size( full_path )).split(" ") table.append(( folder, share_name, size_num, size_unit )) print(tabulate(table, headers = "firstrow")) def remove_share(shares,config,opts): name = opts.name share = [share for share in shares if share['name'] == name] for share_ in share: print("Removing share: %s"%( name, )) print(json.dumps(share_, indent = 2, sort_keys = True)) shares = [share for share in shares if share['name'] != name] share_file = config['shares_file'] print("creating backup %s"%(share_file+".bkp",)) copyfile(share_file, share_file+".bkp") with open(share_file,'wt') as fp: json.dump(shares, fp, indent = 2, sort_keys = True) print("Removed %s from %s"%(name, share_file)) parser = argparse.ArgumentParser(description='Flees share manager') parser.add_argument('-c','--config', action="store", dest="config", default = "data/config.json", help = "Your current config.json file") parser.add_argument('-s','--shares', action="store", dest="shares_file", default = None, help = "shares.json you want to use. Defaults to what config.json defines") subparsers = parser.add_subparsers(help='sub-command help', dest='subparser_name') parser_list = subparsers.add_parser('list', help = "List shares") parser_list.add_argument('-P', action="store_true", dest="show_password", default = False, help = "Display hashed passwords") parser_folders = subparsers.add_parser('folders', help = "List folders and share names") parser_remove = subparsers.add_parser('remove', help = "Remove a share") parser_remove.add_argument(dest="name") opts = parser.parse_args() config = {} if os.path.exists(opts.config): config = json.load(open(opts.config,'rt')) else: if opts.shares == None: print("config file %s does not exist!"%(opts.config,)) sys.exit(1) if opts.shares_file: config['shares_file'] = opts.shares_file if os.path.exists(config['shares_file']): shares = json.load(open(config['shares_file'],'rt')) else: print("shares_file %s does not exist!"%(config['shares_file'])) sys.exit(1) if opts.subparser_name == 'list': list_shares(shares,opts) elif opts.subparser_name == 'folders': list_folders(shares,config) elif opts.subparser_name == 'remove': remove_share(shares,config,opts)