summaryrefslogtreecommitdiffstats
path: root/pyLoadCli.py
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-05-10 21:23:46 +0200
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2011-05-10 21:23:46 +0200
commit60ae0ee3dce4715621b9964c91ad96e08e123204 (patch)
tree251aeb85742a32a8f3711879e4071a66e59bdc26 /pyLoadCli.py
parentfixes netload free (diff)
downloadpyload-60ae0ee3dce4715621b9964c91ad96e08e123204.tar.xz
rewritten cli, closed #275, #304
Diffstat (limited to 'pyLoadCli.py')
-rw-r--r--[-rwxr-xr-x]pyLoadCli.py556
1 files changed, 191 insertions, 365 deletions
diff --git a/pyLoadCli.py b/pyLoadCli.py
index 0fe88b572..5a4a152f2 100755..100644
--- a/pyLoadCli.py
+++ b/pyLoadCli.py
@@ -20,13 +20,12 @@
from getopt import GetoptError, getopt
import gettext
-from itertools import islice
import os
from os import _exit
from os.path import join
import sys
from sys import exit
-import threading
+from threading import Thread, Lock
from time import sleep
from traceback import print_exc
@@ -35,9 +34,13 @@ from codecs import getwriter
sys.stdout = getwriter("utf8")(sys.stdout, errors="replace")
from module import InitHomeDir
+from module.cli.printer import *
+from module.cli import AddPackage, ManageFiles
+
from module.utils import formatSize, decode
from module.ConfigParser import ConfigParser
-from module.remote.thriftbackend.ThriftClient import ThriftClient, NoConnection, NoSSL, WrongLogin, PackageDoesNotExists, ConnectionClosed
+from module.remote.thriftbackend.ThriftClient import ThriftClient, NoConnection, NoSSL, WrongLogin, ConnectionClosed
+from module.lib.Getch import Getch
class Cli:
def __init__(self, client, command):
@@ -45,21 +48,22 @@ class Cli:
self.command = command
if not self.command:
- self.getch = _Getch()
+ self.getch = Getch()
self.input = ""
- self.pos = [0, 0, 0]
self.inputline = 0
+ self.lastLowestLine = 0
self.menuline = 0
- self.new_package = {}
+ self.lock = Lock()
- self.links_added = 0
+ #processor funcions, these will be changed dynamically depending on control flow
+ self.headerHandler = self #the download status
+ self.bodyHandler = self #the menu section
+ self.inputHandler = self
os.system("clear")
- self.println(1, blue("py") + yellow("Load") + white(_(" Command Line Interface")))
- self.println(2, "")
-
- self.file_list = {}
+ println(1, blue("py") + yellow("Load") + white(_(" Command Line Interface")))
+ println(2, "")
self.thread = RefreshThread(self)
self.thread.start()
@@ -68,275 +72,176 @@ class Cli:
else:
self.processCommand()
+ def reset(self):
+ """ reset to initial main menu """
+ self.input = ""
+ self.headerHandler = self.bodyHandler = self.inputHandler = self
+
def start(self):
+ """ main loop. handle input """
while True:
#inp = raw_input()
inp = self.getch.impl()
if ord(inp) == 3:
os.system("clear")
sys.exit() # ctrl + c
- elif ord(inp) == 13:
+ elif ord(inp) == 13: #enter
try:
- self.handle_input()
+ self.lock.acquire()
+ self.inputHandler.onEnter(self.input)
+
except Exception, e:
- self.println(2, red(e))
- self.input = "" #enter
- self.print_input()
+ println(2, red(e))
+ finally:
+ self.lock.release()
+
elif ord(inp) == 127:
self.input = self.input[:-1] #backspace
- self.print_input()
+ try:
+ self.lock.acquire()
+ self.inputHandler.onBackSpace()
+ finally:
+ self.lock.release()
+
elif ord(inp) == 27: #ugly symbol
pass
else:
self.input += inp
- self.print_input()
+ try:
+ self.lock.acquire()
+ self.inputHandler.onChar(inp)
+ finally:
+ self.lock.release()
- def format_time(self, seconds):
- seconds = int(seconds)
+ self.inputline = self.bodyHandler.renderBody(self.menuline)
+ self.renderFooter(self.inputline)
- hours, seconds = divmod(seconds, 3600)
- minutes, seconds = divmod(seconds, 60)
- return "%.2i:%.2i:%.2i" % (hours, minutes, seconds)
- def println(self, line, content):
- print "\033[" + str(line) + ";0H\033[2K" + content + "\033[" + \
- str((self.inputline if self.inputline > 0 else self.inputline + 1) - 1) + ";0H"
+ def refresh(self):
+ """refresh screen"""
- def print_input(self):
- self.println(self.inputline, white(" Input: ") + decode(self.input))
- self.println(self.inputline + 1, "")
- self.println(self.inputline + 2, "")
- self.println(self.inputline + 3, "")
- self.println(self.inputline + 4, "")
+ println(1, blue("py") + yellow("Load") + white(_(" Command Line Interface")))
+ println(2, "")
- def refresh(self):
- """Handle incoming data"""
- data = self.client.statusDownloads()
+ self.lock.acquire()
+
+ self.menuline = self.headerHandler.renderHeader(3) + 1
+ println(self.menuline - 1, "")
+ self.inputline = self.bodyHandler.renderBody(self.menuline)
+ self.renderFooter(self.inputline)
+
+ self.lock.release()
+
+
+ def setInput(self, string=""):
+ self.input = string
+
+ def setHandler(self, klass):
+ #create new handler with reference to cli
+ self.bodyHandler = self.inputHandler = klass(self)
+ self.input = ""
+
+ def renderHeader(self, line):
+ """ prints download status """
#print updated information
- print "\033[J" #clear screen
- self.println(1, blue("py") + yellow("Load") + white(_(" Command Line Interface")))
- self.println(2, "")
- self.println(3, white(_("%s Downloads:") % (len(data))))
- line = 4
+ # print "\033[J" #clear screen
+ # self.println(1, blue("py") + yellow("Load") + white(_(" Command Line Interface")))
+ # self.println(2, "")
+ # self.println(3, white(_("%s Downloads:") % (len(data))))
+
+ data = self.client.statusDownloads()
speed = 0
+
+ println(line, white(_("%s Downloads:") % (len(data))))
+ line += 1
+
for download in data:
if download.status == 12: # downloading
percent = download.percent
z = percent / 4
speed += download.speed
- self.println(line, cyan(download.name))
+ println(line, cyan(download.name))
line += 1
- self.println(line,
- blue("[") + yellow(z * "#" + (25 - z) * " ") + blue("] ") + green(str(percent) + "%") + _(
- " Speed: ") + green(formatSize(speed)+ "/s") + _(" Size: ") + green(
- download.format_size) + _(" Finished in: ") + green(download.format_eta) + _(
- " ID: ") + green(download.fid))
+ println(line,
+ blue("[") + yellow(z * "#" + (25 - z) * " ") + blue("] ") + green(str(percent) + "%") + _(
+ " Speed: ") + green(formatSize(speed) + "/s") + _(" Size: ") + green(
+ download.format_size) + _(" Finished in: ") + green(download.format_eta) + _(
+ " ID: ") + green(download.fid))
line += 1
if download.status == 5:
- self.println(line, cyan(download.name))
+ println(line, cyan(download.name))
line += 1
- self.println(line, _("waiting: ") + green(download.format_wait))
+ println(line, _("waiting: ") + green(download.format_wait))
line += 1
- self.println(line, "")
+
+ println(line, "")
line += 1
status = self.client.statusServer()
if status.pause:
- self.println(line,
- _("Status: ") + red("paused") + _(" total Speed: ") + red(formatSize(speed)+ "/s") + _(
- " Files in queue: ") + red(status.queue))
+ println(line,
+ _("Status: ") + red("paused") + _(" total Speed: ") + red(formatSize(speed) + "/s") + _(
+ " Files in queue: ") + red(status.queue))
else:
- self.println(line,
- _("Status: ") + red("running") + _(" total Speed: ") + red(formatSize(speed) + "/s") + _(
- " Files in queue: ") + red(status.queue))
- line += 1
- self.println(line, "")
+ println(line,
+ _("Status: ") + red("running") + _(" total Speed: ") + red(formatSize(speed) + "/s") + _(
+ " Files in queue: ") + red(status.queue))
+
+ return line + 1
+
+ def renderBody(self, line):
+ """ prints initial menu """
+ println(line, white(_("Menu:")))
+ println(line + 1, "")
+ println(line + 2, mag("1.") + _(" Add Links"))
+ println(line + 3, mag("2.") + _(" Manage Queue"))
+ println(line + 4, mag("3.") + _(" Manage Collector"))
+ println(line + 5, mag("4.") + _(" (Un)Pause Server"))
+ println(line + 6, mag("5.") + _(" Kill Server"))
+ println(line + 7, mag("6.") + _(" Quit"))
+
+ return line + 8
+
+ def renderFooter(self, line):
+ """ prints out the input line with input """
+ println(line, "")
line += 1
- self.menuline = line
- self.build_menu()
- #
- self.file_list = data
+ println(line, white(" Input: ") + decode(self.input))
- def build_menu(self):
- line = self.menuline
- self.println(line, white(_("Menu:")))
- line += 1
- if not self.pos[0]:# main menu
- self.println(line, "")
- line += 1
- self.println(line, mag("1.") + _(" Add Links"))
- line += 1
- self.println(line, mag("2.") + _(" Manage Links"))
- line += 1
- self.println(line, mag("3.") + _(" Manage Collector"))
- line += 1
- self.println(line, mag("4.") + _(" (Un)Pause Server"))
- line += 1
- self.println(line, mag("5.") + _(" Kill Server"))
- line += 1
- self.println(line, mag("6.") + _(" Quit"))
- line += 1
- self.println(line, "")
- line += 1
- self.println(line, "")
- elif self.pos[0] == 1:#add links
-
- if not self.pos[1]:
- self.println(line, "")
- line += 1
- self.println(line, _("Name your package."))
- line += 1
- self.println(line, "")
- line += 1
- self.println(line, "")
- line += 1
- self.println(line, "")
- line += 1
- self.println(line, "")
- line += 1
- self.println(line, mag("0.") + _(" back to main menu"))
- line += 1
- self.println(line, "")
+ #clear old output
+ if line < self.lastLowestLine:
+ for i in range(line + 1, self.lastLowestLine + 1):
+ println(i, "")
- else:
- self.println(line, _("Package: %s") % self.new_package['name'])
- line += 1
- self.println(line, _("Parse the links you want to add."))
- line += 1
- self.println(line, _("Type %s when done.") % mag("END"))
- line += 1
- self.println(line, _("Links added: ") + mag(self.links_added))
- line += 1
- self.println(line, "")
- line += 1
- self.println(line, "")
- line += 1
- self.println(line, mag("0.") + _(" back to main menu"))
- line += 1
- self.println(line, "")
- elif self.pos[0] == 2 or self.pos[0] == 3: #Manage Queues
- swapdest = "Collector" if self.pos[0] == 2 else "Queue"
- if not self.pos[1]:
- if self.pos[0] == 2:
- pack = self.client.getQueue()
- else:
- pack = self.client.getCollector()
- self.println(line, _(
- "Type d(number of package) to delete a package, r to restart, s to send to %s or w/o d,r,s to look into it." % swapdest))
- line += 1
- i = 0
- for value in islice(pack, self.pos[2], self.pos[2] + 5):
- try:
- self.println(line, mag(str(value.pid)) + ": " + value.name)
- line += 1
- i += 1
- except Exception, e:
- pass
- for x in range(5 - i):
- self.println(line, "")
- line += 1
+ self.lastLowestLine = line
- else:
- try:
- pack = self.client.getPackageData(self.pos[1])
- except PackageDoesNotExists:
- self.pos[1] = 0
- self.print_input()
- return
-
- self.println(line, _("Type d(number) of the link you want to delete, r(number) to restart, s(number) to send to %s." % swapdest))
- line += 1
- i = 0
- for value in islice(pack.links, self.pos[2], self.pos[2] + 5):
- try:
- self.println(line, mag(value.fid) + ": %s | %s | %s" % (
- value.name, value.statusmsg, value.plugin))
- line += 1
- i += 1
-
- except Exception, e:
- pass
- for x in range(5 - i):
- self.println(line, "")
- line += 1
-
- self.println(line, mag("p") + _(" - previous") + " | " + mag("n") + _(" - next"))
- line += 1
- self.println(line, mag("0.") + _(" back to main menu"))
-
- self.inputline = line + 1
- self.print_input()
-
- def handle_input(self):
- inp = self.input.strip()
- if inp == "0":
- self.pos = [0, 0, 0]
- self.build_menu()
- return True
-
- if not self.pos[0]:
- if inp == "1":
- self.links_added = 0
- self.pos[0] = 1
- elif inp == "2" or inp == "3":
- self.pos[0] = int(inp)
- self.pos[1] = 0
- elif inp == "4":
- self.client.togglePause()
- elif inp == "5":
- self.client.kill()
- self.client.close()
- sys.exit()
- elif inp == "6":
- os.system('clear')
- sys.exit()
-
- elif self.pos[0] == 1: #add links
- if not self.pos[1]:
- self.new_package['name'] = inp
- self.new_package['links'] = []
- self.pos[1] = 1
- else:
- if inp == "END":
- self.client.addPackage(self.new_package['name'], self.new_package['links'], 1) # add package
- self.pos = [0, 0, 0]
- self.links_added = 0
- else: #TODO validation
- self.new_package['links'].append(inp)
- self.links_added += 1
-
- elif self.pos[0] == 2 or self.pos[0] == 3: #Manage queue/collector
- if not self.pos[1]:
- if inp.startswith("d"):
- if inp.find("-") > -1:
- self.client.deletePackages(range(*map(int, inp[1:].split("-"))))
- else:
- self.client.deletePackages([int(inp[1:])])
- elif inp.startswith("r"):
- self.client.restartPackage(int(inp[1:]))
- elif inp.startswith("s"):
- self.client.movePackage(int(self.pos[0])-2,int(inp[1:])) # Opt 3-2 == 1 (queue) Opt 2-2 == 0 (collector)
- elif inp != "p" and inp != "n":
- self.pos[1] = int(inp)
- self.pos[2] = 0
- elif inp.startswith('r'):
- if inp.find("-") > -1:
- map(self.client.restartFile, range(*map(int, inp[1:].split("-"))))
- else:
- self.client.restartFile(int(inp[1:]))
- elif inp.startswith("s"):
- self.client.movePackage(int(self.pos[0])-2,int(inp[1:])) # Opt 3-2 == 1 (queue) Opt 2-2 == 0 (collector)
- elif inp.startswith('d'):
- if inp.find("-") > -1:
- self.client.deleteFiles(range(*map(int, inp[1:].split("-"))))
- else:
- self.client.deleteFiles([int(inp[1:])])
- if inp == "p":
- self.pos[2] -= 5
- elif inp == "n":
- self.pos[2] += 5
-
- self.build_menu()
+ #set cursor to position
+ print "\033[" + str(self.inputline) + ";0H"
+
+ def onChar(self, char):
+ """ default no special handling for single chars """
+ if char == "1":
+ self.setHandler(AddPackage)
+ elif char == "2":
+ self.setHandler(ManageFiles)
+ elif char == "3":
+ self.setHandler(ManageFiles)
+ self.bodyHandler.target = 0
+ elif char == "4":
+ self.client.togglePause()
+ elif char == "5":
+ self.client.kill()
+ self.client.close()
+ sys.exit()
+ elif char == "6":
+ os.system('clear')
+ sys.exit()
+
+ def onEnter(self, inp):
+ pass
+
+ def onBackSpace(self):
+ pass
def processCommand(self):
command = self.command[0]
@@ -347,10 +252,15 @@ class Cli:
if command == "status":
files = self.client.statusDownloads()
+ if not files:
+ print "No downloads running."
+
for download in files:
if download.status == 12: # downloading
print print_status(download)
- print "\tDownloading: %s @ %s/s\t %s (%s%%)" % (download.format_eta, formatSize(download.speed), formatSize(download.size - download.bleft), download.percent)
+ print "\tDownloading: %s @ %s/s\t %s (%s%%)" % (
+ download.format_eta, formatSize(download.speed), formatSize(download.size - download.bleft),
+ download.percent)
if download.status == 5:
print print_status(download)
print "\tWaiting: %s" % download.format_wait
@@ -368,6 +278,13 @@ class Cli:
self.client.addPackage(args[0], args[1:], 1)
+ elif command == "add_coll":
+ if len(args) < 2:
+ print _("Please use this syntax: add <Package name> <link> <link2> ...")
+ return
+
+ self.client.addPackage(args[0], args[1:], 0)
+
elif command == "del_file":
self.client.deleteFiles([int(x) for x in args])
print "Files deleted."
@@ -376,6 +293,11 @@ class Cli:
self.client.deletePackages([int(x) for x in args])
print "Packages deleted."
+ elif command == "move":
+ for pid in args:
+ pack = self.client.getPackageData(int(pid))
+ self.client.movePackage((pack.dest + 1) % 2, pack.pid)
+
elif command == "pause":
self.client.pause()
@@ -391,9 +313,9 @@ class Cli:
print_commands()
-class RefreshThread(threading.Thread):
+class RefreshThread(Thread):
def __init__(self, cli):
- threading.Thread.__init__(self)
+ Thread.__init__(self)
self.setDaemon(True)
self.cli = cli
@@ -407,110 +329,11 @@ class RefreshThread(threading.Thread):
print _("pyLoad was terminated")
_exit(0)
except Exception, e:
- self.cli.println(2, red(str(e)))
- self.cli.pos[1] = 0
- self.cli.pos[2] = 0
+ println(2, red(str(e)))
+ self.cli.reset()
print_exc()
-class _Getch:
- """
- Gets a single character from standard input. Does not echo to
- the screen.
- """
-
- def __init__(self):
- try:
- self.impl = _GetchWindows()
- except ImportError:
- try:
- self.impl = _GetchMacCarbon()
- except(AttributeError, ImportError):
- self.impl = _GetchUnix()
-
- def __call__(self): return self.impl()
-
-
-class _GetchUnix:
- def __init__(self):
- import tty
- import sys
-
- def __call__(self):
- import sys
- import tty
- import termios
-
- fd = sys.stdin.fileno()
- old_settings = termios.tcgetattr(fd)
- try:
- tty.setraw(sys.stdin.fileno())
- ch = sys.stdin.read(1)
- finally:
- termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
- return ch
-
-
-class _GetchWindows:
- def __init__(self):
- import msvcrt
-
- def __call__(self):
- import msvcrt
-
- return msvcrt.getch()
-
-class _GetchMacCarbon:
- """
- A function which returns the current ASCII key that is down;
- if no ASCII key is down, the null string is returned. The
- page http://www.mactech.com/macintosh-c/chap02-1.html was
- very helpful in figuring out how to do this.
- """
-
- def __init__(self):
- import Carbon
- Carbon.Evt #see if it has this (in Unix, it doesn't)
-
- def __call__(self):
- import Carbon
-
- if Carbon.Evt.EventAvail(0x0008)[0] == 0: # 0x0008 is the keyDownMask
- return ''
- else:
- #
- # The event contains the following info:
- # (what,msg,when,where,mod)=Carbon.Evt.GetNextEvent(0x0008)[1]
- #
- # The message (msg) contains the ASCII char which is
- # extracted with the 0x000000FF charCodeMask; this
- # number is converted to an ASCII character with chr() and
- # returned
- #
- (what, msg, when, where, mod) = Carbon.Evt.GetNextEvent(0x0008)[1]
- return chr(msg)
-
-def blue(string):
- return "\033[1;34m" + unicode(string) + "\033[0m"
-
-def green(string):
- return "\033[1;32m" + unicode(string) + "\033[0m"
-
-def yellow(string):
- return "\033[1;33m" + unicode(string) + "\033[0m"
-
-def red(string):
- return "\033[1;31m" + unicode(string) + "\033[0m"
-
-def cyan(string):
- return "\033[1;36m" + unicode(string) + "\033[0m"
-
-def mag(string):
- return "\033[1;35m" + unicode(string) + "\033[0m"
-
-def white(string):
- return "\033[1;37m" + unicode(string) + "\033[0m"
-
def print_help():
print
print "pyLoadCli Copyright (c) 2008-2011 the pyLoad Team"
@@ -521,11 +344,11 @@ def print_help():
print "See pyLoadCli.py -c for a complete listing."
print
print "<Options>"
- print " -i, --interactive", " Start in interactive mode"
- print
- print " -u, --username=", " " * 2, "Specify Username"
+ print " -i, --interactive", " Start in interactive mode"
+ print
+ print " -u, --username=", " " * 2, "Specify Username"
print " --pw=<password>", " " * 2, "Password"
- print " -a, --address=", " "*3, "Specify address (default=127.0.0.1)"
+ print " -a, --address=", " " * 3, "Specify address (default=127.0.0.1)"
print " -p, --port", " " * 7, "Specify port (default=7227)"
print
print " -h, --help", " " * 7, "Display this help screen"
@@ -537,32 +360,37 @@ def print_packages(data):
for pack in data:
print "Package %s (#%s):" % (pack.name, pack.pid)
for download in pack.links:
- print "\t" + print_file(download)
+ print "\t" + print_file(download)
print
+
def print_file(download):
return "#%(id)-6d %(name)-30s %(statusmsg)-10s %(plugin)-8s" % {
- "id": download.fid,
- "name": download.name,
- "statusmsg": download.statusmsg,
- "plugin": download.plugin
- }
+ "id": download.fid,
+ "name": download.name,
+ "statusmsg": download.statusmsg,
+ "plugin": download.plugin
+ }
+
def print_status(download):
return "#%(id)-6s %(name)-40s Status: %(statusmsg)-10s Size: %(size)s" % {
- "id": download.fid,
- "name": download.name,
- "statusmsg": download.statusmsg,
- "size": download.format_size
- }
+ "id": download.fid,
+ "name": download.name,
+ "statusmsg": download.statusmsg,
+ "size": download.format_size
+ }
+
def print_commands():
commands = [("status", _("Prints server status")),
("queue", _("Prints downloads in queue")),
("collector", _("Prints downloads in collector")),
("add <name> <link1> <link2>...", _("Adds package to queue")),
+ ("add_coll <name> <link1> <link2>...", _("Adds package to collector")),
("del_file <fid> <fid2>...", _("Delete Files from Queue/Collector")),
("del_package <pid> <pid2>...", _("Delete Packages from Queue/Collector")),
+ ("move <pid> <pid2>...", _("Move Packages from Queue to Collector or vice versa")),
("pause", _("Pause the server")),
("unpause", _("continue downloads")),
("toggle", _("Toggle pause/unpause")),
@@ -571,7 +399,7 @@ def print_commands():
print _("List of commands:")
print
for c in commands:
- print "%-30s %s" % c
+ print "%-35s %s" % c
if __name__ == "__main__":
config = ConfigParser()
@@ -622,7 +450,6 @@ if __name__ == "__main__":
client = False
if interactive:
-
try:
client = ThriftClient(addr, port, username, password)
except WrongLogin:
@@ -648,18 +475,17 @@ if __name__ == "__main__":
except WrongLogin:
print _("Login data is wrong.")
except NoConnection:
- print _("Could not establish connection to %(addr)s:%(port)s." % {"addr": addr, "port" : port })
+ print _("Could not establish connection to %(addr)s:%(port)s." % {"addr": addr, "port": port})
else:
try:
client = ThriftClient(addr, port, username, password)
except WrongLogin:
- print _("Login data is required.")
+ print _("Login data is wrong.")
except NoConnection:
- print _("Could not establish connection to %(addr)s:%(port)s." % {"addr": addr, "port" : port })
+ print _("Could not establish connection to %(addr)s:%(port)s." % {"addr": addr, "port": port})
except NoSSL:
- print _("You need py-openssl to connect to this pyLoad.")
-
+ print _("You need py-openssl to connect to this pyLoad core.")
if interactive and command: print _("Interactive mode ignored since you passed some commands.")