bittorrent-curses.py
来自「bittorrent source by python. please enj」· Python 代码 · 共 629 行 · 第 1/2 页
PY
629 行
#!/usr/bin/env python# The contents of this file are subject to the BitTorrent Open Source License# Version 1.1 (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 Urpala and David Harrisonfrom __future__ import divisionfrom BitTorrent.translation import _SPEW_SCROLL_RATE = 1import sysimport osimport loggingfrom logging import ERROR, WARNINGfrom time import time, strftime, sleepimport tracebackfrom BitTorrent import platformfrom BitTorrent.platform import encode_for_filesystem, decode_from_filesystemimport BitTorrent.stackthreading as threadingfrom BitTorrent.defer import DeferredEventfrom BitTorrent.MultiTorrent import MultiTorrent, TorrentAlreadyRunningfrom BitTorrent.Torrent import Feedbackfrom BitTorrent.defaultargs import get_defaultsfrom BitTorrent.parseargs import printHelpfrom BitTorrent.zurllib import urlopenfrom BitTorrent.prefs import Preferencesfrom BitTorrent.obsoletepythonsupport import import_cursesfrom BitTorrent import configfilefrom BitTorrent import BTFailure, UserFailurefrom BitTorrent import versionfrom BitTorrent import GetTorrentfrom BitTorrent.RawServer_twisted import RawServer, taskfrom BitTorrent.ConvertedMetainfo import ConvertedMetainfofrom BitTorrent.yielddefer import launch_coroutine, _wrap_taskfrom BitTorrent import inject_main_logfileinject_main_logfile()from BitTorrent import consolefrom BitTorrent import stderr_console # must import after inject_main_logfile # because import is really a copy. # If imported earlier, stderr_console # doesn't reflect the changes made in # inject_main_logfile!! # BAAAHHHH!!def wrap_log(context_string, logger): """Useful when passing a logger to a deferred's errback. The context specifies what was being done when the exception was raised.""" return lambda e, *args, **kwargs : logger.error(context_string, exc_info=e)try: curses = import_curses() import curses.panel from curses.wrapper import wrapper as curses_wrapper from signal import signal, SIGWINCHexcept: print _("Textmode UI 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 "bittorrent-console" 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, ulrate): self.scrwin = scrwin self.errlist = errlist self.doneflag = doneflag signal(SIGWINCH, self.winch_handler) self.changeflag = DeferredEvent() self.done = False self.reread_config = reread_config self.ulrate = ulrate 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() curses.use_default_colors() 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() elif inchar in (ord('u'),ord('U')): curses.echo() self.fieldwin.nodelay(0) s = self.fieldwin.getstr(6,10) curses.noecho() self.fieldwin.nodelay(1) r = None try: r = int(s) except ValueError: pass if r is not None: self.ulrate(r) 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)) #numCopies = statistics['numCopies'] #nextCopies = ', '.join(["%d:%.1f%%" % (a,int(b*1000)/10) for a,b in # zip(xrange(numCopies+1, 1000), statistics['numCopyList'])]) if not self.done: self.seedStatus = _("%d seen now") % statistics['numSeeds'] # self.seedStatus = _("%d seen now, plus %d distributed copies" # "(%s)") % (statistics['numSeeds' ], # statistics['numCopies'], # nextCopies) else: self.seedStatus = "" # self.seedStatus = _("%d distributed copies (next: %s)") % ( # statistics['numCopies'], nextCopies) self.peerStatus = _("%d seen now") % statistics['numPeers'] self.fieldwin.erase() self.fieldwin.addnstr(0, 0, self.file, self.fieldw, curses.A_BOLD) self.fieldwin.addnstr(1, 0, self.fileSize, self.fieldw) self.fieldwin.addnstr(2, 0, self.downloadTo, self.fieldw) if self.progress: self.fieldwin.addnstr(3, 0, self.progress, self.fieldw, curses.A_BOLD) self.fieldwin.addnstr(4, 0, self.status, self.fieldw) self.fieldwin.addnstr(5, 0, self.downRate, self.fieldw) self.fieldwin.addnstr(6, 0, self.upRate, self.fieldw) self.fieldwin.addnstr(7, 0, self.shareRating, self.fieldw) self.fieldwin.addnstr(8, 0, self.seedStatus, self.fieldw) self.fieldwin.addnstr(9, 0, self.peerStatus, self.fieldw) self.spewwin.erase() if not spew: errsize = self.spewh if self.errors: self.spewwin.addnstr(0, 0, _("log:"), self.speww, curses.A_BOLD) errsize = len(self.errors) displaysize = min(errsize, self.spewh-1) displaytop = errsize - displaysize errlst = [e[0:self.speww-self.labelw-2] for e in self.errors] for i in range(displaysize): self.spewwin.addnstr(i, self.labelw, errlst[displaytop + i], #self.speww-self.labelw-1, self.speww-self.labelw-2, curses.A_BOLD) else: if self.errors: self.spewwin.addnstr(0, 0, _("log:"), self.speww, curses.A_BOLD) err = self.errors[-1][0:self.speww-self.labelw-2] self.spewwin.addnstr(0, self.labelw, err, self.speww-self.labelw-1, curses.A_BOLD) self.spewwin.addnstr(2, 0, _(" # IP Upload Download Completed Speed"), self.speww, curses.A_BOLD) if self.spew_scroll_time + SPEW_SCROLL_RATE < time(): self.spew_scroll_time = time() if len(spew) > self.spewh-5 or self.spew_scroll_pos > 0: self.spew_scroll_pos += 1
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?