summaryrefslogtreecommitdiffstats
path: root/pyLoadCli.py
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2009-12-20 00:27:02 +0100
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2009-12-20 00:27:02 +0100
commit18d827faf2960efcfb2e1196375e5542e25d20ab (patch)
tree7cea392fd00051ba216e91b9199003286d2d2610 /pyLoadCli.py
parentFixed file_exists function for local files (diff)
downloadpyload-18d827faf2960efcfb2e1196375e5542e25d20ab.tar.xz
reimplemented old CLI
Diffstat (limited to 'pyLoadCli.py')
-rwxr-xr-xpyLoadCli.py713
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