diff options
| -rw-r--r-- | config | 4 | ||||
| -rwxr-xr-x | pyLoadCli.py | 527 | ||||
| -rwxr-xr-x | pyLoadCore.py | 25 | 
3 files changed, 229 insertions, 327 deletions
| @@ -1,5 +1,7 @@  [remote] -port = 7272 +port = 7227 +listenaddr = 0.0.0.0 +username = admin  password = pwhere  [webinterface] diff --git a/pyLoadCli.py b/pyLoadCli.py index fd65e04da..186281e32 100755 --- a/pyLoadCli.py +++ b/pyLoadCli.py @@ -1,77 +1,142 @@  #!/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 curses, traceback, string, os +from time import sleep, time +import xmlrpclib +from threading import RLock, Thread +import sys  import os.path  from os import chdir  from os.path import dirname  from os.path import abspath  from os import sep -from time import sleep -import sys -import time - -from module.remote.ClientSocket import SocketThread +import ConfigParser  class pyLoadCli: -    def __init__(self, adress, port, pw): -        self.thread = SocketThread(adress, int(port), pw, self) -        self.getch = _Getch() -        self.input = "" -        self.pos = [0, 0] -        self.inputline = 0 -        self.menuline = 0 - -        self.links_added = 0 - -        os.system("clear") -        self.println(1, blue("py") + yellow("Load") + white(" Command Line Interface")) -        self.println(2, "") - - -        self.file_list = {} -        self.thread.push_exec("get_links") - -        self.start() - -    def start(self): +    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.add_win = None +        self.proxy = None +         +        self.downloads = [] +        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) +         +        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("Add", "a", self.show_add_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) +        self.lock.release() +     +    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): +        if self.current_dwin_rows != down_num: +            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_add_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 = []          while True: -            #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 +            box.move(2, 2) +            s = box.getstr() +            if s == "END": +                break              else: -                self.input += inp -                self.print_input() - +                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 update_status(self): +        self.update_downloads() +          def format_time(self, seconds):          seconds = int(seconds) @@ -80,247 +145,75 @@ class pyLoadCli:          return "%.2i:%.2i:%.2i" % (hours, minutes, seconds)      def format_size(self, size): -        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 data_arrived(self, obj): -        """Handle incoming data""" -        if obj.command == "update": -            #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(obj.data)))) -            line = 4 -            speed = 0 -            for download in obj.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 -            if obj.status['pause']: -                self.println(line, "Status: " + red("paused") + " total Speed: " + red(str(int(speed)) + " kb/s") + " Files in queue: " + red(str(obj.status["queue"]))) -            else: -                self.println(line, "Status: " + red("running") + " total Speed: " + red(str(int(speed)) + " kb/s") + " Files in queue: " + red(str(obj.status["queue"]))) -            line += 1 -            self.println(line, "") -            line += 1 -            self.menuline = line -             -            self.build_menu() -        elif obj.command == "file_list" or obj.function == "get_links": -            self.file_list = obj.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.thread.push_exec("toggle_pause") -            elif inp == "4": -                self.thread.push_exec("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 _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 '' +        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_command(self): +        c = self.screen.getch() +        if c == curses.KEY_END: +            self.exit()          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__": - +            f = self.get_menu_func(c) +            if f: +                f() +        self.refresh() +     +    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) +     +    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: +            sleep(1) +    finally: +        getch_loop.stop() +        refresh_loop.stop() +        return + +if __name__=='__main__':      if len(sys.argv) > 1:          shortOptions = 'l' @@ -332,19 +225,19 @@ if __name__ == "__main__":                  chdir(dirname(abspath(__file__)) + sep)                  config = ConfigParser.SafeConfigParser()                  config.read('config') - -                pipe = subprocess.PIPE -                subprocess.Popen("./pyLoadCore.py", stdout=pipe, stderr=pipe) -                print "Starting pyLoad Core" -                sleep(1) -                cli = pyLoadCli("127.0.0.1", config.get("remote", "port"), config.get("remote", "password")) -        if len(extraparams) == 3: -            address, port, password = sys.argv[1:4] -            cli = pyLoadCli(address, port, password) +                server_url = "https://%s:%s@%s:%s/" % ( +                    config.get("remote", "username"), +                    config.get("remote", "password"), +                    config.get("remote", "listenaddr"), +                    config.get("remote", "port") +                ) +                 +        if len(extraparams) == 1: +            server_url = sys.argv[1]      else: -        address = raw_input("Adress:") -        port = raw_input("Port:") -        password = raw_input("Password:") -        cli = pyLoadCli(address, port, password) - +        print "URL scheme: https://user:password@host:port/" +        server_url = raw_input("URL: ") +         +    curses.wrapper(main) +    sys.exit() diff --git a/pyLoadCore.py b/pyLoadCore.py index b4045ffee..b329655a0 100755 --- a/pyLoadCore.py +++ b/pyLoadCore.py @@ -79,13 +79,6 @@ class Core(object):      def read_option(self):          return self.config -    def server_send_status(self): -        obj = RequestObject() -        obj.command = "update" -        obj.data = self.get_downloads() -        obj.status = self.server_status() -        self.server.push_all(obj) -      def init_webserver(self):  #        if not self.config['webinterface']['activated']:  #            return False @@ -175,7 +168,11 @@ class Core(object):  ####################################################################################################################      def init_server(self):          try: -            self.server = SecureXMLRPCServer(("", 1337), "ssl.crt", "ssl.key", {"testuser":"testpw"}) +            server_addr = (self.config['remote']['listenaddr'], int(self.config['remote']['port'])) +            usermap = { +                self.config['remote']['username']: self.config['remote']['password'] +            } +            self.server = SecureXMLRPCServer(server_addr, "ssl.crt", "ssl.key", usermap)              self.server.register_introspection_functions()              self.server.register_function(self.status_downloads)              self.server.register_function(self.status_server) @@ -187,7 +184,8 @@ class Core(object):              self.server.register_function(self.move_urls_down)              self.server.register_function(self.is_time_download)              self.server.register_function(self.is_time_reconnect) -    #       self.server.register_function(self.server_status) +            self.server.register_function(self.get_conf_val) +            self.server.register_function(self.file_exists)              self.logger.info("Test Server Started")              thread.start_new_thread(self.server.serve_forever, ())          except Exception, e: @@ -294,6 +292,12 @@ class Core(object):              downloads.append(download)          return downloads +    def get_conf_val(self, cat, var): +        if var != "username" and var != "password": +            return self.config[cat][var] +        else: +            raise Exception("not allowed!") +          def status_server(self):          status = {}          status['pause'] = self.thread_list.pause @@ -305,6 +309,9 @@ class Core(object):          return status +    def file_exists(self, path): #@XXX: security?! +        return exists(path) +          def add_urls(self, links):          self.file_list.extend(links)          self.file_list.save() | 
