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 + -
显示快捷键?