Example #1
0
    def _display_data(self, data):
        if 3 * len(data) <= self.mainwinh:
            self.scroll_pos = 0
            self.scrolling = False
        elif self.scroll_time + DOWNLOAD_SCROLL_RATE < time.time():
            self.scroll_time = time.time()
            self.scroll_pos += 1
            self.scrolling = True
            if self.scroll_pos >= 3 * len(data) + 2:
                self.scroll_pos = 0

        i = int(self.scroll_pos / 3)
        self.disp_line = (3 * i) - self.scroll_pos
        self.disp_end = False

        while not self.disp_end:
            ii = i % len(data)
            if i and not ii:
                if not self.scrolling:
                    break
                self._display_line('')
                if self._display_line(''):
                    break
            (name, status, progress, peers, seeds, _, dist, uprate, dnrate,
             upamt, dnamt, size, t, msg) = data[ii]
            if t is not None and t > 0:
                status = 'ETA in ' + formatIntClock(t)
            name = ljust(name, self.mainwinw - 32)
            size = rjust(formatSize(size), 8)
            uprate = rjust('%s/s' % formatSize(uprate), 10)
            dnrate = rjust('%s/s' % formatSize(dnrate), 10)
            line = "%3d %s%s%s%s" % (ii + 1, name, size, dnrate, uprate)
            self._display_line(line, True)
            if peers + seeds:
                datastr = '    ({}) {} - {} up {} dn - {} peers {} seeds ' \
                    '{:.3f} dist copies'.format(
                        progress, status, formatSize(upamt), formatSize(dnamt),
                        peers, seeds, dist)
            else:
                datastr = '    ({}) {} - {} up {} dn'.format(
                    progress, status, formatSize(upamt), formatSize(dnamt))
            self._display_line(datastr)
            self._display_line('    ' + ljust(msg, self.mainwinw - 4))
            i += 1
    def _display_data(self, data):
        if 3 * len(data) <= self.mainwinh:
            self.scroll_pos = 0
            self.scrolling = False
        elif self.scroll_time + DOWNLOAD_SCROLL_RATE < time.time():
            self.scroll_time = time.time()
            self.scroll_pos += 1
            self.scrolling = True
            if self.scroll_pos >= 3 * len(data) + 2:
                self.scroll_pos = 0

        i = int(self.scroll_pos / 3)
        self.disp_line = (3 * i) - self.scroll_pos
        self.disp_end = False

        while not self.disp_end:
            ii = i % len(data)
            if i and not ii:
                if not self.scrolling:
                    break
                self._display_line('')
                if self._display_line(''):
                    break
            (name, status, progress, peers, seeds, _, dist, uprate, dnrate,
             upamt, dnamt, size, t, msg) = data[ii]
            if t > 0:
                status = 'ETA in ' + formatIntClock(t)
            name = ljust(name, self.mainwinw - 32)
            size = rjust(formatSize(size), 8)
            uprate = rjust('%s/s' % formatSize(uprate), 10)
            dnrate = rjust('%s/s' % formatSize(dnrate), 10)
            line = "%3d %s%s%s%s" % (ii + 1, name, size, dnrate, uprate)
            self._display_line(line, True)
            if peers + seeds:
                datastr = '    ({}) {} - {} up {} dn - {} peers {} seeds ' \
                    '{:.3f} dist copies'.format(
                        progress, status, formatSize(upamt), formatSize(dnamt),
                        peers, seeds, dist)
            else:
                datastr = '    ({}) {} - {} up {} dn'.format(
                    progress, status, formatSize(upamt), formatSize(dnamt))
            self._display_line(datastr)
            self._display_line('    ' + ljust(msg, self.mainwinw - 4))
            i += 1
Example #3
0
    def stats(self):
        self.rawserver.add_task(self.stats, self.stats_period)
        data = []
        for hash in self.torrent_list:
            cache = self.torrent_cache[hash]
            if self.config['display_path']:
                name = cache['path']
            else:
                name = cache['name']
            size = cache['length']
            d = self.downloads[hash]
            progress = '0.0%'
            peers = 0
            seeds = 0
            seedsmsg = "S"
            dist = 0.0
            uprate = 0.0
            dnrate = 0.0
            upamt = 0
            dnamt = 0
            t = 0
            if d.is_dead():
                status = 'stopped'
            elif d.waiting:
                status = 'waiting for hash check'
            elif d.checking:
                status = d.status_msg
                progress = '{:.1%}'.format(d.status_done)
            else:
                stats = d.statsfunc()
                s = stats['stats']
                if d.seed:
                    status = 'seeding'
                    progress = '100.0%'
                    seeds = s.numOldSeeds
                    seedsmsg = "s"
                    dist = s.numCopies
                else:
                    if s.numSeeds + s.numPeers:
                        t = stats['time']
                        if t == 0:  # unlikely
                            t = 0.01
                        status = formatIntClock(t) or 'downloading'
                    else:
                        t = -1
                        status = 'connecting to peers'
                    progress = '{:.1%}'.format(stats['frac'])
                    seeds = s.numSeeds
                    dist = s.numCopies2
                    dnrate = stats['down']
                peers = s.numPeers
                uprate = stats['up']
                upamt = s.upTotal
                dnamt = s.downTotal

            if d.is_dead() or d.status_errtime + 300 > clock():
                msg = d.status_err[-1]
            else:
                msg = ''

            data.append((name, status, progress, peers, seeds, seedsmsg, dist,
                         uprate, dnrate, upamt, dnamt, size, t, msg))
        stop = self.Output.display(data)
        if stop:
            self.doneflag.set()
Example #4
0
    def display(self,
                dpflag=threading.Event(),
                fractionDone=None,
                timeEst=None,
                downRate=None,
                upRate=None,
                activity=None,
                statistics=None,
                spew=None,
                **kwargs):

        inchar = self.fieldwin.getch()
        if inchar == 12:  # ^L
            self._remake_window()
        elif inchar in (ord('q'), ord('Q')):
            self.doneflag.set()

        if activity is not None and not self.done:
            self.activity = activity
        elif timeEst == 0:
            self.activity = 'download complete!'
        elif timeEst is not None:
            self.activity = 'finishing in ' + formatIntClock(timeEst)
        if self.changeflag.is_set() or \
                self.last_update_time + 0.1 > clock() and \
                fractionDone not in (0.0, 1.0) and \
                activity is not None:
            return
        self.last_update_time = clock()
        if fractionDone is not None:
            blocknum = int(self.fieldw * fractionDone)
            self.progress = blocknum * '#' + (self.fieldw - blocknum) * '_'
            self.status = '%s (%.1f%%)' % (self.activity, fractionDone * 100)
        else:
            self.status = self.activity
        if downRate is not None:
            self.downRate = '%.1f KB/s' % (float(downRate) / (1 << 10))
        if upRate is not None:
            self.upRate = '%.1f KB/s' % (float(upRate) / (1 << 10))
        if statistics is not None:
            self.shareRating = '{}  ({:.1f} MB up / {:.1f} MB down)'.format(
                '{:.3f}'.format(statistics.shareRating)
                if 0 <= statistics.shareRating <= 100 else 'oo',
                float(statistics.upTotal) / (1 << 20),
                float(statistics.downTotal) / (1 << 20))
            if self.done:
                seeds = '{:d} seen recently, '.format(statistics.numOldSeeds)
                copies = 'plus {:.3f} distributed copies'.format(
                    round(statistics.numCopies, 3))
            else:
                seeds = '{:d} seen now, '.format(statistics.numSeeds)
                copies = 'plus {:.3f} distributed copies'.format(
                    round(statistics.numCopies2, 3))
            self.seedStatus = seeds + copies
            self.peerStatus = '{:d} seen now, {:.1f}% done at {:.1f} kB/s' \
                ''.format(statistics.numPeers, statistics.percentDone,
                          float(statistics.torrentRate) / (1 << 10))

        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, "error(s):", self.speww,
                                     curses.A_BOLD)
                errsize = len(self.errors)
                displaysize = min(errsize, self.spewh)
                displaytop = errsize - displaysize
                for i in range(displaysize):
                    self.spewwin.addnstr(i, self.labelw,
                                         self.errors[displaytop + i],
                                         self.speww - self.labelw - 1,
                                         curses.A_BOLD)
        else:
            if self.errors:
                self.spewwin.addnstr(0, 0, "error:", self.speww, curses.A_BOLD)
                self.spewwin.addnstr(0, self.labelw, self.errors[-1],
                                     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 < clock():
                self.spew_scroll_time = clock()
                if len(spew) > self.spewh - 5 or self.spew_scroll_pos > 0:
                    self.spew_scroll_pos += 1
            if self.spew_scroll_pos > len(spew):
                self.spew_scroll_pos = 0

            for i, subspew in enumerate(spew, 1):
                subspew['lineno'] = i
            spew.append({'lineno': None})
            spew = spew[self.spew_scroll_pos:] + spew[:self.spew_scroll_pos]

            for i in range(min(self.spewh - 5, len(spew))):
                if not spew[i]['lineno']:
                    continue
                self.spewwin.addnstr(i + 3, 0, '%3d' % spew[i]['lineno'], 3)
                self.spewwin.addnstr(i + 3, 4,
                                     spew[i]['ip'] + spew[i]['direction'], 16)
                if spew[i]['uprate'] > 100:
                    self.spewwin.addnstr(
                        i + 3, 20,
                        '{:6.0f} KB/s'.format(float(spew[i]['uprate']) / 1000),
                        11)
                self.spewwin.addnstr(i + 3, 32, '-----', 5)
                if spew[i]['uinterested']:
                    self.spewwin.addnstr(i + 3, 33, 'I', 1)
                if spew[i]['uchoked']:
                    self.spewwin.addnstr(i + 3, 35, 'C', 1)
                if spew[i]['downrate'] > 100:
                    self.spewwin.addnstr(
                        i + 3, 38, '{:6.0f} KB/s'.format(
                            float(spew[i]['downrate']) / 1000), 11)
                self.spewwin.addnstr(i + 3, 50, '-------', 7)
                if spew[i]['dinterested']:
                    self.spewwin.addnstr(i + 3, 51, 'I', 1)
                if spew[i]['dchoked']:
                    self.spewwin.addnstr(i + 3, 53, 'C', 1)
                if spew[i]['snubbed'] == 1:
                    self.spewwin.addnstr(i + 3, 55, 'S', 1)
                self.spewwin.addnstr(i + 3, 58,
                                     '{:6.1%}'.format(spew[i]['completed']), 6)
                if spew[i]['speed'] is not None:
                    self.spewwin.addnstr(
                        i + 3, 64,
                        '{:5.0f} KB/s'.format(float(spew[i]['speed']) / 1000),
                        10)

            if statistics is not None:
                self.spewwin.addnstr(
                    self.spewh - 1, 0, 'downloading {:d} pieces, have {:d} '
                    'fragments, {:d} of {:d} pieces completed'.format(
                        statistics.storage_active, statistics.storage_dirty,
                        statistics.storage_numcomplete,
                        statistics.storage_totalpieces), self.speww - 1)

        curses.panel.update_panels()
        curses.doupdate()
        dpflag.set()
Example #5
0
    def display(self, dpflag=threading.Event(), fractionDone=None,
                timeEst=None, downRate=None, upRate=None, activity=None,
                statistics=None, spew=None, **kwargs):

        inchar = self.fieldwin.getch()
        if inchar == 12:                    # ^L
            self._remake_window()
        elif inchar in (ord('q'), ord('Q')):
            self.doneflag.set()

        if activity is not None and not self.done:
            self.activity = activity
        elif timeEst is not None:
            self.activity = 'finishing in ' + formatIntClock(timeEst)
        if self.changeflag.isSet() or \
                self.last_update_time + 0.1 > clock() and \
                fractionDone not in (0.0, 1.0) and \
                activity is not None:
            return
        self.last_update_time = clock()
        if fractionDone is not None:
            blocknum = int(self.fieldw * fractionDone)
            self.progress = blocknum * '#' + (self.fieldw - blocknum) * '_'
            self.status = '%s (%.1f%%)' % (self.activity, fractionDone * 100)
        else:
            self.status = self.activity
        if downRate is not None:
            self.downRate = '%.1f KB/s' % (float(downRate) / (1 << 10))
        if upRate is not None:
            self.upRate = '%.1f KB/s' % (float(upRate) / (1 << 10))
        if statistics is not None:
            self.shareRating = '{}  ({:.1f} MB up / {:.1f} MB down)'.format(
                '{:.3f}'.format(statistics.shareRating)
                if 0 <= statistics.shareRating <= 100 else 'oo',
                float(statistics.upTotal) / (1 << 20),
                float(statistics.downTotal) / (1 << 20))
            if self.done:
                seeds = '{:d} seen recently, '.format(statistics.numOldSeeds)
                copies = 'plus {:.3f} distributed copies'.format(
                    round(statistics.numCopies, 3))
            else:
                seeds = '{:d} seen now, '.format(statistics.numSeeds)
                copies = 'plus {:.3f} distributed copies'.format(
                    round(statistics.numCopies2, 3))
            self.seedStatus = seeds + copies
            self.peerStatus = '{:d} seen now, {:.1f}% done at {:.1f} kB/s' \
                ''.format(statistics.numPeers, statistics.percentDone,
                          float(statistics.torrentRate) / (1 << 10))

        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, "error(s):", self.speww,
                                     curses.A_BOLD)
                errsize = len(self.errors)
                displaysize = min(errsize, self.spewh)
                displaytop = errsize - displaysize
                for i in range(displaysize):
                    self.spewwin.addnstr(
                        i, self.labelw, self.errors[displaytop + i],
                        self.speww - self.labelw - 1, curses.A_BOLD)
        else:
            if self.errors:
                self.spewwin.addnstr(0, 0, "error:", self.speww, curses.A_BOLD)
                self.spewwin.addnstr(
                    0, self.labelw, self.errors[-1],
                    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 < clock():
                self.spew_scroll_time = clock()
                if len(spew) > self.spewh - 5 or self.spew_scroll_pos > 0:
                    self.spew_scroll_pos += 1
            if self.spew_scroll_pos > len(spew):
                self.spew_scroll_pos = 0

            for i, subspew in enumerate(spew, 1):
                subspew['lineno'] = i
            spew.append({'lineno': None})
            spew = spew[self.spew_scroll_pos:] + spew[:self.spew_scroll_pos]

            for i in range(min(self.spewh - 5, len(spew))):
                if not spew[i]['lineno']:
                    continue
                self.spewwin.addnstr(i + 3, 0, '%3d' % spew[i]['lineno'], 3)
                self.spewwin.addnstr(i + 3, 4,
                                     spew[i]['ip'] + spew[i]['direction'], 16)
                if spew[i]['uprate'] > 100:
                    self.spewwin.addnstr(i + 3, 20, '{:6.0f} KB/s'.format(
                        float(spew[i]['uprate']) / 1000), 11)
                self.spewwin.addnstr(i + 3, 32, '-----', 5)
                if spew[i]['uinterested']:
                    self.spewwin.addnstr(i + 3, 33, 'I', 1)
                if spew[i]['uchoked']:
                    self.spewwin.addnstr(i + 3, 35, 'C', 1)
                if spew[i]['downrate'] > 100:
                    self.spewwin.addnstr(i + 3, 38, '{:6.0f} KB/s'.format(
                        float(spew[i]['downrate']) / 1000), 11)
                self.spewwin.addnstr(i + 3, 50, '-------', 7)
                if spew[i]['dinterested']:
                    self.spewwin.addnstr(i + 3, 51, 'I', 1)
                if spew[i]['dchoked']:
                    self.spewwin.addnstr(i + 3, 53, 'C', 1)
                if spew[i]['snubbed'] == 1:
                    self.spewwin.addnstr(i + 3, 55, 'S', 1)
                self.spewwin.addnstr(i + 3, 58, '{:6.1%}'.format(
                    spew[i]['completed']), 6)
                if spew[i]['speed'] is not None:
                    self.spewwin.addnstr(i + 3, 64, '{:5.0f} KB/s'.format(
                        float(spew[i]['speed']) / 1000), 10)

            if statistics is not None:
                self.spewwin.addnstr(
                    self.spewh - 1, 0, 'downloading {:d} pieces, have %d '
                    'fragments, %d of %d pieces completed'.format(
                        statistics.storage_active,
                        statistics.storage_dirty,
                        statistics.storage_numcomplete,
                        statistics.storage_totalpieces),
                    self.speww - 1)

        curses.panel.update_panels()
        curses.doupdate()
        dpflag.set()
Example #6
0
    def stats(self):
        self.rawserver.add_task(self.stats, self.stats_period)
        data = []
        for hash in self.torrent_list:
            cache = self.torrent_cache[hash]
            if self.config['display_path']:
                name = cache['path']
            else:
                name = cache['name']
            size = cache['length']
            d = self.downloads[hash]
            progress = '0.0%'
            peers = 0
            seeds = 0
            seedsmsg = "S"
            dist = 0.0
            uprate = 0.0
            dnrate = 0.0
            upamt = 0
            dnamt = 0
            t = 0
            if d.is_dead():
                status = 'stopped'
            elif d.waiting:
                status = 'waiting for hash check'
            elif d.checking:
                status = d.status_msg
                progress = '{:.1%}'.format(d.status_done)
            else:
                stats = d.statsfunc()
                s = stats['stats']
                if d.seed:
                    status = 'seeding'
                    progress = '100.0%'
                    seeds = s.numOldSeeds
                    seedsmsg = "s"
                    dist = s.numCopies
                else:
                    if s.numSeeds + s.numPeers:
                        t = stats['time']
                        if t == 0:  # unlikely
                            t = 0.01
                        status = formatIntClock(t) or 'downloading'
                    else:
                        t = -1
                        status = 'connecting to peers'
                    progress = '{:.1%}'.format(stats['frac'])
                    seeds = s.numSeeds
                    dist = s.numCopies2
                    dnrate = stats['down']
                peers = s.numPeers
                uprate = stats['up']
                upamt = s.upTotal
                dnamt = s.downTotal

            if d.is_dead() or d.status_errtime + 300 > clock():
                msg = d.status_err[-1]
            else:
                msg = ''

            data.append((name, status, progress, peers, seeds, seedsmsg, dist,
                         uprate, dnrate, upamt, dnamt, size, t, msg))
        stop = self.Output.display(data)
        if stop:
            self.doneflag.set()
Example #7
0
    def display(
        self,
        dpflag=threading.Event(),
        fractionDone=None,
        timeEst=None,
        downRate=None,
        upRate=None,
        activity=None,
        statistics=None,
        spew=None,
        **kwargs
    ):

        inchar = self.fieldwin.getch()
        if inchar == -1:
            pass
        elif inchar == 12:  # ^L
            self._remake_window()
        elif inchar in b"qQ":
            self.doneflag.set()

        if activity is not None and not self.done:
            self.activity = activity
        elif timeEst == 0:
            self.activity = "download complete!"
        elif timeEst is not None:
            self.activity = "finishing in " + formatIntClock(timeEst)
        if (
            self.changeflag.is_set()
            or self.last_update_time + 0.1 > clock()
            and fractionDone not in (0.0, 1.0)
            and activity is not None
        ):
            return
        self.last_update_time = clock()
        if fractionDone is not None:
            blocknum = int(self.fieldw * fractionDone)
            self.progress = blocknum * "#" + (self.fieldw - blocknum) * "_"
            self.status = "%s (%.1f%%)" % (self.activity, fractionDone * 100)
        else:
            self.status = self.activity
        if downRate is not None:
            self.downRate = "%.1f KB/s" % (float(downRate) / (1 << 10))
        if upRate is not None:
            self.upRate = "%.1f KB/s" % (float(upRate) / (1 << 10))
        if statistics is not None:
            self.shareRating = "{}  ({:.1f} MB up / {:.1f} MB down)".format(
                "{:.3f}".format(statistics.shareRating) if 0 <= statistics.shareRating <= 100 else "oo",
                float(statistics.upTotal) / (1 << 20),
                float(statistics.downTotal) / (1 << 20),
            )
            if self.done:
                seeds = "{:d} seen recently, ".format(statistics.numOldSeeds)
                copies = "plus {:.3f} distributed copies".format(round(statistics.numCopies, 3))
            else:
                seeds = "{:d} seen now, ".format(statistics.numSeeds)
                copies = "plus {:.3f} distributed copies".format(round(statistics.numCopies2, 3))
            self.seedStatus = seeds + copies
            self.peerStatus = "{:d} seen now, {:.1f}% done at {:.1f} kB/s" "".format(
                statistics.numPeers, statistics.percentDone, float(statistics.torrentRate) / (1 << 10)
            )

        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, "error(s):", self.speww, curses.A_BOLD)
                errsize = len(self.errors)
                displaysize = min(errsize, self.spewh)
                displaytop = errsize - displaysize
                for i in range(displaysize):
                    self.spewwin.addnstr(
                        i, self.labelw, self.errors[displaytop + i], self.speww - self.labelw - 1, curses.A_BOLD
                    )
        else:
            if self.errors:
                self.spewwin.addnstr(0, 0, "error:", self.speww, curses.A_BOLD)
                self.spewwin.addnstr(0, self.labelw, self.errors[-1], 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 < clock():
                self.spew_scroll_time = clock()
                if len(spew) > self.spewh - 5 or self.spew_scroll_pos > 0:
                    self.spew_scroll_pos += 1
            if self.spew_scroll_pos > len(spew):
                self.spew_scroll_pos = 0

            for i, subspew in enumerate(spew, 1):
                subspew["lineno"] = i
            spew.append({"lineno": None})
            spew = spew[self.spew_scroll_pos :] + spew[: self.spew_scroll_pos]

            for i in range(min(self.spewh - 5, len(spew))):
                if not spew[i]["lineno"]:
                    continue
                self.spewwin.addnstr(i + 3, 0, "%3d" % spew[i]["lineno"], 3)
                self.spewwin.addnstr(i + 3, 4, spew[i]["ip"] + spew[i]["direction"], 16)
                if spew[i]["uprate"] > 100:
                    self.spewwin.addnstr(i + 3, 20, "{:6.0f} KB/s".format(float(spew[i]["uprate"]) / 1000), 11)
                self.spewwin.addnstr(i + 3, 32, "-----", 5)
                if spew[i]["uinterested"]:
                    self.spewwin.addnstr(i + 3, 33, "I", 1)
                if spew[i]["uchoked"]:
                    self.spewwin.addnstr(i + 3, 35, "C", 1)
                if spew[i]["downrate"] > 100:
                    self.spewwin.addnstr(i + 3, 38, "{:6.0f} KB/s".format(float(spew[i]["downrate"]) / 1000), 11)
                self.spewwin.addnstr(i + 3, 50, "-------", 7)
                if spew[i]["dinterested"]:
                    self.spewwin.addnstr(i + 3, 51, "I", 1)
                if spew[i]["dchoked"]:
                    self.spewwin.addnstr(i + 3, 53, "C", 1)
                if spew[i]["snubbed"] == 1:
                    self.spewwin.addnstr(i + 3, 55, "S", 1)
                self.spewwin.addnstr(i + 3, 58, "{:6.1%}".format(spew[i]["completed"]), 6)
                if spew[i]["speed"] is not None:
                    self.spewwin.addnstr(i + 3, 64, "{:5.0f} KB/s".format(float(spew[i]["speed"]) / 1000), 10)

            if statistics is not None:
                self.spewwin.addnstr(
                    self.spewh - 1,
                    0,
                    "downloading {:d} pieces, have {:d} "
                    "fragments, {:d} of {:d} pieces completed".format(
                        statistics.storage_active,
                        statistics.storage_dirty,
                        statistics.storage_numcomplete,
                        statistics.storage_totalpieces,
                    ),
                    self.speww - 1,
                )

        curses.panel.update_panels()
        curses.doupdate()
        dpflag.set()