aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan McCrohan <jmccrohan@gmail.com>2013-11-07 22:59:33 +0000
committerJonathan McCrohan <jmccrohan@gmail.com>2013-11-07 22:59:33 +0000
commitb69595ebe001b53486ebbd9fa4511b02fbbed158 (patch)
treeadb82150f45b70678a3c98a22a5cf7241e3c64b6
parent6e65ceca570ecef88682498d7e67a729421d45a0 (diff)
parent61d5dfe4359a77db8837cf7ea643b44cc22d36ab (diff)
downloadtransmission-remote-cli-b69595ebe001b53486ebbd9fa4511b02fbbed158.tar.gz
Merge tag 'upstream/1.6.3'
Upstream version 1.6.3
-rw-r--r--NEWS9
-rwxr-xr-xtransmission-remote-cli154
2 files changed, 103 insertions, 60 deletions
diff --git a/NEWS b/NEWS
index 9f5f440..5f62c47 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,12 @@
+1.6.3 2013-11-07
+ BUGFIXES:
+ - Properly handle East-Asian wide characters in progress bar/torrent title
+ - New keybinding 'N': Start queued torrent
+ - Tab completion in torrent search dialog
+ - Faster (un)pausing of all torrents
+ - Display Transmission version in top bar
+
+
1.6.2 2013-08-09
- Support for Transmission version 2.82
diff --git a/transmission-remote-cli b/transmission-remote-cli
index cba4d22..540a058 100755
--- a/transmission-remote-cli
+++ b/transmission-remote-cli
@@ -16,7 +16,7 @@
# http://www.gnu.org/licenses/gpl-3.0.txt #
########################################################################
-VERSION = '1.6.2'
+VERSION = '1.6.3'
TRNSM_VERSION_MIN = '1.90'
TRNSM_VERSION_MAX = '2.82'
@@ -294,7 +294,7 @@ class Transmission:
DETAIL_FIELDS = [ 'files', 'priorities', 'wanted', 'peers', 'trackers',
'activityDate', 'dateCreated', 'startDate', 'doneDate',
- 'totalSize', 'leftUntilDone', 'comment',
+ 'totalSize', 'leftUntilDone', 'comment', 'creator',
'hashString', 'pieceCount', 'pieceSize', 'pieces',
'downloadedEver', 'corruptEver', 'peersFrom' ] + LIST_FIELDS
@@ -317,6 +317,7 @@ class Transmission:
response = request.get_response()
self.rpc_version = response['arguments']['rpc-version']
+ self.version = response['arguments']['version'].split()[0]
# rpc version too old?
version_error = "Unsupported Transmission version: " + str(response['arguments']['version']) + \
@@ -347,7 +348,7 @@ class Transmission:
if self.rpc_version >= 14:
self.LIST_FIELDS.append('queuePosition');
self.DETAIL_FIELDS.append('queuePosition');
-
+
# set up request list
self.requests = {'torrent-list':
TransmissionRequest(host, port, path, 'torrent-get', self.TAG_TORRENT_LIST, {'fields': self.LIST_FIELDS}),
@@ -653,13 +654,18 @@ class Transmission:
else:
return ''
- def stop_torrent(self, id):
- request = TransmissionRequest(self.host, self.port, self.path, 'torrent-stop', 1, {'ids': [id]})
+ def stop_torrents(self, ids):
+ request = TransmissionRequest(self.host, self.port, self.path, 'torrent-stop', 1, {'ids': ids})
request.send_request()
self.wait_for_torrentlist_update()
- def start_torrent(self, id):
- request = TransmissionRequest(self.host, self.port, self.path, 'torrent-start', 1, {'ids': [id]})
+ def start_torrents(self, ids):
+ request = TransmissionRequest(self.host, self.port, self.path, 'torrent-start', 1, {'ids': ids})
+ request.send_request()
+ self.wait_for_torrentlist_update()
+
+ def start_now_torrent(self, id):
+ request = TransmissionRequest(self.host, self.port, self.path, 'torrent-start-now', 1, {'ids': [id]})
request.send_request()
self.wait_for_torrentlist_update()
@@ -849,7 +855,6 @@ class Interface:
self.stats = server.get_global_stats()
self.torrent_details = []
self.selected_torrent = -1 # changes to >-1 when focus >-1 & user hits return
- self.all_paused = False
self.highlight_dialog = False
self.search_focus = 0 # like self.focus but for searches in torrent list
self.focused_id = -1 # the id (provided by Transmission) of self.torrents[self.focus]
@@ -892,6 +897,7 @@ class Interface:
ord('K'): self.K_key,
ord('p'): self.pause_unpause_torrent,
ord('P'): self.pause_unpause_all_torrent,
+ ord('N'): self.start_now_torrent,
ord('v'): self.verify_torrent,
ord('y'): self.verify_torrent,
ord('r'): self.r_key,
@@ -1060,13 +1066,18 @@ class Interface:
while True:
server.update(1)
- # display torrentlist
- if self.selected_torrent == -1:
- self.draw_torrent_list()
-
- # display some torrent's details
- else:
- self.draw_details()
+ # I'm catching all exceptions here because resizing the terminal
+ # can make a huge mess, e.g. we might be drawing to areas that
+ # don't exist anymore. The proper way would probably be to write a
+ # wrapper around self.pad.addstr() and anything else that uses
+ # coordinates, but it's not worth the effort as this part is
+ # called continuously.
+ try:
+ if self.selected_torrent == -1:
+ self.draw_torrent_list()
+ else:
+ self.draw_details()
+ except: pass
self.stats = server.get_global_stats()
self.draw_title_bar() # show shortcuts and stuff
@@ -1197,7 +1208,7 @@ class Interface:
self.file_pritority_or_switch_details(c)
def add_torrent(self):
- location = self.dialog_input_text("Add torrent from file or URL", homedir2tilde(os.getcwd()+os.sep), tab_complete='all')
+ location = self.dialog_input_text("Add torrent from file or URL", homedir2tilde(os.getcwd()+os.sep), tab_complete='files')
if location:
error = server.add_torrent(tilde2homedir(location))
if error:
@@ -1320,19 +1331,24 @@ class Interface:
else:
t = self.torrents[self.focus]
if t['status'] == Transmission.STATUS_STOPPED:
- server.start_torrent(t['id'])
+ server.start_torrents([t['id']])
+ else:
+ server.stop_torrents([t['id']])
+
+ def start_now_torrent(self, c):
+ if self.focus > -1:
+ if self.selected_torrent > -1:
+ t = self.torrent_details
else:
- server.stop_torrent(t['id'])
+ t = self.torrents[self.focus]
+ server.start_now_torrent(t['id'])
def pause_unpause_all_torrent(self, c):
- if self.all_paused:
- for t in self.torrents:
- server.start_torrent(t['id'])
- self.all_paused = False
+ focused_torrent = self.torrents[ max(0,self.focus) ]
+ if focused_torrent['status'] == Transmission.STATUS_STOPPED:
+ server.start_torrents([t['id'] for t in self.torrents])
else:
- for t in self.torrents:
- server.stop_torrent(t['id'])
- self.all_paused = True
+ server.stop_torrents([t['id'] for t in self.torrents])
def verify_torrent(self, c):
if self.focus > -1:
@@ -1644,16 +1660,15 @@ class Interface:
c = self.screen.getch()
if c == -1:
return 0
-
f = self.keybindings.get(c, None)
if f:
f(c)
-
- # update view
- if self.selected_torrent == -1:
- self.draw_torrent_list()
- else:
- self.draw_details()
+ try:
+ if self.selected_torrent == -1:
+ self.draw_torrent_list()
+ else:
+ self.draw_details()
+ except: pass
def filter_torrent_list(self):
unfiltered = self.torrents
@@ -1834,13 +1849,19 @@ class Interface:
tag_done += curses.A_BOLD
if self.torrentname_is_progressbar:
- # addstr() dies when you tell it to draw on the last column of the
- # terminal, so we have to catch this exception.
- try:
- self.pad.addstr(ypos, 0, self.enc(title[0:bar_width]), tag_done)
- self.pad.addstr(ypos, len_columns(title[0:bar_width]), self.enc(title[bar_width:]), tag)
- except:
- pass
+ # Estimate widths, which works for anything ASCII
+ bar_complete = title[:bar_width]
+ bar_incomplete = title[bar_width:]
+ # Adjust for East-Asian (wide) characters
+ while len_columns(bar_complete) != bar_width:
+ if len_columns(bar_complete) > bar_width:
+ bar_incomplete = bar_complete[-1] + bar_incomplete
+ bar_complete = bar_complete[:-1]
+ else:
+ bar_complete += bar_incomplete[0]
+ bar_incomplete = bar_incomplete[1:]
+ self.pad.addstr(ypos, 0, self.enc(bar_complete), tag_done)
+ self.pad.addstr(ypos, len_columns(bar_complete), self.enc(bar_incomplete), tag)
else:
self.pad.addstr(ypos, 0, self.enc(title), tag_done)
@@ -2044,6 +2065,9 @@ class Interface:
info.append(['Location: ',"%s" % homedir2tilde(t['downloadDir'])])
+ if t['creator']:
+ info.append(['Creator: ',"%s" % t['creator']])
+
ypos = self.draw_details_list(ypos, info)
self.draw_details_eventdates(ypos+1)
@@ -2579,7 +2603,7 @@ class Interface:
self.draw_connection_status()
self.draw_quick_help()
def draw_connection_status(self):
- status = "Transmission @ %s:%s" % (server.host, server.port)
+ status = "Transmission %s @ %s:%s" % (server.version, server.host, server.port)
if cmd_args.DEBUG:
status = "%d x %d " % (self.width, self.height) + status
self.screen.addstr(0, 0, self.enc(status), curses.A_REVERSE)
@@ -2618,6 +2642,7 @@ class Interface:
" +/- Adjust bandwidth priority for focused torrent\n" + \
" p Pause/Unpause torrent\n" + \
" P Pause/Unpause all torrents\n" + \
+ " N Start torrent now\n" + \
" v/y Verify torrent\n" + \
" m Move torrent\n" + \
" n Reannounce torrent\n" + \
@@ -2775,8 +2800,9 @@ class Interface:
# tab_complete values:
- # 'all': complete with any files/directories
+ # 'files': complete with any files/directories
# 'dirs': complete only with directories
+ # 'torrent_list': complete with names from the torrent list
# any false value: do not complete
def dialog_input_text(self, message, input='', on_change=None, on_enter=None, tab_complete=None):
width = self.width - 4
@@ -2838,29 +2864,37 @@ class Interface:
index += 1
if on_change: on_change(input)
elif c == ord('\t') and tab_complete:
- (dirname, filename) = os.path.split(tilde2homedir(input))
- if not dirname:
- dirname = unicode(os.getcwd())
- try:
- possible_choices = [ choice for choice in os.listdir(dirname)
- if choice.startswith(filename) ]
- except OSError:
- continue;
- if tab_complete == 'dirs':
- possible_choices = [ d for d in possible_choices
- if os.path.isdir(os.path.join(dirname, d)) ]
+ possible_choices = [];
+ if tab_complete in ('files', 'dirs'):
+ (dirname, filename) = os.path.split(tilde2homedir(input))
+ if not dirname:
+ dirname = unicode(os.getcwd())
+ try:
+ possible_choices = [ os.path.join(dirname, choice) for choice in os.listdir(dirname)
+ if choice.startswith(filename) ]
+ except OSError:
+ continue;
+ if tab_complete == 'dirs':
+ possible_choices = [ d for d in possible_choices
+ if os.path.isdir(d) ]
+ elif tab_complete == 'torrent_list':
+ possible_choices = [ t['name'] for t in self.torrents
+ if t['name'].startswith(input) ]
if(possible_choices):
- input = os.path.join(dirname, os.path.commonprefix(possible_choices))
- if len(possible_choices) == 1 and os.path.isdir(input) and input.endswith(os.sep) == False:
- input += os.sep
- input = homedir2tilde(input)
+ input = os.path.commonprefix(possible_choices)
+ if tab_complete in ('files', 'dirs'):
+ if len(possible_choices) == 1 and os.path.isdir(input) and input.endswith(os.sep) == False:
+ input += os.sep
+ input = homedir2tilde(input)
index = len(input)
+ if on_change: on_change(input);
if on_change: win.redrawwin()
def dialog_search_torrentlist(self, c):
self.dialog_input_text('Search torrent by title:',
on_change=self.draw_torrent_list,
- on_enter=self.increment_search)
+ on_enter=self.increment_search,
+ tab_complete = 'torrent_list')
def increment_search(self, input):
self.search_focus += 1
@@ -3315,7 +3349,7 @@ def ljust_columns(text, max_width, padchar=' '):
def len_columns(text):
""" Returns the amount of columns that <text> would occupy. """
- if type(text) == type(str()):
+ if isinstance(text, str):
text = unicode(text, ENCODING)
columns = 0
for character in text:
@@ -3338,8 +3372,8 @@ def num2str(num, format='%s'):
def debug(data):
if cmd_args.DEBUG:
file = open("debug.log", 'a')
- if type(data) == type(str()):
- file.write(data)
+ if isinstance(data, str) or isinstance(data, unicode):
+ file.write(data.encode('UTF-8', 'replace'))
else:
import pprint
pp = pprint.PrettyPrinter(indent=4)