diff options
| -rw-r--r-- | .gitattributes | 1 | ||||
| -rw-r--r-- | pyload/Core.py | 603 | ||||
| -rw-r--r-- | pyload/cli/Cli.py | 586 | ||||
| -rw-r--r-- | pyload/plugins/container/DLC_25.pyc (renamed from module/plugins/container/DLC_25.pyc) | bin | 8340 -> 8340 bytes | |||
| -rw-r--r-- | pyload/plugins/container/DLC_26.pyc (renamed from module/plugins/container/DLC_26.pyc) | bin | 8313 -> 8313 bytes | |||
| -rw-r--r-- | pyload/plugins/container/DLC_27.pyc (renamed from module/plugins/container/DLC_27.pyc) | bin | 8237 -> 8237 bytes | 
6 files changed, 1190 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..176a458f9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/pyload/Core.py b/pyload/Core.py new file mode 100644 index 000000000..575eda357 --- /dev/null +++ b/pyload/Core.py @@ -0,0 +1,603 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +############################################################################### +#   Copyright(c) 2008-2013 pyLoad Team +#   http://www.pyload.org +# +#   This file is part of pyLoad. +#   pyLoad is free software: you can redistribute it and/or modify +#   it under the terms of the GNU Affero General Public License as +#   published by the Free Software Foundation, either version 3 of the +#   License, or (at your option) any later version. +# +#   Subjected to the terms and conditions in LICENSE +############################################################################### + +CURRENT_VERSION = '0.4.9.9-dev' + +import __builtin__ + +from getopt import getopt, GetoptError +import logging +import logging.handlers +import os +from os import _exit, execl, getcwd, remove, walk, chdir, close +import signal +import sys +from sys import argv, executable, exit +from time import time, sleep +from traceback import print_exc + +import locale +locale.locale_alias = locale.windows_locale = {} #save ~100kb ram, no known sideeffects for now + +import subprocess +subprocess.__doc__ = None # the module with the largest doc we are using + +import InitHomeDir +from AccountManager import AccountManager +from config.ConfigParser import ConfigParser +from config.ConfigManager import ConfigManager +from PluginManager import PluginManager +from interaction.EventManager import EventManager +from network.RequestFactory import RequestFactory +from web.ServerThread import WebServer +from Scheduler import Scheduler +from remote.RemoteManager import RemoteManager +from utils.JsEngine import JsEngine + +import utils.pylgettext as gettext +from utils import formatSize, get_console_encoding +from utils.fs import free_space, exists, makedirs, join, chmod + +from codecs import getwriter + +# test runner overwrites sys.stdout +if hasattr(sys.stdout, "encoding"): enc = get_console_encoding(sys.stdout.encoding) +else: enc = "utf8" + +sys._stdout = sys.stdout +sys.stdout = getwriter(enc)(sys.stdout, errors="replace") + +# TODO List +# - configurable auth system ldap/mysql +# - cron job like sheduler +# - plugin stack / multi decrypter +# - media plugin type +# - general progress info +# - content attribute for files / sync status +# - sync with disk content / file manager / nested packages +# - sync between pyload cores +# - new attributes (date|sync status) +# - embedded packages +# - would require new/modified link collector concept +# - pausable links/packages +# - toggable accounts +# - interaction manager +# - improve external scripts +# - make pyload undestructable to fail plugins -> see ConfigParser first + +class Core(object): +    """pyLoad Core, one tool to rule them all... (the filehosters) :D""" + +    def __init__(self): +        self.doDebug = False +        self.running = False +        self.daemon = False +        self.remote = True +        self.pdb = None +        self.arg_links = [] +        self.pidfile = "pyload.pid" +        self.deleteLinks = False # will delete links on startup + +        if len(argv) > 1: +            try: +                options, args = getopt(argv[1:], 'vchdusqp:', +                    ["version", "clear", "clean", "help", "debug", "user", +                     "setup", "configdir=", "changedir", "daemon", +                     "quit", "status", "no-remote","pidfile="]) + +                for option, argument in options: +                    if option in ("-v", "--version"): +                        print "pyLoad", CURRENT_VERSION +                        exit() +                    elif option in ("-p", "--pidfile"): +                        self.pidfile = argument +                    elif option == "--daemon": +                        self.daemon = True +                    elif option in ("-c", "--clear"): +                        self.deleteLinks = True +                    elif option in ("-h", "--help"): +                        self.print_help() +                        exit() +                    elif option in ("-d", "--debug"): +                        self.doDebug = True +                    elif option in ("-u", "--user"): +                        from Setup import Setup + +                        self.config = ConfigParser() +                        s = Setup(pypath, self.config) +                        s.set_user() +                        exit() +                    elif option in ("-s", "--setup"): +                        from Setup import Setup + +                        self.config = ConfigParser() +                        s = Setup(pypath, self.config) +                        s.start() +                        exit() +                    elif option == "--changedir": +                        from Setup import Setup + +                        self.config = ConfigParser() +                        s = Setup(pypath, self.config) +                        s.conf_path(True) +                        exit() +                    elif option in ("-q", "--quit"): +                        self.quitInstance() +                        exit() +                    elif option == "--status": +                        pid = self.isAlreadyRunning() +                        if self.isAlreadyRunning(): +                            print pid +                            exit(0) +                        else: +                            print "false" +                            exit(1) +                    elif option == "--clean": +                        self.cleanTree() +                        exit() +                    elif option == "--no-remote": +                        self.remote = False + +            except GetoptError: +                print 'Unknown Argument(s) "%s"' % " ".join(argv[1:]) +                self.print_help() +                exit() + +    def print_help(self): +        print "" +        print "pyLoad v%s     2008-2013 the pyLoad Team" % CURRENT_VERSION +        print "" +        if sys.argv[0].endswith(".py"): +            print "Usage: python pyload.py [options]" +        else: +            print "Usage: pyload [options]" +        print "" +        print "<Options>" +        print "  -v, --version", " " * 10, "Print version to terminal" +        print "  -c, --clear", " " * 12, "Delete all saved packages/links" +        #print "  -a, --add=<link/list>", " " * 2, "Add the specified links" +        print "  -u, --user", " " * 13, "Manages users" +        print "  -d, --debug", " " * 12, "Enable debug mode" +        print "  -s, --setup", " " * 12, "Run setup assistant" +        print "  --configdir=<dir>", " " * 6, "Run with <dir> as configuration directory" +        print "  -p, --pidfile=<file>", " " * 3, "Set pidfile to <file>" +        print "  --changedir", " " * 12, "Change configuration directory permanently" +        print "  --daemon", " " * 15, "Daemonize after startup" +        print "  --no-remote", " " * 12, "Disable remote access" +        print "  --status", " " * 15, "Display pid if running or False" +        print "  --clean", " " * 16, "Remove .pyc/.pyo files" +        print "  -q, --quit", " " * 13, "Quit a running pyLoad instance" +        print "  -h, --help", " " * 13, "Display this help screen" +        print "" + + +    def quit(self, a, b): +        self.shutdown() +        self.log.info(_("Received Quit signal")) +        _exit(1) + +    def writePidFile(self): +        self.deletePidFile() +        pid = os.getpid() +        f = open(self.pidfile, "wb") +        f.write(str(pid)) +        f.close() +        chmod(self.pidfile, 0660) + +    def deletePidFile(self): +        if self.checkPidFile(): +            self.log.debug("Deleting old pidfile %s" % self.pidfile) +            os.remove(self.pidfile) + +    def checkPidFile(self): +        """ return pid as int or 0""" +        if os.path.isfile(self.pidfile): +            f = open(self.pidfile, "rb") +            pid = f.read().strip() +            f.close() +            if pid: +                pid = int(pid) +                return pid + +        return 0 + +    def isAlreadyRunning(self): +        pid = self.checkPidFile() +        if not pid or os.name == "nt": return False +        try: +            os.kill(pid, 0)  # 0 - default signal (does nothing) +        except: +            return 0 + +        return pid + +    def quitInstance(self): +        if os.name == "nt": +            print "Not supported on windows." +            return + +        pid = self.isAlreadyRunning() +        if not pid: +            print "No pyLoad running." +            return + +        try: +            os.kill(pid, 3) #SIGUIT + +            t = time() +            print "waiting for pyLoad to quit" + +            while exists(self.pidfile) and t + 10 > time(): +                sleep(0.25) + +            if not exists(self.pidfile): +                print "pyLoad successfully stopped" +            else: +                os.kill(pid, 9) #SIGKILL +                print "pyLoad did not respond" +                print "Kill signal was send to process with id %s" % pid + +        except: +            print "Error quitting pyLoad" + + +    def cleanTree(self): +        for path, dirs, files in walk(self.path("")): +            for f in files: +                if not f.endswith(".pyo") and not f.endswith(".pyc"): +                    continue + +                if "_25" in f or "_26" in f or "_27" in f: +                    continue + +                print join(path, f) +                remove(join(path, f)) + +    def start(self, rpc=True, web=True, tests=False): +        """ starts the fun :D """ + +        self.version = CURRENT_VERSION + +        # TODO: Re-enable when its working again +        # TODO: Don't forget it +        if False and not exists("pyload.conf") and not tests: +            from Setup import Setup + +            print "This is your first start, running configuration assistant now." +            self.config = ConfigParser() +            s = Setup(pypath, self.config) +            res = False +            try: +                res = s.start() +            except SystemExit: +                pass +            except KeyboardInterrupt: +                print "\nSetup interrupted" +            except: +                res = False +                print_exc() +                print "Setup failed" +            if not res: +                remove("pyload.conf") + +            exit() + +        try: signal.signal(signal.SIGQUIT, self.quit) +        except: pass + +        self.config = ConfigParser() + +        gettext.setpaths([join(os.sep, "usr", "share", "pyload", "locale"), None]) +        translation = gettext.translation("pyLoad", self.path("locale"), +                                          languages=[self.config['general']['language'],"en"],fallback=True) +        translation.install(True) + +        # load again so translations are propagated +        self.config.loadDefault() + +        self.debug = self.doDebug or self.config['general']['debug_mode'] +        self.remote &= self.config['remote']['activated'] + +        pid = self.isAlreadyRunning() +        # don't exit when in test runner +        if pid and not tests: +            print _("pyLoad already running with pid %s") % pid +            exit() + +        if os.name != "nt" and self.config["general"]["renice"]: +            os.system("renice %d %d" % (self.config["general"]["renice"], os.getpid())) + +        if self.config["permission"]["change_group"]: +            if os.name != "nt": +                try: +                    from grp import getgrnam + +                    group = getgrnam(self.config["permission"]["group"]) +                    os.setgid(group[2]) +                except Exception, e: +                    print _("Failed changing group: %s") % e + +        if self.config["permission"]["change_user"]: +            if os.name != "nt": +                try: +                    from pwd import getpwnam + +                    user = getpwnam(self.config["permission"]["user"]) +                    os.setuid(user[2]) +                except Exception, e: +                    print _("Failed changing user: %s") % e + +        if self.debug: +            self.init_logger(logging.DEBUG) # logging level +        else: +            self.init_logger(logging.INFO) # logging level + +        self.do_kill = False +        self.do_restart = False +        self.shuttedDown = False + +        self.log.info(_("Starting") + " pyLoad %s" % CURRENT_VERSION) +        self.log.info(_("Using home directory: %s") % getcwd()) + +        if not tests: +            self.writePidFile() + +        self.captcha = True # checks seems to fail, although tesseract is available + +        self.eventManager = self.evm = EventManager(self) +        self.setupDB() + +        # Upgrade to configManager +        self.config = ConfigManager(self, self.config) + +        if self.deleteLinks: +            self.log.info(_("All links removed")) +            self.db.purgeLinks() + +        self.requestFactory = RequestFactory(self) +        __builtin__.pyreq = self.requestFactory + +        # deferred import, could improve start-up time +        from Api import Api +        from AddonManager import AddonManager +        from interaction.InteractionManager import InteractionManager +        from threads.ThreadManager import ThreadManager + +        Api.initComponents() +        self.api = Api(self) + +        self.scheduler = Scheduler(self) + +        #hell yeah, so many important managers :D +        self.pluginManager = PluginManager(self) +        self.interactionManager = self.im = InteractionManager(self) +        self.accountManager = AccountManager(self) +        self.threadManager = ThreadManager(self) +        self.addonManager = AddonManager(self) +        self.remoteManager = RemoteManager(self) + +        self.js = JsEngine() + +        # enough initialization for test cases +        if tests: return + +        self.log.info(_("Download time: %s") % self.api.isTimeDownload()) + +        if rpc: +            self.remoteManager.startBackends() + +        if web: +            self.init_webserver() + +        dl_folder = self.config["general"]["download_folder"] + +        if not exists(dl_folder): +            makedirs(dl_folder) + +        spaceLeft = free_space(dl_folder) + +        self.log.info(_("Free space: %s") % formatSize(spaceLeft)) + +        self.config.save() #save so config files gets filled + +        link_file = join(pypath, "links.txt") + +        if exists(link_file): +            f = open(link_file, "rb") +            if f.read().strip(): +                self.api.addPackage("links.txt", [link_file], 1) +            f.close() + +        link_file = "links.txt" +        if exists(link_file): +            f = open(link_file, "rb") +            if f.read().strip(): +                self.api.addPackage("links.txt", [link_file], 1) +            f.close() + +        #self.scheduler.addJob(0, self.accountManager.getAccountInfos) +        self.log.info(_("Activating Accounts...")) +        self.accountManager.refreshAllAccounts() + +        #restart failed +        if self.config["download"]["restart_failed"]: +            self.log.info(_("Restarting failed downloads...")) +            self.api.restartFailed() + +        self.threadManager.pause = False +        self.running = True + +        self.addonManager.activateAddons() + +        self.log.info(_("pyLoad is up and running")) +        self.eventManager.dispatchEvent("core:ready") + +        #test api +#        from pyload.common.APIExerciser import startApiExerciser +#        startApiExerciser(self, 3) + +        #some memory stats +#        from guppy import hpy +#        hp=hpy() +#        print hp.heap() +#        import objgraph +#        objgraph.show_most_common_types(limit=30) +#        import memdebug +#        memdebug.start(8002) +#        from meliae import scanner +#        scanner.dump_all_objects(self.path('objs.json')) + +        locals().clear() + +        while True: +            sleep(1.5) +            if self.do_restart: +                self.log.info(_("restarting pyLoad")) +                self.restart() +            if self.do_kill: +                self.shutdown() +                self.log.info(_("pyLoad quits")) +                self.removeLogger() +                _exit(0) +                # TODO check exits codes, clean exit is still blocked + +            self.threadManager.work() +            self.interactionManager.work() +            self.scheduler.work() + +    def setupDB(self): +        from database import DatabaseBackend +        from FileManager import FileManager + +        self.db = DatabaseBackend(self) # the backend +        self.db.setup() + +        self.files = FileManager(self) +        self.db.manager = self.files #ugly? + +    def init_webserver(self): +        if self.config['webinterface']['activated']: +            self.webserver = WebServer(self) +            self.webserver.start() + +    def init_logger(self, level): +        console = logging.StreamHandler(sys.stdout) + +        # try to get a time formatting depending on system locale +        tfrm = None +        try: # change current locale to default if it is not set +            current_locale = locale.getlocale() +            if current_locale == (None, None): +                current_locale = locale.setlocale(locale.LC_ALL, '') + +            # We use timeformat provided by locale when available +            if current_locale != (None, None): +                tfrm = locale.nl_langinfo(locale.D_FMT) + " " + locale.nl_langinfo(locale.T_FMT) +        except: # something did go wrong, locale is heavily platform dependant +            pass + +        # default formatting when no one was obtained +        if not tfrm: +            tfrm = "%d.%m.%Y %H:%M:%S" + +        frm = logging.Formatter("%(asctime)s %(levelname)-8s  %(message)s", tfrm) +        console.setFormatter(frm) +        self.log = logging.getLogger("log") # setable in config + +        if not exists(self.config['log']['log_folder']): +            makedirs(self.config['log']['log_folder'], 0700) + +        if self.config['log']['file_log']: +            if self.config['log']['log_rotate']: +                file_handler = logging.handlers.RotatingFileHandler(join(self.config['log']['log_folder'], 'log.txt'), +                                                                    maxBytes=self.config['log']['log_size'] * 1024, +                                                                    backupCount=int(self.config['log']['log_count']), +                                                                    encoding="utf8") +            else: +                file_handler = logging.FileHandler(join(self.config['log']['log_folder'], 'log.txt'), encoding="utf8") + +            file_handler.setFormatter(frm) +            self.log.addHandler(file_handler) + +        self.log.addHandler(console) #if console logging +        self.log.setLevel(level) + +    def removeLogger(self): +        for h in list(self.log.handlers): +            self.log.removeHandler(h) +            h.close() + + +    def restart(self): +        self.shutdown() +        chdir(owd) +        # close some open fds +        for i in range(3,50): +            try: +                close(i) +            except : +                pass + +        execl(executable, executable, *sys.argv) +        _exit(0) + +    def shutdown(self): +        self.log.info(_("shutting down...")) +        self.eventManager.dispatchEvent("coreShutdown") +        try: +            if self.config['webinterface']['activated'] and hasattr(self, "webserver"): +                pass # TODO: quit webserver? +#                self.webserver.quit() + +            for thread in self.threadManager.threads: +                thread.put("quit") + +            self.api.stopAllDownloads() +            self.addonManager.deactivateAddons() + +        except: +            self.print_exc() +            self.log.info(_("error while shutting down")) + +        finally: +            self.files.syncSave() +            self.db.shutdown() +            self.shuttedDown = True + +        self.deletePidFile() + +    def shell(self): +        """ stop and open an ipython shell inplace""" +        if self.debug: +            from IPython import embed +            sys.stdout = sys._stdout +            embed() + +    def breakpoint(self): +        if self.debug: +            from IPython.core.debugger import Pdb +            sys.stdout = sys._stdout +            if not self.pdb: self.pdb = Pdb() +            self.pdb.set_trace() + +    def print_exc(self): +        if self.debug: +            print_exc() + +    def path(self, *args): +        return join(pypath, *args) + + diff --git a/pyload/cli/Cli.py b/pyload/cli/Cli.py new file mode 100644 index 000000000..394a631c3 --- /dev/null +++ b/pyload/cli/Cli.py @@ -0,0 +1,586 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +#Copyright (C) 2012 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/>. +# +### +from __future__ import with_statement +from getopt import GetoptError, getopt + +import pyload.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 pyload import InitHomeDir +from pyload.cli.printer import * +from pyload.cli import AddPackage, ManageFiles + +from pyload.Api import Destination +from pyload.utils import formatSize, decode +from pyload.remote.thriftbackend.ThriftClient import ThriftClient, NoConnection, NoSSL, WrongLogin, ConnectionClosed +from pyload.lib.Getch import Getch +from pyload.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 <Package name> <link> <link2> ...") +                return + +            self.client.addPackage(args[0], args[1:], Destination.Queue, "") + +        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:], 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.pauseServer() + +        elif command == "unpause": +            self.client.unpauseServer() + +        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-2012 the pyLoad Team" +    print +    print "Usage: [python] pyLoadCli.py [options] [command]" +    print +    print "<Commands>" +    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 user name" +    print "  --pw=<password>", " " * 2, "Password" +    print "  -a, --address=", " " * 3, "Use address (current=%s)" % config["addr"] +    print "  -p, --port", " " * 7, "Use 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 text" +    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 <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")), +        ("restart_file <fid> <fid2>...", _("Restart files")), +        ("restart_package <pid> <pid2>...", _("Restart packages")), +        ("check <container|url> ...", _("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) diff --git a/module/plugins/container/DLC_25.pyc b/pyload/plugins/container/DLC_25.pyc Binary files differindex b8fde0051..b8fde0051 100644 --- a/module/plugins/container/DLC_25.pyc +++ b/pyload/plugins/container/DLC_25.pyc diff --git a/module/plugins/container/DLC_26.pyc b/pyload/plugins/container/DLC_26.pyc Binary files differindex 41a4e0cb8..41a4e0cb8 100644 --- a/module/plugins/container/DLC_26.pyc +++ b/pyload/plugins/container/DLC_26.pyc diff --git a/module/plugins/container/DLC_27.pyc b/pyload/plugins/container/DLC_27.pyc Binary files differindex a6bffaf74..a6bffaf74 100644 --- a/module/plugins/container/DLC_27.pyc +++ b/pyload/plugins/container/DLC_27.pyc  | 
