diff options
author | RaNaN <Mast3rRaNaN@hotmail.de> | 2009-12-20 00:27:02 +0100 |
---|---|---|
committer | RaNaN <Mast3rRaNaN@hotmail.de> | 2009-12-20 00:27:02 +0100 |
commit | 18d827faf2960efcfb2e1196375e5542e25d20ab (patch) | |
tree | 7cea392fd00051ba216e91b9199003286d2d2610 /pyLoadCli.py | |
parent | Fixed file_exists function for local files (diff) | |
download | pyload-18d827faf2960efcfb2e1196375e5542e25d20ab.tar.xz |
reimplemented old CLI
Diffstat (limited to 'pyLoadCli.py')
-rwxr-xr-x | pyLoadCli.py | 713 |
1 files changed, 360 insertions, 353 deletions
diff --git a/pyLoadCli.py b/pyLoadCli.py index 96165a7b5..d5e214ca4 100755 --- a/pyLoadCli.py +++ b/pyLoadCli.py @@ -1,274 +1,88 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# +#Copyright (C) 2009 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 <http://www.gnu.org/licenses/>. +# +### +import ConfigParser +import subprocess +import os +import os.path +from os import chdir +from os.path import join +from os.path import abspath +from os.path import dirname +from os import sep +from time import sleep +import sys +import time +import threading +import xmlrpclib -""" - 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. +from module.XMLConfigParser import XMLConfigParser - 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. +class pyLoadCli: + def __init__(self, server_url): + self.core = xmlrpclib.ServerProxy(server_url, allow_none=True) + self.getch = _Getch() + self.input = "" + self.pos = [0, 0] + self.inputline = 0 + self.menuline = 0 - You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. - - @author: mkaay - @version: v0.3 -""" + try: + self.core.get_server_version() + except: + print "pyLoadCore not running" + exit() -SERVER_VERSION = "0.3" + self.links_added = 0 -import curses -from time import sleep, time -import xmlrpclib -from threading import RLock, Thread -import sys -from os import chdir -from os.path import dirname -from os.path import abspath -from os import sep -import ConfigParser + os.system("clear") + self.println(1, blue("py") + yellow("Load") + white(" Command Line Interface")) + self.println(2, "") -class pyLoadCli: - menu_items = [] - - def __init__(self, stdscr, server_url): - self.stdscr = stdscr - self.lock = RLock() - self.lock.acquire() - self.stop = False - - self.download_win = None - self.collectorbox = None - self.add_win = None - self.proxy = None - - self.downloads = [] - self.tmp_bind = [] - self.current_dwin_rows = 0 - self.lock.release() - - self.connect(server_url) - - self.lock.acquire() - - curses.init_pair(1, curses.COLOR_BLUE, curses.COLOR_BLACK) - curses.init_pair(2, curses.COLOR_YELLOW, curses.COLOR_BLACK) - curses.init_pair(3, curses.COLOR_GREEN, curses.COLOR_BLACK) - curses.init_pair(4, curses.COLOR_CYAN, curses.COLOR_BLACK) - curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_WHITE ) - - self.screen = self.stdscr.subwin(23, 79, 0, 0) - self.screen.box() - self.screen.addstr(1, 48, "py", curses.color_pair(1)) - self.screen.addstr(1, 50, "Load", curses.color_pair(2)) - self.screen.addstr(1, 55, "Command Line Interface") - self.lock.release() - - self.add_menu("Status", "s", None) - self.add_menu("Collector", "c", self.collector_menu) - self.add_menu("Add-Link", "l", self.show_addl_box) - self.add_menu("New-Package", "p", self.show_newp_box) - self.add_menu("Quit", "q", self.exit) - - self.init_download_win() - self.update_downloads() - - def connect(self, server_url): - self.lock.acquire() - self.proxy = xmlrpclib.ServerProxy(server_url, allow_none=True) - server_version = self.proxy.get_server_version() - self.lock.release() - if not server_version == SERVER_VERSION: - raise Exception("server is version %s client accepts version %s" % (server_version, SERVER_VERSION)) - - def refresh(self): - self.lock.acquire() - self.screen.refresh() - self.lock.release() - - def init_download_win(self): - self.lock.acquire() - rows = 2 - if self.current_dwin_rows != 0: - rows = self.current_dwin_rows*3 + 1 - self.download_win = self.screen.subwin(rows, 75, 3, 2) - self.download_win.box() - self.lock.release() - - def adjust_download_win_size(self, down_num, force=False): - if self.current_dwin_rows != down_num or force: - self.lock.acquire() - self.download_win.erase() - self.current_dwin_rows = down_num - self.lock.release() - self.init_download_win() - self.screen.redrawwin() - - def update_downloads(self): - self.lock.acquire() - self.downloads = self.proxy.status_downloads() - self.lock.release() - self.adjust_download_win_size(len(self.downloads)) - self.show_downloads() - - def show_downloads(self): - self.lock.acquire() - self.download_win.redrawwin() - for r, d in enumerate(self.downloads): - r = r*3+1 - if d["status"] == "downloading": - self.download_win.addstr(r, 2, d["name"], curses.color_pair(4)) - self.download_win.addstr(r, 35, "[", curses.color_pair(1)) - self.download_win.addstr(r, 36, "#" * (int(d["percent"])/4), curses.color_pair(2)) - self.download_win.addstr(r, 61, "]", curses.color_pair(1)) - self.download_win.addstr(r, 63, "%s%%" % d["percent"], curses.color_pair(3)) - self.download_win.addstr(r+1, 8, "Speed:", curses.color_pair(0)) - self.download_win.addstr(r+1, 15, "%s kb/s" % int(d["speed"]), curses.color_pair(3)) - self.download_win.addstr(r+1, 25, "Size:", curses.color_pair(0)) - self.download_win.addstr(r+1, 31, self.format_size(d["size"]), curses.color_pair(3)) - self.download_win.addstr(r+1, 38, "ETA:", curses.color_pair(0)) - self.download_win.addstr(r+1, 43, self.format_time(d['eta']), curses.color_pair(3)) - self.download_win.addstr(r+1, 52, "ID:", curses.color_pair(0)) - self.download_win.addstr(r+1, 55, str(d["id"]), curses.color_pair(3)) - elif d["status"] == "waiting": - self.download_win.addstr(r, 2, d["name"], curses.color_pair(4)) - self.download_win.addstr(r+1, 4, "waiting: " + self.format_time(d["wait_until"]- time()), curses.color_pair(3)) - self.lock.release() - self.refresh() - - def show_addl_box(self): - self.lock.acquire() - curses.echo() - box = self.screen.subwin(4, 75, 18, 2) - box.box() - self.lock.release() - box.addstr(1, 2, "URL: (type 'END' if done)") - rows = [] + + self.file_list = {} + + self.thread = RefreshThread(self) + self.thread.start() + + self.start() + + def start(self): while True: - box.move(2, 2) - s = box.getstr() - if s == "END": - break + #inp = raw_input() + inp = self.getch.impl() + if ord(inp) == 3: + os.system("clear") + sys.exit() # ctrl + c + elif ord(inp) == 13: + self.handle_input() + self.input = "" #enter + self.print_input() + elif ord(inp) == 127: + self.input = self.input[:-1] #backspace + self.print_input() + elif ord(inp) == 27: #ugly symbol + pass else: - rows.append(s) - box.addstr(2, 2, " "*72) - box.erase() - self.lock.acquire() - curses.noecho() - for row in rows: - if row[:7] == "http://" or self.proxy.file_exists(row): - self.proxy.add_urls([row]) - self.lock.release() - - def show_newp_box(self): - self.lock.acquire() - curses.echo() - box = self.screen.subwin(4, 75, 18, 2) - box.box() - self.lock.release() - box.addstr(1, 2, "Package Name:") - box.move(2, 2) - s = box.getstr() - box.erase() - self.lock.acquire() - curses.noecho() - id = self.proxy.new_package(s) - self.lock.release() - self.show_package_edit(id) - - def show_package_edit(self, id): - self.lock.acquire() - self.tmp_bind = [] - data = self.proxy.get_package_data(id) - pfiles = self.proxy.get_package_files(id) - box = self.screen.subwin(7+len(pfiles[0:5]), 71, 4, 4) - box.box() - box.bkgdset(" ", curses.color_pair(0)) - self.lock.release() - box.addstr(1, 2, "ID: %(id)s" % data) - box.addstr(2, 2, "Name: %(package_name)s" % data) - box.addstr(3, 2, "Folder: %(folder)s" % data) - box.addstr(4, 2, "Files in Package:") - for r, fid in enumerate(pfiles[0:5]): - data = self.proxy.get_file_info(fid) - box.addstr(5+r, 2, "#%(id)d - %(url)s" % data) - box.move(len(pfiles[0:5])+5, 2) - self.show_link_collector() - curses.echo() - fid = box.getstr() - curses.noecho() - self.proxy.move_file_2_package(int(fid), id) - box.erase() - self.hide_collector() - self.redraw() - - def show_link_collector(self): - self.lock.acquire() - cfiles = self.proxy.get_collector_files() - self.collectorbox = self.screen.subwin(len(cfiles[0:5])+2, 71, 14, 4) - self.collectorbox.box() - for r, fid in enumerate(cfiles[0:5]): - data = self.proxy.get_file_info(fid) - self.collectorbox.addstr(r+1, 2, "#%(id)d - %(url)s" % data) - self.lock.release() - - def show_package_collector(self): - show = True - page = 0 - rows_pp = 6 - while show: - self.lock.acquire() - cpack = self.proxy.get_collector_packages() - self.collectorbox = self.screen.subwin(2+len(cpack[rows_pp*page:rows_pp*(page+1)]), 71, 14, 4) - self.collectorbox.box() - for r, data in enumerate(cpack[rows_pp*page:rows_pp*(page+1)]): - self.collectorbox.addstr(r+1, 2, "#%(id)d - %(package_name)s" % data) - self.lock.release() - self.refresh() - c = self.collectorbox.getch() - if c == ord("n"): - if page <= float(len(cpack))/float(rows_pp)-1: - page = page+1 - elif c == ord("p"): - page = page-1 - if page < 0: - page = 0 - elif c == ord("d"): - curses.echo() - id = self.collectorbox.getstr() - curses.noecho() - self.proxy.push_package_2_queue(int(id)) - else: - show = False - self.hide_collector() - - def hide_collector(self): - self.lock.acquire() - self.collectorbox.erase() - self.lock.release() - - def collector_menu(self): - menu = self.screen.subwin(4, 12, 2, 10) - menu.box() - menu.addstr(1, 1, " inks ") - menu.addstr(2, 1, " ackages ") - menu.addstr(1, 2, "L", curses.A_BOLD | curses.A_UNDERLINE) - menu.addstr(2, 2, "P", curses.A_BOLD | curses.A_UNDERLINE) - c = menu.getch() - menu.erase() - self.redraw() - if c == ord("l"): - return - elif c == ord("p"): - self.show_package_collector() - - def update_status(self): - self.update_downloads() - + self.input += inp + self.print_input() + def format_time(self, seconds): seconds = int(seconds) @@ -277,86 +91,261 @@ class pyLoadCli: return "%.2i:%.2i:%.2i" % (hours, minutes, seconds) def format_size(self, size): - return str(size / 1024) + " MB" - - def add_menu(self, name, key, func): - self.lock.acquire() - left = 2 - for item in self.menu_items: - left += len(item[0]) + 1 - self.menu_items.append((name, key.lower(), func)) - self.screen.addstr(1, left, name) - p = name.lower().find(key.lower()) - if not p == -1: - self.screen.addstr(1, left+p, name[p], curses.A_BOLD | curses.A_UNDERLINE) - self.lock.release() - - def get_menu_func(self, key): - for item in self.menu_items: - if ord(item[1]) == key: - return item[2] - return None - - def get_tmp_func(self, key): - for item in self.tmp_bind: - if item[0] == key: - return item[1] - return None - - def get_command(self): - c = self.screen.getch() - if c == curses.KEY_END: - self.exit() + return str(size / 1024) + " MiB" + + def println(self, line, content): + print "\033[" + str(line) + ";0H\033[2K" + str(content) + "\033[" + str((self.inputline if self.inputline > 0 else self.inputline + 1) - 1) + ";0H" + + def print_input(self): + self.println(self.inputline, white(" Input: ") + self.input) + self.println(self.inputline + 1, "") + self.println(self.inputline + 2, "") + self.println(self.inputline + 3, "") + self.println(self.inputline + 4, "") + + def refresh(self): + """Handle incoming data""" + data = self.core.status_downloads() + #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 + speed = 0 + for download in data: + if download["status"] == "downloading": + percent = download["percent"] + z = percent / 4 + speed += download['speed'] + self.println(line, cyan(download["name"])) + line += 1 + self.println(line, blue("[") + yellow(z * "#" + (25-z) * " ") + blue("] ") + green(str(percent) + "%") + " Speed: " + green(str(int(download['speed'])) + " kb/s") + " Size: " + green(self.format_size(download['size'])) + " Finished in: " + green(self.format_time(download['eta'])) + " ID: " + green(str(download['id']))) + line += 1 + if download["status"] == "waiting": + self.println(line, cyan(download["name"])) + line += 1 + self.println(line, "waiting: " + green(self.format_time(download["wait_until"]- time.time()))) + line += 1 + self.println(line, "") + line += 1 + status = self.core.status_server() + if status['pause']: + self.println(line, "Status: " + red("paused") + " total Speed: " + red(str(int(speed)) + " kb/s") + " Files in queue: " + red(str(status["queue"]))) else: - f = self.get_menu_func(c) - if not f: - f = self.get_tmp_func(c) - if f: - f() - self.refresh() - - def redraw(self): - self.adjust_download_win_size(len(self.downloads), force=True) - - def exit(self): - self.stop = True - -class LoopThread(Thread): - def __init__(self, func, ret_func=None, sleep_time=None): - self.func = func - self.ret_func = ret_func - self.sleep_time = sleep_time - self.running = True - Thread.__init__(self) + self.println(line, "Status: " + red("running") + " total Speed: " + red(str(int(speed)) + " kb/s") + " Files in queue: " + red(str(status["queue"]))) + line += 1 + self.println(line, "") + line += 1 + self.menuline = line + + self.build_menu() + # + self.file_list = data + + def build_menu(self): + line = self.menuline + self.println(line, white("Menu:")) + line += 1 + if self.pos[0] == 0:# main menu + self.println(line, "") + line += 1 + self.println(line, mag("1.") + " Add Links") + line += 1 + self.println(line, mag("2.") + " Remove Links") + line += 1 + self.println(line, mag("3.") + " (Un)Pause Server") + line += 1 + self.println(line, mag("4.") + " Kill Server") + line += 1 + self.println(line, mag("5.") + " Quit") + line += 1 + self.println(line, "") + line += 1 + self.println(line, "") + elif self.pos[0] == 1:#add links + self.println(line, "Parse the links you want to add.") + line += 1 + self.println(line, "") + line += 1 + self.println(line, "") + line += 1 + self.println(line, "Links added: " + mag(str(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:#remove links + self.println(line, "Type the number of the link you want to delete.") + line += 1 + i = 0 + for id in range(self.pos[1], self.pos[1] + 5): + if id < 0 or id >= len(self.file_list['order']): + continue + item = self.file_list['order'][id] + self.println(line, mag(str(item)) + ": " + self.file_list[item].url) + line += 1 + i += 1 + 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] + self.build_menu() + return True + + if self.pos[0] == 0: + if inp == "1": + self.links_added = 0 + self.pos[0] = 1 + elif inp == "2": + self.pos[0] = 2 + self.pos[1] = 0 + elif inp == "3": + self.core.toggle_pause() + elif inp == "4": + self.core.kill() + sys.exit() + elif inp == "5": + os.system('clear') + sys.exit() + elif self.pos[0] == 1: #add links + if inp[:7] == "http://" or os.path.exists(inp): + self.thread.push_exec("add_links", [(inp, None)]) + self.links_added += 1 + elif self.pos[0] == 2: #remove links + if inp == "p": + self.pos[1] -= 5 + elif inp == "n": + self.pos[1] += 5 + else: + self.thread.push_exec("remove_links", [[inp]]) + + self.build_menu() + +class RefreshThread(threading.Thread): + def __init__(self, cli): + threading.Thread.__init__(self) + self.cli = cli def run(self): - while self.running: - if self.sleep_time: - sleep(self.sleep_time) - ret = self.func() - if self.ret_func: - self.ret_func(ret) - - def stop(self): - self.running = False - -server_url = "" -def main(stdscr): - global server_url - cli = pyLoadCli(stdscr, server_url) - refresh_loop = LoopThread(cli.update_status, sleep_time=1) - refresh_loop.start() - getch_loop = LoopThread(cli.get_command) - getch_loop.start() - try: - while not cli.stop: + while True: + self.cli.refresh() sleep(1) - finally: - getch_loop.stop() - refresh_loop.stop() - return + + + + +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" + string + "\033[0m" + +def green(string): + return "\033[1;32m" + string + "\033[0m" + +def yellow(string): + return "\033[1;33m" + string + "\033[0m" + +def red(string): + return "\033[1;31m" + string + "\033[0m" + +def cyan(string): + return "\033[1;36m" + string + "\033[0m" + +def mag(string): + return "\033[1;35m" + string + "\033[0m" + +def white(string): + return "\033[1;37m" + string + "\033[0m" + +if __name__ == "__main__": -if __name__=='__main__': if len(sys.argv) > 1: shortOptions = 'l' @@ -365,26 +354,44 @@ if __name__=='__main__': opts, extraparams = __import__("getopt").getopt(sys.argv[1:], shortOptions, longOptions) for option, params in opts: if option in ("-l", "--local"): - chdir(dirname(abspath(__file__)) + sep) - config = ConfigParser.SafeConfigParser() - config.read('config') - ssl = "" - if config.get("ssl", "activated") == "True": + xmlconfig = XMLConfigParser(join(abspath(dirname(__file__)),"module","config","core.xml")) + config = xmlconfig.getConfig() + + ssl= "" + if config['ssl']['activated'] == "True": ssl = "s" + server_url = "http%s://%s:%s@%s:%s/" % ( - ssl, - config.get("remote", "username"), - config.get("remote", "password"), - config.get("remote", "listenaddr"), - config.get("remote", "port") - ) + ssl, + config['remote']['username'], + config['remote']['password'], + config['remote']['listenaddr'], + config['remote']['port'] + ) - if len(extraparams) == 1: - server_url = sys.argv[1] + if len(extraparams) == 4: + username, address, port, password = sys.argv[1:5] + + server_url = "http://%s:%s@%s:%s/" % ( + username, + adress, + port, + passwort + ) + else: - print "URL scheme: http[s]://user:password@host:port/" - server_url = raw_input("URL: ") + username = raw_input("Username:") + address = raw_input("Adress:") + port = raw_input("Port:") + password = raw_input("Password:") + + server_url = "http://%s:%s@%s:%s/" % ( + username, + adress, + port, + passwort + ) - curses.wrapper(main) - sys.exit() + + cli = pyLoadCli(server_url)
\ No newline at end of file |