diff options
Diffstat (limited to '')
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | transmission-remote-cli-bash-completion.sh | 17 | ||||
-rwxr-xr-x | transmission-remote-cli.py | 213 |
4 files changed, 160 insertions, 80 deletions
@@ -1,3 +1,10 @@ +1.3 2012-05-23 + - Added Bash completion + - Estimate time until next ratio milestone is reached + - Don't connect to Transmission daemon when imported + - Show which versions of Transmission are supported in --version output + + 1.2.2 2012-05-02 BUGFIXES: - Handle escape key correctly in Turtle Mode speed limit dialogs @@ -1,7 +1,8 @@ # A console client for the BitTorrent client [Transmission](http://www.transmissionbt.com/ "Transmission Homepage"). -**Download the latest version for [Transmission 1.90-2.50](http://github.com/fagga/transmission-remote-cli/raw/master/transmission-remote-cli.py).** +**Download the latest version for [Transmission 1.90-2.52](http://github.com/fagga/transmission-remote-cli/raw/master/transmission-remote-cli.py).** +**Also available in Debian Wheezy / Ubuntu Quantal: `apt-get install transmission-remote-cli`** ## Modules diff --git a/transmission-remote-cli-bash-completion.sh b/transmission-remote-cli-bash-completion.sh new file mode 100644 index 0000000..2a0cec6 --- /dev/null +++ b/transmission-remote-cli-bash-completion.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +_transmission-remote-cli.py () { + local cur prev opts + + _get_comp_words_by_ref cur prev + + opts="--version -h --help -c --connect= -s --ssl -f --config= --create-config -n --netrc --debug" + + if [[ ${cur} == -* ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + else + _filedir torrent + fi +} + +complete -F _transmission-remote-cli.py transmission-remote-cli.py diff --git a/transmission-remote-cli.py b/transmission-remote-cli.py index ff7a487..abcca78 100755 --- a/transmission-remote-cli.py +++ b/transmission-remote-cli.py @@ -16,10 +16,10 @@ # http://www.gnu.org/licenses/gpl-3.0.txt # ######################################################################## -VERSION = '1.2.2' +VERSION = '1.3' TRNSM_VERSION_MIN = '1.90' -TRNSM_VERSION_MAX = '2.51' +TRNSM_VERSION_MAX = '2.52' RPC_VERSION_MIN = 8 RPC_VERSION_MAX = 14 @@ -148,8 +148,8 @@ class ColorManager: bg_name = pair.split(',')[1].split(':')[1].upper() fg_name = pair.split(',')[0].split(':')[1].upper() return { 'id': len(self.config.keys()) + 1, - 'bg':eval('curses.COLOR_' + bg_name), - 'fg':eval('curses.COLOR_' + fg_name) } + 'bg': eval('curses.COLOR_' + bg_name), + 'fg': eval('curses.COLOR_' + fg_name) } def get_id(self, name): return self.config[name]['id'] def get_bg(self, name): return self.config[name]['bg'] @@ -157,6 +157,25 @@ class ColorManager: def get_names(self): return self.config.keys() +class Normalizer: + def __init__(self): + self.values = {} + + def add(self, id, value, max): + if not id in self.values.keys(): + self.values[id] = [ float(value) ] + else: + if len(self.values[id]) >= max: + self.values[id].pop(0) + self.values[id].append(float(value)) + return self.get(id) + + def get(self, id): + if not id in self.values.keys(): + return 0.0 + return sum(self.values[id]) / len(self.values[id]) + + authhandler = None session_id = 0 @@ -1734,8 +1753,8 @@ class Interface: copies_distributed = (float(t['uploadedEver']) / float(t['sizeWhenDone'])) except ZeroDivisionError: copies_distributed = 0 - info.append(['Upload: ', "%s " % scale_bytes(t['uploadedEver'], 'long') + \ - "(%.2f copies) distributed; " % copies_distributed]) + info.append(['Upload: ', "%s (%d%%) transmitted; " % + (scale_bytes(t['uploadedEver'], 'long'), t['uploadRatio']*100)]) if t['rateUpload']: info[-1].append("sending %s per second" % scale_bytes(t['rateUpload'], 'long')) if t['uploadLimited']: @@ -1743,6 +1762,20 @@ class Interface: else: info[-1].append("no transmission in progress") + info.append(['Ratio: ', '%.2f copies distributed' % copies_distributed]) + norm_upload_rate = norm.add('%s:rateUpload' % t['id'], t['rateUpload'], 15) + if norm_upload_rate > 0: + target_ratio = self.get_target_ratio() + bytes_left = (max(t['downloadedEver'],t['sizeWhenDone']) * target_ratio) - t['uploadedEver'] + time_left = bytes_left / norm_upload_rate + info[-1][-1] += '; ' + if time_left < 86400: # 1 day + info[-1].append('approaching %.2f at %s' % \ + (target_ratio, timestamp(time.time() + time_left, "%R"))) + else: + info[-1].append('approaching %.2f on %s' % \ + (target_ratio, timestamp(time.time() + time_left, "%x"))) + info.append(['Seed limit: ']) if t['seedRatioMode'] == 0: if self.stats['seedRatioLimited']: @@ -1790,6 +1823,22 @@ class Interface: self.draw_details_eventdates(ypos+1) return ypos+1 + def get_target_ratio(self): + t = self.torrent_details + if t['seedRatioMode'] == 1: + return t['seedRatioLimit'] # individual limit + elif t['seedRatioMode'] == 0 and self.stats['seedRatioLimited']: + return self.stats['seedRatioLimit'] # global limit + else: + # round up to next 10/5/1 + if t['uploadRatio'] >= 100: + step_size = 10.0 + elif t['uploadRatio'] >= 10: + step_size = 5.0 + else: + step_size = 1.0 + return int(round((t['uploadRatio'] + step_size/2) / step_size) * step_size) + def draw_details_eventdates(self, ypos): t = self.torrent_details @@ -2810,12 +2859,11 @@ def scale_time(seconds, type='short'): return "%dy" % years -def timestamp(timestamp): +def timestamp(timestamp, format="%x %X"): if timestamp < 1: return 'never' - date_format = "%x %X" - absolute = time.strftime(date_format, time.localtime(timestamp)) + absolute = time.strftime(format, time.localtime(timestamp)) if timestamp > time.time(): relative = 'in ' + scale_time(int(timestamp - time.time()), 'long') else: @@ -3061,76 +3109,83 @@ def parse_sort_str(sort_str): sort_orders.append( { 'name':x[0], 'reverse':False } ) return sort_orders +def show_version(option, opt_str, value, parser): + quit("transmission-remote-cli %s (supports Transmission %s-%s)\n" % \ + (VERSION, TRNSM_VERSION_MIN, TRNSM_VERSION_MAX)) + + +if __name__ == '__main__': + # command line parameters + default_config_path = os.environ['HOME'] + '/.config/transmission-remote-cli/settings.cfg' + parser = OptionParser(usage="%prog [options] [-- transmission-remote options]", + description="%%prog %s" % VERSION) + parser.add_option("-v", "--version", action="callback", callback=show_version, + help="Show version number and supported Transmission versions.") + parser.add_option("-c", "--connect", action="store", dest="connection", default="", + help="Point to the server using pattern [username:password@]host[:port]/[path]") + parser.add_option("-s", "--ssl", action="store_true", dest="ssl", default=False, + help="Connect to Transmission using SSL.") + parser.add_option("-f", "--config", action="store", dest="configfile", default=default_config_path, + help="Path to configuration file.") + parser.add_option("--create-config", action="callback", callback=create_config, + help="Create configuration file CONFIGFILE with default values.") + parser.add_option("-n", "--netrc", action="store_true", dest="use_netrc", default=False, + help="Get authentication info from your ~/.netrc file.") + parser.add_option("--debug", action="store_true", dest="DEBUG", default=False, + help="Everything passed to the debug() function will be added to the file debug.log.") + (cmd_args, transmissionremote_args) = parser.parse_args() + + + # read config from config file + config.read(cmd_args.configfile) + + # command line connection data can override config file + if cmd_args.connection: + host, port, path, username, password = explode_connection_string(cmd_args.connection) + config.set('Connection', 'host', host) + config.set('Connection', 'port', str(port)) + config.set('Connection', 'path', path) + config.set('Connection', 'username', username) + config.set('Connection', 'password', password) + if cmd_args.use_netrc: + username, password = read_netrc(hostname=config.get('Connection','host')) + config.set('Connection', 'username', username) + config.set('Connection', 'password', password) + if cmd_args.ssl: + config.set('Connection', 'ssl', 'True') -# command line parameters -default_config_path = os.environ['HOME'] + '/.config/transmission-remote-cli/settings.cfg' -parser = OptionParser(usage="%prog [options] [-- transmission-remote options]", - version="%%prog %s" % VERSION, - description="%%prog %s" % VERSION) -parser.add_option("-c", "--connect", action="store", dest="connection", default="", - help="Point to the server using pattern [username:password@]host[:port]/[path]") -parser.add_option("-s", "--ssl", action="store_true", dest="ssl", default=False, - help="Connect to transmission using SSL.") -parser.add_option("-f", "--config", action="store", dest="configfile", default=default_config_path, - help="Path to configuration file.") -parser.add_option("--create-config", action="callback", callback=create_config, - help="Create configuration file CONFIGFILE with default values.") -parser.add_option("-n", "--netrc", action="store_true", dest="use_netrc", default=False, - help="Get authentication info from your ~/.netrc file.") -parser.add_option("--debug", action="store_true", dest="DEBUG", default=False, - help="Everything passed to the debug() function will be added to the file debug.log.") -(cmd_args, transmissionremote_args) = parser.parse_args() - - -# read config from config file -config.read(cmd_args.configfile) - -# command line connection data can override config file -if cmd_args.connection: - host, port, path, username, password = explode_connection_string(cmd_args.connection) - config.set('Connection', 'host', host) - config.set('Connection', 'port', str(port)) - config.set('Connection', 'path', path) - config.set('Connection', 'username', username) - config.set('Connection', 'password', password) -if cmd_args.use_netrc: - username, password = read_netrc(hostname=config.get('Connection','host')) - config.set('Connection', 'username', username) - config.set('Connection', 'password', password) -if cmd_args.ssl: - config.set('Connection', 'ssl', 'True') - - - -# forward arguments after '--' to transmission-remote -if transmissionremote_args: - cmd = ['transmission-remote', '%s:%s' % - (config.get('Connection', 'host'), config.get('Connection', 'port'))] - - # one argument and it doesn't start with '-' --> treat it like it's a torrent link/url - if len(transmissionremote_args) == 1 and not transmissionremote_args[0].startswith('-'): - cmd.extend(['-a', transmissionremote_args[0]]) - - if config.get('Connection', 'username') and config.get('Connection', 'password'): - cmd_print = cmd - cmd_print.extend(['--auth', '%s:PASSWORD' % config.get('Connection', 'username')]) - print "EXECUTING:\n%s\nRESPONSE:" % ' '.join(cmd_print) - cmd.extend(['--auth', '%s:%s' % (config.get('Connection', 'username'), config.get('Connection', 'password'))]) - cmd.extend(transmissionremote_args) - else: - print "EXECUTING:\n%s\nRESPONSE:" % ' '.join(cmd) - try: - retcode = call(cmd) - except OSError, msg: - quit("Could not execute the above command: %s\n" % msg, 128) - quit('', retcode) - - -server = Transmission(config.get('Connection', 'host'), - config.getint('Connection', 'port'), - config.get('Connection', 'path'), - config.get('Connection', 'username'), - config.get('Connection', 'password')) -Interface() + + # forward arguments after '--' to transmission-remote + if transmissionremote_args: + cmd = ['transmission-remote', '%s:%s' % + (config.get('Connection', 'host'), config.get('Connection', 'port'))] + + # one argument and it doesn't start with '-' --> treat it like it's a torrent link/url + if len(transmissionremote_args) == 1 and not transmissionremote_args[0].startswith('-'): + cmd.extend(['-a', transmissionremote_args[0]]) + + if config.get('Connection', 'username') and config.get('Connection', 'password'): + cmd_print = cmd + cmd_print.extend(['--auth', '%s:PASSWORD' % config.get('Connection', 'username')]) + print "EXECUTING:\n%s\nRESPONSE:" % ' '.join(cmd_print) + cmd.extend(['--auth', '%s:%s' % (config.get('Connection', 'username'), config.get('Connection', 'password'))]) + cmd.extend(transmissionremote_args) + else: + print "EXECUTING:\n%s\nRESPONSE:" % ' '.join(cmd) + + try: + retcode = call(cmd) + except OSError, msg: + quit("Could not execute the above command: %s\n" % msg, 128) + quit('', retcode) + + + norm = Normalizer() + server = Transmission(config.get('Connection', 'host'), + config.getint('Connection', 'port'), + config.get('Connection', 'path'), + config.get('Connection', 'username'), + config.get('Connection', 'password')) + Interface() |