aboutsummaryrefslogtreecommitdiffstats
path: root/transmission-remote-cli.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xtransmission-remote-cli.py213
1 files changed, 134 insertions, 79 deletions
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()