|
|
|
|
File: [Development] / bittornado / btlaunchmanycurses.py
(download)
/
(as text)
Revision: 1.30, Sat May 15 22:49:09 2004 UTC (6 years, 3 months ago) by theshadow Branch: MAIN Changes since 1.29: +1 -0 lines added cache cleanup code |
#!/usr/bin/env python
# Written by John Hoffman
# see LICENSE.txt for license information
DOWNLOAD_SCROLL_RATE = 1
from BitTornado import PSYCO
if PSYCO.psyco:
try:
import psyco
assert psyco.__version__ >= 0x010100f0
psyco.full()
except:
pass
from BitTornado.launchmanycore import LaunchMany
from BitTornado.download_bt1 import defaults, get_usage
from BitTornado.parseargs import parseargs
from threading import Event
from sys import argv, exit
from time import time, localtime, strftime
import sys, os
from BitTornado import version, report_email
from BitTornado.ConfigDir import ConfigDir
try:
import curses
import curses.panel
from curses.wrapper import wrapper as curses_wrapper
from signal import signal, SIGWINCH
except:
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)
assert sys.version >= '2', "Install Python 2.0 or greater"
try:
True
except:
True = 1
False = 0
Exceptions = []
def fmttime(n):
if n <= 0:
return None
n = int(n)
m, s = divmod(n, 60)
h, m = divmod(m, 60)
if h > 1000000:
return 'connecting to peers'
return 'ETA in %d:%02d:%02d' % (h, m, s)
def fmtsize(n):
n = long(n)
unit = [' B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
i = 0
if (n > 999):
i = 1
while i + 1 < len(unit) and (n >> 10) >= 999:
i += 1
n >>= 10
n = float(n) / (1 << 10)
if i > 0:
size = '%.1f' % n + '%s' % unit[i]
else:
size = '%.0f' % n + '%s' % unit[i]
return size
def ljust(s, size):
s = s[:size]
return s + (' '*(size-len(s)))
def rjust(s, size):
s = s[:size]
return (' '*(size-len(s)))+s
class CursesDisplayer:
def __init__(self, scrwin):
self.messages = []
self.scroll_pos = 0
self.scroll_time = 0
self.scrwin = scrwin
signal(SIGWINCH, self.winch_handler)
self.changeflag = Event()
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()
self._display_messages()
def _remake_window(self):
self.scrh, self.scrw = self.scrwin.getmaxyx()
self.scrpan = curses.panel.new_panel(self.scrwin)
self.mainwinh = int(2*(self.scrh)/3)
self.mainwinw = self.scrw - 4 # - 2 (bars) - 2 (spaces)
self.mainwiny = 2 # + 1 (bar) + 1 (titles)
self.mainwinx = 2 # + 1 (bar) + 1 (space)
# + 1 to all windows so we can write at mainwinw
self.mainwin = curses.newwin(self.mainwinh, self.mainwinw+1,
self.mainwiny, self.mainwinx)
self.mainpan = curses.panel.new_panel(self.mainwin)
self.mainwin.scrollok(0)
self.mainwin.nodelay(1)
self.headerwin = curses.newwin(1, self.mainwinw+1,
1, self.mainwinx)
self.headerpan = curses.panel.new_panel(self.headerwin)
self.headerwin.scrollok(0)
self.totalwin = curses.newwin(1, self.mainwinw+1,
self.mainwinh+1, self.mainwinx)
self.totalpan = curses.panel.new_panel(self.totalwin)
self.totalwin.scrollok(0)
self.statuswinh = self.scrh-4-self.mainwinh
self.statuswin = curses.newwin(self.statuswinh, self.mainwinw+1,
self.mainwinh+3, self.mainwinx)
self.statuspan = curses.panel.new_panel(self.statuswin)
self.statuswin.scrollok(0)
try:
self.scrwin.border(ord('|'),ord('|'),ord('-'),ord('-'),ord(' '),ord(' '),ord(' '),ord(' '))
except:
pass
self.headerwin.addnstr(0, 2, '#', self.mainwinw - 25, curses.A_BOLD)
self.headerwin.addnstr(0, 4, 'Filename', self.mainwinw - 25, curses.A_BOLD)
self.headerwin.addnstr(0, self.mainwinw - 24, 'Size', 4, curses.A_BOLD)
self.headerwin.addnstr(0, self.mainwinw - 18, 'Download', 8, curses.A_BOLD)
self.headerwin.addnstr(0, self.mainwinw - 6, 'Upload', 6, curses.A_BOLD)
self.totalwin.addnstr(0, self.mainwinw - 27, 'Totals:', 7, curses.A_BOLD)
self._display_messages()
curses.panel.update_panels()
curses.doupdate()
self.changeflag.clear()
def _display_line(self, s, bold = False):
if self.disp_end:
return True
line = self.disp_line
self.disp_line += 1
if line < 0:
return False
if bold:
self.mainwin.addnstr(line, 0, s, self.mainwinw, curses.A_BOLD)
else:
self.mainwin.addnstr(line, 0, s, self.mainwinw)
if self.disp_line >= self.mainwinh:
self.disp_end = True
return self.disp_end
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():
self.scroll_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, seedsmsg, dist,
uprate, dnrate, upamt, dnamt, size, t, msg ) = data[ii]
t = fmttime(t)
if t:
status = t
name = ljust(name,self.mainwinw-32)
size = rjust(fmtsize(size),8)
uprate = rjust('%s/s' % fmtsize(uprate),10)
dnrate = rjust('%s/s' % fmtsize(dnrate),10)
line = "%3d %s%s%s%s" % (ii+1, name, size, dnrate, uprate)
self._display_line(line, True)
if peers + seeds:
datastr = ' (%s) %s - %s peers %s seeds %.3f dist copies - %s up %s dn' % (
progress, status, peers, seeds, dist,
fmtsize(upamt), fmtsize(dnamt) )
else:
datastr = ' '+status+' ('+progress+')'
self._display_line(datastr)
self._display_line(' '+ljust(msg,self.mainwinw-4))
i += 1
def display(self, data):
if self.changeflag.isSet():
return
inchar = self.mainwin.getch()
if inchar == 12: # ^L
self._remake_window()
self.mainwin.erase()
if data:
self._display_data(data)
else:
self.mainwin.addnstr( 1, int(self.mainwinw/2)-5,
'no torrents', 12, curses.A_BOLD )
totalup = 0
totaldn = 0
for ( name, status, progress, peers, seeds, seedsmsg, dist,
uprate, dnrate, upamt, dnamt, size, t, msg ) in data:
totalup += uprate
totaldn += dnrate
totalup = '%s/s' % fmtsize(totalup)
totaldn = '%s/s' % fmtsize(totaldn)
self.totalwin.erase()
self.totalwin.addnstr(0, self.mainwinw-27, 'Totals:', 7, curses.A_BOLD)
self.totalwin.addnstr(0, self.mainwinw-20 + (10-len(totaldn)),
totaldn, 10, curses.A_BOLD)
self.totalwin.addnstr(0, self.mainwinw-10 + (10-len(totalup)),
totalup, 10, curses.A_BOLD)
curses.panel.update_panels()
curses.doupdate()
return inchar in (ord('q'),ord('Q'))
def message(self, s):
self.messages.append(strftime('%x %X - ',localtime(time()))+s)
self._display_messages()
def _display_messages(self):
self.statuswin.erase()
winpos = 0
for s in self.messages[-self.statuswinh:]:
self.statuswin.addnstr(winpos, 0, s, self.mainwinw)
winpos += 1
curses.panel.update_panels()
curses.doupdate()
def exception(self, s):
Exceptions.append(s)
self.message('SYSTEM ERROR - EXCEPTION GENERATED')
def LaunchManyWrapper(scrwin, config):
LaunchMany(config, CursesDisplayer(scrwin))
if __name__ == '__main__':
if argv[1:] == ['--version']:
print version
exit(0)
defaults.extend( [
( 'parse_dir_interval', 60,
"how often to rescan the torrent directory, in seconds" ),
( 'saveas_style', 2,
"How to name torrent downloads (1 = rename to torrent name, " +
"2 = save under name in torrent, 3 = save in directory under torrent name)" ),
( 'display_path', 0,
"whether to display the full path or the torrent contents for each torrent" ),
] )
try:
configdir = ConfigDir('launchmanycurses')
defaultsToIgnore = ['responsefile', 'url', 'priority']
configdir.setDefaults(defaults,defaultsToIgnore)
configdefaults = configdir.loadConfig()
defaults.append(('save_options',0,
"whether to save the current options as the new default configuration " +
"(only for btlaunchmanycurses.py)"))
if len(argv) < 2:
print "Usage: btlaunchmanycurses.py <directory> <global options>\n"
print "<directory> - directory to look for .torrent files (semi-recursive)"
print get_usage(defaults, 80, configdefaults)
exit(1)
config, args = parseargs(argv[1:], defaults, 1, 1, configdefaults)
if config['save_options']:
configdir.saveConfig(config)
configdir.deleteOldCacheData(config['expire_cache_data'])
if not os.path.isdir(args[0]):
raise ValueError("Warning: "+args[0]+" is not a directory")
config['torrent_dir'] = args[0]
except ValueError, e:
print 'error: ' + str(e) + '\nrun with no args for parameter explanations'
exit(1)
curses_wrapper(LaunchManyWrapper, config)
if Exceptions:
print '\nEXCEPTION:'
print Exceptions[0]
print 'please report this to '+report_email
| No CVS admin address has been configured |
Powered by ViewCVS 0.9.3 |