📄 btdownloadcurses.py
字号:
#!/usr/bin/env python# The contents of this file are subject to the BitTorrent Open Source License# Version 1.0 (the License). You may not copy or use this file, in either# source code or executable form, except in compliance with the License. You# may obtain a copy of the License at http://www.bittorrent.com/license/.## Software distributed under the License is distributed on an AS IS basis,# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License# for the specific language governing rights and limitations under the# License.# Original version written by Henry 'Pi' James, modified by (at least)# John Hoffman and Uoti Urpalafrom __future__ import divisionSPEW_SCROLL_RATE = 1import sysimport osimport threadingfrom time import time, strftimefrom BitTorrent.download import Feedback, Multitorrentfrom BitTorrent.defaultargs import get_defaultsfrom BitTorrent.parseargs import parseargs, printHelpfrom BitTorrent.zurllib import urlopenfrom BitTorrent.bencode import bdecodefrom BitTorrent.ConvertedMetainfo import ConvertedMetainfofrom BitTorrent import configfilefrom BitTorrent import BTFailurefrom BitTorrent import versiontry: import curses import curses.panel from curses.wrapper import wrapper as curses_wrapper from signal import signal, SIGWINCHexcept: print 'Textmode GUI initialization failed, cannot proceed.' print print 'This download interface requires the standard Python module ' \ '"curses", which is unfortunately not available for the native ' \ 'Windows port of Python. It is however available for the Cygwin ' \ 'port of Python, running on all Win32 systems (www.cygwin.com).' print print 'You may still use "btdownloadheadless.py" to download.' sys.exit(1)def fmttime(n): if n == 0: return 'download complete!' try: n = int(n) assert n >= 0 and n < 5184000 # 60 days except: return '<unknown>' m, s = divmod(n, 60) h, m = divmod(m, 60) return 'finishing in %d:%02d:%02d' % (h, m, s)def fmtsize(n): s = str(n) size = s[-3:] while len(s) > 3: s = s[:-3] size = '%s,%s' % (s[-3:], size) if n > 999: unit = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] i = 1 while i + 1 < len(unit) and (n >> 10) >= 999: i += 1 n >>= 10 n /= (1 << 10) size = '%s (%.0f %s)' % (size, n, unit[i]) return sizeclass CursesDisplayer(object): def __init__(self, scrwin, errlist, doneflag, reread_config): self.scrwin = scrwin self.errlist = errlist self.doneflag = doneflag signal(SIGWINCH, self.winch_handler) self.changeflag = threading.Event() self.done = False self.reread_config = reread_config self.activity = '' self.status = '' self.progress = '' self.downRate = '---' self.upRate = '---' self.shareRating = '' self.seedStatus = '' self.peerStatus = '' self.errors = [] self.file = '' self.downloadTo = '' self.fileSize = '' self.numpieces = 0 self.spew_scroll_time = 0 self.spew_scroll_pos = 0 self._remake_window() def set_torrent_values(self, name, path, size, numpieces): self.file = name self.downloadTo = path self.fileSize = fmtsize(size) self.numpieces = numpieces self._remake_window() def winch_handler(self, signum, stackframe): self.changeflag.set() curses.endwin() self.scrwin.refresh() self.scrwin = curses.newwin(0, 0, 0, 0) self._remake_window() def _remake_window(self): self.scrh, self.scrw = self.scrwin.getmaxyx() self.scrpan = curses.panel.new_panel(self.scrwin) self.labelh, self.labelw, self.labely, self.labelx = 11, 9, 1, 2 self.labelwin = curses.newwin(self.labelh, self.labelw, self.labely, self.labelx) self.labelpan = curses.panel.new_panel(self.labelwin) self.fieldh, self.fieldw, self.fieldy, self.fieldx = ( self.labelh, self.scrw-2 - self.labelw-3, 1, self.labelw+3) self.fieldwin = curses.newwin(self.fieldh, self.fieldw, self.fieldy, self.fieldx) self.fieldwin.nodelay(1) self.fieldpan = curses.panel.new_panel(self.fieldwin) self.spewh, self.speww, self.spewy, self.spewx = ( self.scrh - self.labelh - 2, self.scrw - 3, 1 + self.labelh, 2) self.spewwin = curses.newwin(self.spewh, self.speww, self.spewy, self.spewx) self.spewpan = curses.panel.new_panel(self.spewwin) try: self.scrwin.border(ord('|'),ord('|'),ord('-'),ord('-'),ord(' '),ord(' '),ord(' '),ord(' ')) except: pass self.labelwin.addstr(0, 0, 'file:') self.labelwin.addstr(1, 0, 'size:') self.labelwin.addstr(2, 0, 'dest:') self.labelwin.addstr(3, 0, 'progress:') self.labelwin.addstr(4, 0, 'status:') self.labelwin.addstr(5, 0, 'dl speed:') self.labelwin.addstr(6, 0, 'ul speed:') self.labelwin.addstr(7, 0, 'sharing:') self.labelwin.addstr(8, 0, 'seeds:') self.labelwin.addstr(9, 0, 'peers:') curses.panel.update_panels() curses.doupdate() self.changeflag.clear() def finished(self): self.done = True self.downRate = '---' self.display({'activity':'download succeeded', 'fractionDone':1}) def error(self, errormsg): newerrmsg = strftime('[%H:%M:%S] ') + errormsg self.errors.append(newerrmsg.split('\n')[0]) self.errlist.append(newerrmsg) self.display({}) def display(self, statistics): fractionDone = statistics.get('fractionDone') activity = statistics.get('activity') timeEst = statistics.get('timeEst') downRate = statistics.get('downRate') upRate = statistics.get('upRate') spew = statistics.get('spew') inchar = self.fieldwin.getch() if inchar == 12: # ^L self._remake_window() elif inchar in (ord('q'),ord('Q')): self.doneflag.set() elif inchar in (ord('r'),ord('R')): self.reread_config() if timeEst is not None: self.activity = fmttime(timeEst) elif activity is not None: self.activity = activity if self.changeflag.isSet(): return if fractionDone is not None: blocknum = int(self.fieldw * fractionDone) self.progress = blocknum * '#' + (self.fieldw - blocknum) * '_' self.status = '%s (%.1f%%)' % (self.activity, fractionDone * 100) if downRate is not None: self.downRate = '%.1f KB/s' % (downRate / (1 << 10)) if upRate is not None: self.upRate = '%.1f KB/s' % (upRate / (1 << 10)) downTotal = statistics.get('downTotal') if downTotal is not None: upTotal = statistics['upTotal'] if downTotal <= upTotal / 100: self.shareRating = 'oo (%.1f MB up / %.1f MB down)' % ( upTotal / (1<<20), downTotal / (1<<20)) else: self.shareRating = '%.3f (%.1f MB up / %.1f MB down)' % ( upTotal / downTotal, upTotal / (1<<20), downTotal / (1<<20))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -