#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#Copyright (C) 2011 RaNaN
#
#This program is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 3 of the License,
#or (at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#See the GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
# along with this program; if not, see .
#
###
from __future__ import with_statement
from getopt import GetoptError, getopt
import module.common.pylgettext as gettext
import os
from os import _exit
from os.path import join, exists, abspath, basename
import sys
from sys import exit
from threading import Thread, Lock
from time import sleep
from traceback import print_exc
import ConfigParser
from codecs import getwriter
if os.name == "nt":
enc = "cp850"
else:
enc = "utf8"
sys.stdout = getwriter(enc)(sys.stdout, errors="replace")
from module import InitHomeDir
from module.cli.printer import *
from module.cli import AddPackage, ManageFiles
from module.Api import Destination
from module.utils import formatSize, decode
from module.remote.thriftbackend.ThriftClient import ThriftClient, NoConnection, NoSSL, WrongLogin, ConnectionClosed
from module.lib.Getch import Getch
from module.lib.rename_process import renameProcess
class Cli:
def __init__(self, client, command):
self.client = client
self.command = command
if not self.command:
renameProcess('pyLoadCli')
self.getch = Getch()
self.input = ""
self.inputline = 0
self.lastLowestLine = 0
self.menuline = 0
self.lock = Lock()
#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")
println(1, blue("py") + yellow("Load") + white(_(" Command Line Interface")))
println(2, "")
self.thread = RefreshThread(self)
self.thread.start()
self.start()
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: #enter
try:
self.lock.acquire()
self.inputHandler.onEnter(self.input)
except Exception, e:
println(2, red(e))
finally:
self.lock.release()
elif ord(inp) == 127:
self.input = self.input[:-1] #backspace
try:
self.lock.acquire()
self.inputHandler.onBackSpace()
finally:
self.lock.release()
elif ord(inp) == 27: #ugly symbol
pass
else:
self.input += inp
try:
self.lock.acquire()
self.inputHandler.onChar(inp)
finally:
self.lock.release()
self.inputline = self.bodyHandler.renderBody(self.menuline)
self.renderFooter(self.inputline)
def refresh(self):
"""refresh screen"""
println(1, blue("py") + yellow("Load") + white(_(" Command Line Interface")))
println(2, "")
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))))
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
println(line, cyan(download.name))
line += 1
println(line,
blue("[") + yellow(z * "#" + (25 - z) * " ") + blue("] ") + green(str(percent) + "%") + _(
" Speed: ") + green(formatSize(download.speed) + "/s") + _(" Size: ") + green(
download.format_size) + _(" Finished in: ") + green(download.format_eta) + _(
" ID: ") + green(download.fid))
line += 1
if download.status == 5:
println(line, cyan(download.name))
line += 1
println(line, _("waiting: ") + green(download.format_wait))
line += 1
println(line, "")
line += 1
status = self.client.statusServer()
if status.pause:
paused = _("Status:") + " " + red(_("paused"))
else:
paused = _("Status:") + " " + red(_("running"))
println(line,"%s %s: %s %s: %s %s: %s" % (
paused, _("total Speed"), red(formatSize(speed) + "/s"), _("Files in queue"), red(
status.queue), _("Total"), red(status.total)))
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
println(line, white(" Input: ") + decode(self.input))
#clear old output
if line < self.lastLowestLine:
for i in range(line + 1, self.lastLowestLine + 1):
println(i, "")
self.lastLowestLine = line
#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 = Destination.Collector
elif char == "4":
self.client.togglePause()
self.setInput()
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]
args = []
if len(self.command) > 1:
args = self.command[1:]
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)
elif download.status == 5:
print print_status(download)
print "\tWaiting: %s" % download.format_wait
else:
print print_status(download)
elif command == "queue":
print_packages(self.client.getQueueData())
elif command == "collector":
print_packages(self.client.getCollectorData())
elif command == "add":
if len(args) < 2:
print _("Please use this syntax: add ...")
return
self.client.addPackage(args[0], args[1:], Destination.Queue)
elif command == "add_coll":
if len(args) < 2:
print _("Please use this syntax: add ...")
return
self.client.addPackage(args[0], args[1:], Destination.Collector)
elif command == "del_file":
self.client.deleteFiles([int(x) for x in args])
print "Files deleted."
elif command == "del_package":
self.client.deletePackages([int(x) for x in args])
print "Packages deleted."
elif command == "move":
for pid in args:
pack = self.client.getPackageInfo(int(pid))
self.client.movePackage((pack.dest + 1) % 2, pack.pid)
elif command == "check":
print _("Checking %d links:") % len(args)
print
rid = self.client.checkOnlineStatus(args).rid
self.printOnlineCheck(self.client, rid)
elif command == "check_container":
path = args[0]
if not exists(join(owd, path)):
print _("File does not exists.")
return
f = open(join(owd, path), "rb")
content = f.read()
f.close()
rid = self.client.checkOnlineStatusContainer([], basename(f.name), content).rid
self.printOnlineCheck(self.client, rid)
elif command == "pause":
self.client.pause()
elif command == "unpause":
self.client.unpause()
elif command == "toggle":
self.client.togglePause()
elif command == "kill":
self.client.kill()
elif command == "restart_file":
for x in args:
self.client.restartFile(int(x))
print "Files restarted."
elif command == "restart_package":
for pid in args:
self.client.restartPackage(int(pid))
print "Packages restarted."
else:
print_commands()
def printOnlineCheck(self, client, rid):
while True:
sleep(1)
result = client.pollResults(rid)
for url, status in result.data.iteritems():
if status.status == 2: check = "Online"
elif status.status == 1: check = "Offline"
else: check = "Unknown"
print "%-45s %-12s\t %-15s\t %s" % (status.name, formatSize(status.size), status.plugin, check)
if result.rid == -1: break
class RefreshThread(Thread):
def __init__(self, cli):
Thread.__init__(self)
self.setDaemon(True)
self.cli = cli
def run(self):
while True:
sleep(1)
try:
self.cli.refresh()
except ConnectionClosed:
os.system("clear")
print _("pyLoad was terminated")
_exit(0)
except Exception, e:
println(2, red(str(e)))
self.cli.reset()
print_exc()
def print_help(config):
print
print "pyLoadCli Copyright (c) 2008-2011 the pyLoad Team"
print
print "Usage: [python] pyLoadCli.py [options] [command]"
print
print ""
print "See pyLoadCli.py -c for a complete listing."
print
print ""
print " -i, --interactive", " Start in interactive mode"
print
print " -u, --username=", " " * 2, "Specify Username"
print " --pw=", " " * 2, "Password"
print " -a, --address=", " " * 3, "Specify address (current=%s)" % config["addr"]
print " -p, --port", " " * 7, "Specify port (current=%s)" % config["port"]
print
print " -l, --language", " " * 3, "Set user interface language (current=%s)" % config["language"]
print " -h, --help", " " * 7, "Display this help screen"
print " -c, --commands", " " * 3, "List all available commands"
print
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
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
}
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
}
def print_commands():
commands = [("status", _("Prints server status")),
("queue", _("Prints downloads in queue")),
("collector", _("Prints downloads in collector")),
("add ...", _("Adds package to queue")),
("add_coll ...", _("Adds package to collector")),
("del_file ...", _("Delete Files from Queue/Collector")),
("del_package ...", _("Delete Packages from Queue/Collector")),
("move ...", _("Move Packages from Queue to Collector or vice versa")),
("restart_file ...", _("Restart files")),
("restart_package ...", _("Restart packages")),
("check ...", _("Check online status, works with local container")),
("check_container path", _("Checks online status of a container file")),
("pause", _("Pause the server")),
("unpause", _("continue downloads")),
("toggle", _("Toggle pause/unpause")),
("kill", _("kill server")), ]
print _("List of commands:")
print
for c in commands:
print "%-35s %s" % c
def writeConfig(opts):
try:
with open(join(homedir, ".pyloadcli"), "w") as cfgfile:
cfgfile.write("[cli]")
for opt in opts:
cfgfile.write("%s=%s\n" % (opt, opts[opt]))
except:
print _("Couldn't write user config file")
def main():
config = {"addr": "127.0.0.1", "port": "7227", "language": "en"}
try:
config["language"] = os.environ["LANG"][0:2]
except:
pass
if (not exists(join(pypath, "locale", config["language"]))) or config["language"] == "":
config["language"] = "en"
configFile = ConfigParser.ConfigParser()
configFile.read(join(homedir, ".pyloadcli"))
if configFile.has_section("cli"):
for opt in configFile.items("cli"):
config[opt[0]] = opt[1]
gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None])
translation = gettext.translation("pyLoadCli", join(pypath, "locale"),
languages=[config["language"],"en"],fallback=True)
translation.install(unicode=True)
interactive = False
command = None
username = ""
password = ""
shortOptions = 'iu:p:a:hcl:'
longOptions = ['interactive', "username=", "pw=", "address=", "port=", "help", "commands", "language="]
try:
opts, extraparams = getopt(sys.argv[1:], shortOptions, longOptions)
for option, params in opts:
if option in ("-i", "--interactive"):
interactive = True
elif option in ("-u", "--username"):
username = params
elif option in ("-a", "--address"):
config["addr"] = params
elif option in ("-p", "--port"):
config["port"] = params
elif option in ("-l", "--language"):
config["language"] = params
gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None])
translation = gettext.translation("pyLoadCli", join(pypath, "locale"),
languages=[config["language"],"en"],fallback=True)
translation.install(unicode=True)
elif option in ("-h", "--help"):
print_help(config)
exit()
elif option in ("--pw"):
password = params
elif option in ("-c", "--comands"):
print_commands()
exit()
except GetoptError:
print 'Unknown Argument(s) "%s"' % " ".join(sys.argv[1:])
print_help(config)
exit()
if len(extraparams) >= 1:
command = extraparams
client = False
if interactive:
try:
client = ThriftClient(config["addr"], int(config["port"]), username, password)
except WrongLogin:
pass
except NoSSL:
print _("You need py-openssl to connect to this pyLoad Core.")
exit()
except NoConnection:
config["addr"] = False
config["port"] = False
if not client:
if not config["addr"]: config["addr"] = raw_input(_("Address: "))
if not config["port"]: config["port"] = raw_input(_("Port: "))
if not username: username = raw_input(_("Username: "))
if not password:
from getpass import getpass
password = getpass(_("Password: "))
try:
client = ThriftClient(config["addr"], int(config["port"]), username, password)
except WrongLogin:
print _("Login data is wrong.")
except NoConnection:
print _("Could not establish connection to %(addr)s:%(port)s." % {"addr": config["addr"],
"port": config["port"]})
else:
try:
client = ThriftClient(config["addr"], int(config["port"]), username, password)
except WrongLogin:
print _("Login data is wrong.")
except NoConnection:
print _("Could not establish connection to %(addr)s:%(port)s." % {"addr": config["addr"],
"port": config["port"]})
except NoSSL:
print _("You need py-openssl to connect to this pyLoad core.")
if interactive and command: print _("Interactive mode ignored since you passed some commands.")
if client:
writeConfig(config)
cli = Cli(client, command)
if __name__ == "__main__":
main()