summaryrefslogtreecommitdiffstats
path: root/pyLoadCore.py
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2010-08-25 18:22:27 +0200
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2010-08-25 18:22:27 +0200
commit29f9dc8fb3396b03d732ebcbeb1cc8f00fe13897 (patch)
treef2a910cbea747a7b0c0a50d6c66691e54f5ef47f /pyLoadCore.py
parentmerged gui (diff)
downloadpyload-29f9dc8fb3396b03d732ebcbeb1cc8f00fe13897.tar.xz
new dirs
Diffstat (limited to 'pyLoadCore.py')
-rwxr-xr-xpyLoadCore.py681
1 files changed, 681 insertions, 0 deletions
diff --git a/pyLoadCore.py b/pyLoadCore.py
new file mode 100755
index 000000000..be6d40126
--- /dev/null
+++ b/pyLoadCore.py
@@ -0,0 +1,681 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+ 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/>.
+
+ @author: spoob
+ @author: sebnapi
+ @author: RaNaN
+ @author: mkaay
+ @version: v0.4.0
+"""
+CURRENT_VERSION = '0.4.1-dev'
+
+from getopt import GetoptError
+from getopt import getopt
+import gettext
+from imp import find_module
+import logging
+import logging.handlers
+from os import _exit
+from os import execv
+from os import getcwd
+from os import makedirs
+from os import name as platform
+from os import remove
+from os import sep
+from os.path import exists
+from os.path import join
+import signal
+import subprocess
+import sys
+from sys import argv
+from sys import executable
+from sys import exit
+from sys import stdout
+import thread
+import time
+from time import sleep
+from traceback import print_exc
+from xmlrpclib import Binary
+
+
+
+from module import InitHomeDir
+from module.AccountManager import AccountManager
+from module.CaptchaManager import CaptchaManager
+from module.ConfigParser import ConfigParser
+from module.FileDatabase import FileHandler
+from module.HookManager import HookManager
+from module.PluginManager import PluginManager
+from module.PullEvents import PullManager
+from module.RequestFactory import RequestFactory
+from module.ThreadManager import ThreadManager
+import module.remote.SecureXMLRPCServer as Server
+from module.web.ServerThread import WebServer
+from module.FileDatabase import PyFile
+
+
+class Core(object):
+ """ pyLoad Core """
+
+ def __init__(self):
+ self.doDebug = False
+ self.arg_links = []
+
+ if len(argv) > 1:
+ try:
+ options, args = getopt(argv[1:], 'vca:hdus', ["version", "clear", "add=", "help", "debug", "user", "setup", "configdir"])
+
+ for option, argument in options:
+ if option in ("-v", "--version"):
+ print "pyLoad", CURRENT_VERSION
+ exit()
+ elif option in ("-c", "--clear"):
+ try:
+ remove("files.db")
+ print "Removed Linklist"
+ except:
+ print "No Linklist found"
+ elif option in ("-a", "--add"):
+ #self.arg_links.append(argument)
+ #@TODO
+ print "Added %s" % argument
+ elif option in ("-h", "--help"):
+ self.print_help()
+ exit()
+ elif option in ("-d", "--debug"):
+ self.doDebug = True
+ elif option in ("-u", "--user"):
+ from module.setup import Setup
+ self.config = ConfigParser()
+ s = Setup(pypath, self.config)
+ s.set_user()
+ exit()
+ elif option in ("-s", "--setup"):
+ from module.setup import Setup
+ self.config = ConfigParser()
+ s = Setup(pypath, self.config)
+ s.start()
+ exit()
+ elif option == "--configdir":
+ from module.setup import Setup
+ self.config = ConfigParser()
+ s = Setup(pypath, self.config)
+ s.conf_path(True)
+ exit()
+ except GetoptError:
+ print 'Unknown Argument(s) "%s"' % " ".join(argv[1:])
+ self.print_help()
+ exit()
+
+ def print_help(self):
+ print ""
+ print "pyLoad %s Copyright (c) 2008-2010 the pyLoad Team" % CURRENT_VERSION
+ print ""
+ print "Usage: [python] pyLoadCore.py [options]"
+ print ""
+ print "<Options>"
+ print " -v, --version", " " * 10, "Print version to terminal"
+ print " -c, --clear", " " * 12, "Delete the saved linklist"
+ #print " -a, --add=<link/list>", " " * 2, "Add the specified links"
+ print " -u, --user", " " * 13, "Set new User and password"
+ print " -d, --debug", " " * 12, "Enable debug mode"
+ print " -s, --setup", " " * 12, "Run Setup Assistent"
+ print " --configdir", " " * 12, "Set new config directory"
+ print " -h, --help", " " * 13, "Display this help screen"
+ print ""
+
+ def toggle_pause(self):
+ if self.thread_list.pause:
+ self.thread_list.pause = False
+ return False
+ elif not self.thread_list.pause:
+ self.thread_list.pause = True
+ return True
+
+ def quit(self, a, b):
+ self.shutdown()
+ self.log.info(_("Received Quit signal"))
+ _exit(1)
+
+ def start(self):
+ """ starts the fun :D """
+
+ if not exists("pyload.conf"):
+ from module.setup import Setup
+ print "This is your first start, running configuration assistent now."
+ self.config = ConfigParser()
+ s = Setup(pypath, self.config)
+ try:
+ res = s.start()
+ 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()
+
+ translation = gettext.translation("pyLoad", self.path("locale"), languages=["en", self.config['general']['language']])
+ translation.install(unicode=(True if sys.getfilesystemencoding().lower().startswith("utf") else False))
+
+ self.debug = self.doDebug or self.config['general']['debug_mode']
+
+ self.check_file(self.config['log']['log_folder'], _("folder for logs"), True)
+
+ 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.log.info(_("Using home directory: %s") % getcwd())
+
+ #@TODO refractor
+
+ self.check_install("Crypto", _("pycrypto to decode container files"))
+ self.check_install("Image", _("Python Image Libary (PIL) for captcha reading"))
+ self.check_install("pycurl", _("pycurl to download any files"), True, True)
+ self.check_install("django", _("Django for webinterface"))
+ self.check_file("tmp", _("folder for temporary files"), True)
+ #self.check_install("tesseract", _("tesseract for captcha reading"), False)
+
+ self.check_file(self.config['general']['download_folder'], _("folder for downloads"), True)
+
+ if self.config['ssl']['activated']:
+ self.check_install("OpenSSL", _("OpenSSL for secure connection"), True)
+
+
+ self.downloadSpeedLimit = int(self.config.get("general", "download_speed_limit"))
+
+ self.requestFactory = RequestFactory(self)
+
+ #path.append(self.plugin_folder)
+
+ self.lastClientConnected = 0
+
+ self.server_methods = ServerMethods(self)
+
+ #hell yeah, so many important managers :D
+ self.files = FileHandler(self)
+ self.pluginManager = PluginManager(self)
+ self.pullManager = PullManager(self)
+ self.accountManager = AccountManager(self)
+ self.threadManager = ThreadManager(self)
+ self.captchaManager = CaptchaManager(self)
+ self.hookManager = HookManager(self)
+
+ self.log.info(_("Downloadtime: %s") % self.server_methods.is_time_download())
+
+ self.init_server()
+ self.init_webserver()
+
+ #linkFile = self.config['general']['link_file']
+
+ freeSpace = self.freeSpace()
+ if freeSpace > 5 * 1024:
+ self.log.info(_("Free space: %sGB") % (freeSpace / 1024))
+ else:
+ self.log.info(_("Free space: %sMB") % freeSpace)
+
+ self.threadManager.pause = False
+ #self.threadManager.start()
+
+ self.hookManager.coreReady()
+
+ self.config.save() #save so config files gets filled
+
+ while True:
+
+ sleep(2)
+ if self.do_restart:
+ self.log.info(_("restarting pyLoad"))
+ self.restart()
+ if self.do_kill:
+ self.shutdown()
+ self.log.info(_("pyLoad quits"))
+ exit()
+
+ self.threadManager.work()
+ self.hookManager.periodical()
+
+ def init_server(self):
+ try:
+ server_addr = (self.config['remote']['listenaddr'], int(self.config['remote']['port']))
+ usermap = {self.config.username: self.config.password}
+ if self.config['ssl']['activated']:
+ if exists(self.config['ssl']['cert']) and exists(self.config['ssl']['key']):
+ self.server = Server.SecureXMLRPCServer(server_addr, self.config['ssl']['cert'], self.config['ssl']['key'], usermap)
+ self.log.info(_("Secure XMLRPC Server Started"))
+ else:
+ self.log.warning(_("SSL Certificates not found, fallback to auth XMLRPC server"))
+ self.server = Server.AuthXMLRPCServer(server_addr, usermap)
+ self.log.info(_("Auth XMLRPC Server Started"))
+ else:
+ self.server = Server.AuthXMLRPCServer(server_addr, usermap)
+ self.log.info(_("Auth XMLRPC Server Started"))
+
+ self.server.register_instance(self.server_methods)
+
+ thread.start_new_thread(self.server.serve_forever, ())
+ except Exception, e:
+ self.log.error(_("Failed starting XMLRPC server CLI and GUI will not be available: %s") % str(e))
+ if self.debug:
+ print_exc()
+
+ def init_webserver(self):
+ if self.config['webinterface']['activated']:
+ self.webserver = WebServer(self)
+ self.webserver.start()
+
+ def init_logger(self, level):
+ console = logging.StreamHandler(stdout)
+ frm = logging.Formatter("%(asctime)s %(levelname)-8s %(message)s", "%d.%m.%Y %H:%M:%S")
+ console.setFormatter(frm)
+ self.log = logging.getLogger("log") # settable in config
+
+ if self.config['log']['file_log']:
+ file_handler = logging.handlers.RotatingFileHandler(join(self.config['log']['log_folder'], 'log.txt'), maxBytes=102400, backupCount=int(self.config['log']['log_count'])) #100 kib each
+ file_handler.setFormatter(frm)
+ self.log.addHandler(file_handler)
+
+ self.log.addHandler(console) #if console logging
+ self.log.setLevel(level)
+
+ def check_install(self, check_name, legend, python=True, essential=False):
+ """check wether needed tools are installed"""
+ try:
+ if python:
+ find_module(check_name)
+ else:
+ pipe = subprocess.PIPE
+ subprocess.Popen(check_name, stdout=pipe, stderr=pipe)
+ except:
+ self.log.info(_("Install %s") % legend)
+ if essential: exit()
+
+ def check_file(self, check_names, description="", folder=False, empty=True, essential=False, quiet=False):
+ """check wether needed files exists"""
+ tmp_names = []
+ if not type(check_names) == list:
+ tmp_names.append(check_names)
+ else:
+ tmp_names.extend(check_names)
+ file_created = True
+ file_exists = True
+ for tmp_name in tmp_names:
+ if not exists(tmp_name):
+ file_exists = False
+ if empty:
+ try:
+ if folder:
+ tmp_name = tmp_name.replace("/", sep)
+ makedirs(tmp_name)
+ else:
+ open(tmp_name, "w")
+ except:
+ file_created = False
+ else:
+ file_created = False
+ if not file_exists and not quiet:
+ if file_created:
+ #self.log.info( _("%s created") % description )
+ pass
+ else:
+ if not empty:
+ self.log.warning(_("could not find %s: %s") % (description, tmp_name))
+ else:
+ print _("could not create %s: %s") % (description, tmp_name)
+ if essential:
+ exit()
+
+ def isClientConnected(self):
+ return (self.lastClientConnected + 30) > time.time()
+
+ def restart(self):
+ self.shutdown()
+ execv(executable, [executable, "pyLoadCore.py"])
+
+ def compare_time(self, start, end):
+
+ start = map(int, start)
+ end = map(int, end)
+
+ if start == end: return True
+
+ now = list(time.localtime()[3:5])
+ if start < now and end > now: return True
+ elif start > end and (now > start or now < end): return True
+ elif start < now and end < now and start > end: return True
+ else: return False
+
+
+ def shutdown(self):
+ self.log.info(_("shutting down..."))
+ try:
+ if self.config['webinterface']['activated']:
+ self.webserver.quit()
+ #self.webserver.join()
+ for thread in self.threadManager.threads:
+ thread.put("quit")
+ pyfiles = self.files.cache.values()
+
+ for pyfile in pyfiles:
+ pyfile.abortDownload()
+
+ except:
+ if self.debug:
+ print_exc()
+ self.log.info(_("error while shutting down"))
+
+ finally:
+ self.files.syncSave()
+
+
+ def path(self, * args):
+ return join(pypath, * args)
+
+ def freeSpace(self):
+ folder = self.config['general']['download_folder']
+ if platform == 'nt':
+ import ctypes
+ free_bytes = ctypes.c_ulonglong(0)
+ ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(folder), None, None, ctypes.pointer(free_bytes))
+ return free_bytes.value / 1024 / 1024 #megabyte
+ else:
+ from os import statvfs
+ s = statvfs(folder)
+ return s.f_bsize * s.f_bavail / 1024 / 1024 #megabyte
+
+
+####################################
+ ########## XMLRPC Methods ##########
+ ####################################
+
+class ServerMethods():
+ """ methods that can be used by clients with xmlrpc connection"""
+ def __init__(self, core):
+ self.core = core
+
+ def status_downloads(self):
+ """ gives status about all files currently processed """
+ downloads = []
+ for pyfile in [x.active for x in self.core.threadManager.threads + self.core.threadManager.localThreads if x.active]:
+ if not isinstance(pyfile, PyFile):
+ continue
+ download = {}
+ download['id'] = pyfile.id
+ download['name'] = pyfile.name
+ download['speed'] = pyfile.getSpeed()
+ download['eta'] = pyfile.getETA()
+ download['format_eta'] = pyfile.formatETA()
+ download['kbleft'] = pyfile.getBytesLeft() #holded for backward comp.
+ download['bleft'] = pyfile.getBytesLeft()
+ download['size'] = pyfile.getSize()
+ download['format_size'] = pyfile.formatSize()
+ download['percent'] = pyfile.getPercent()
+ download['status'] = pyfile.status
+ download['statusmsg'] = pyfile.m.statusMsg[pyfile.status]
+ download['format_wait'] = pyfile.formatWait()
+ download['wait_until'] = pyfile.waitUntil
+ download['package'] = pyfile.package().name
+ downloads.append(download)
+ return downloads
+
+ def get_conf_val(self, cat, var, sec="core"):
+ """ get config value """
+ if sec == "core":
+ return self.core.config[cat][var]
+ elif sec == "plugin":
+ return self.core.config.getPlugin(cat, var)
+
+ def set_conf_val(self, cat, opt, val, sec="core"):
+ """ set config value """
+ if sec == "core":
+ self.core.config[str(cat)][str(opt)] = val
+ elif sec == "plugin":
+ self.core.config.setPlugin(cat, opt, val)
+
+ def get_config(self):
+ """ gets complete config """
+ return self.core.config.config
+
+ def get_plugin_config(self):
+ """ gets complete plugin config """
+ return self.core.config.plugin
+
+ def pause_server(self):
+ self.core.threadManager.pause = True
+
+ def unpause_server(self):
+ self.core.threadManager.pause = False
+
+ def toggle_pause(self):
+ if self.core.threadManager.pause:
+ self.core.threadManager.pause = False
+ else:
+ self.core.threadManager.pause = True
+ return self.core.threadManager.pause
+
+ def status_server(self):
+ """ dict with current server status """
+ status = {}
+ status['pause'] = self.core.threadManager.pause
+ status['activ'] = len(self.core.threadManager.processingIds())
+ status['queue'] = self.core.files.getFileCount()
+ status['total'] = self.core.files.getFileCount()
+ status['speed'] = 0
+
+ for pyfile in [x.active for x in self.core.threadManager.threads if x.active]:
+ status['speed'] += pyfile.getSpeed()
+
+ status['download'] = not self.core.threadManager.pause and self.is_time_download()
+ status['reconnect'] = self.core.config['reconnect']['activated'] and self.is_time_reconnect()
+
+ return status
+
+ def get_server_version(self):
+ return CURRENT_VERSION
+
+ def add_package(self, name, links, queue=0):
+ #0 is collector
+ if self.core.config['general']['folder_per_package']:
+ folder = name
+ else:
+ folder = ""
+
+ pid = self.core.files.addPackage(name, folder, queue)
+
+ self.core.files.addLinks(links, pid)
+
+ self.core.log.info(_("Added package %s containing %s links") % (name, len(links)))
+
+ self.core.files.save()
+
+ return pid
+
+
+ def get_package_data(self, id):
+ return self.core.files.getPackageData(int(id))
+
+ def get_file_data(self, id):
+ info = self.core.files.getFileData(int(id))
+ if not info:
+ return None
+ info = {str(info.keys()[0]): info[info.keys()[0]]}
+ return info
+
+ def del_links(self, ids):
+ for id in ids:
+ self.core.files.deleteLink(int(id))
+
+ self.core.files.save()
+
+ def del_packages(self, ids):
+
+ for id in ids:
+ self.core.files.deletePackage(int(id))
+
+ self.core.files.save()
+
+ def kill(self):
+ self.core.do_kill = True
+ return True
+
+ def restart(self):
+ self.core.do_restart = True
+
+ def get_queue(self):
+ return self.core.files.getCompleteData(1)
+
+ def get_collector(self):
+ return self.core.files.getCompleteData(0)
+
+ def add_files_to_package(self, pid, urls):
+ #@TODO implement
+ pass
+
+ def push_package_to_queue(self, id):
+ self.core.files.setPackageLocation(id, 1)
+
+ def restart_package(self, packid):
+ self.core.files.restartPackage(int(packid))
+
+ def restart_file(self, fileid):
+ self.core.files.restartFile(int(fileid))
+
+ def upload_container(self, filename, content):
+ th = open(join(self.core.config["general"]["download_folder"], "tmp_" + filename), "wb")
+ th.write(str(content))
+ th.close()
+
+ self.add_package(th.name, [th.name], 1)
+
+ def get_log(self, offset=0):
+ filename = join(self.core.config['log']['log_folder'], 'log.txt')
+ try:
+ fh = open(filename, "r")
+ lines = fh.readlines()
+ fh.close()
+ if offset >= len(lines):
+ return None
+ return lines[offset:]
+ except:
+ return ('No log available', )
+
+ def stop_downloads(self):
+ pyfiles = self.core.files.cache.values()
+
+ for pyfile in pyfiles:
+ pyfile.abortDownload()
+
+ def abort_files(self, fids):
+ pyfiles = self.core.files.cache.values()
+
+ for pyfile in pyfiles:
+ if pyfile.id in fids:
+ pyfile.abortDownload()
+
+ def stop_download(self, type, id):
+ if self.core.files.cache.has_key(id):
+ self.core.files.cache[id].abortDownload()
+
+
+ def set_package_name(self, pid, name):
+ pack = self.core.files.getPackage(pid)
+ pack.name = name
+ pack.sync()
+
+ def pull_out_package(self, pid):
+ """put package back to collector"""
+ self.core.files.setPackageLocation(pid, 0)
+
+ def is_captcha_waiting(self):
+ self.core.lastClientConnected = time.time()
+ task = self.core.captchaManager.getTask()
+ return not task == None
+
+ def get_captcha_task(self, exclusive=False):
+ self.core.lastClientConnected = time.time()
+ task = self.core.captchaManager.getTask()
+ if task:
+ task.setWatingForUser(exclusive=exclusive)
+ c = task.getCaptcha()
+ return str(task.getID()), Binary(c[0]), str(c[1])
+ else:
+ return None, None, None
+
+ def get_task_status(self, tid):
+ self.core.lastClientConnected = time.time()
+ return self.core.captchaManager.getTaskFromID(tid).getStatus()
+
+ def set_captcha_result(self, tid, result):
+ self.core.lastClientConnected = time.time()
+ task = self.core.captchaManager.getTaskFromID(tid)
+ if task:
+ task.setResult(result)
+ task.setDone()
+ return True
+ else:
+ return False
+
+ def get_events(self, uuid):
+ return self.core.pullManager.getEvents(uuid)
+
+ def get_accounts(self):
+ plugins = self.core.accountManager.getAccountPlugins()
+ data = {}
+ for p in plugins:
+ data[p.__name__] = p.getAllAccounts()
+ return data
+
+ def update_account(self, plugin, account, password, options=[]):
+ """ create and update account """
+ self.core.accountManager.updateAccount(plugin, account, password, options)
+
+ def remove_account(self, plugin, account):
+ self.core.accountManager.removeAccount(plugin, account)
+
+ def set_priority(self, id, priority):
+ p = self.core.files.getPackage(id)
+ p.setPriority(priority)
+
+ def is_time_download(self):
+ start = self.core.config['downloadTime']['start'].split(":")
+ end = self.core.config['downloadTime']['end'].split(":")
+ return self.core.compare_time(start, end)
+
+ def is_time_reconnect(self):
+ start = self.core.config['reconnect']['startTime'].split(":")
+ end = self.core.config['reconnect']['endTime'].split(":")
+ return self.core.compare_time(start, end)
+
+# And so it begins...
+if __name__ == "__main__":
+ pyload_core = Core()
+ try:
+ pyload_core.start()
+ except KeyboardInterrupt:
+ pyload_core.shutdown()
+ pyload_core.log.info(_("killed pyLoad from Terminal"))
+ _exit(1)