def add_rss(self, bot, update): try: component.get('Core').enable_plugin('YaRSS2') self.isRss = True return self.prepare_categoies(bot, update) except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def execute_commands(self, torrent_id, event): if event == "added" and not self.torrent_manager.session_started: return elif event == "removed": torrent_id, torrent_name, save_path = self.preremoved_cache.pop(torrent_id) else: torrent = component.get("TorrentManager").torrents[torrent_id] info = torrent.get_status(["name", "save_path"]) # getProcessOutputAndValue requires args to be str torrent_id = utf8_encoded(torrent_id) torrent_name = utf8_encoded(info["name"]) save_path = utf8_encoded(info["save_path"]) log.debug("[execute] Running commands for %s", event) def log_error(result, command): (stdout, stderr, exit_code) = result if exit_code: log.warn("[execute] command '%s' failed with exit code %d", command, exit_code) if stdout: log.warn("[execute] stdout: %s", stdout) if stderr: log.warn("[execute] stderr: %s", stderr) # Go through and execute all the commands for command in self.config["commands"]: if command[EXECUTE_EVENT] == event: command = os.path.expandvars(command[EXECUTE_COMMAND]) command = os.path.expanduser(command) if os.path.isfile(command) and os.access(command, os.X_OK): log.debug("[execute] Running %s", command) d = getProcessOutputAndValue(command, (torrent_id, torrent_name, save_path), env=os.environ) d.addCallback(log_error, command) else: log.error("[execute] Execute script not found or not executable")
def __init__(self, con_pool_size=1, proxy_url=None, urllib3_proxy_kwargs=None): try: if urllib3_proxy_kwargs is None: urllib3_proxy_kwargs = dict() # This was performed on Windows only, but it shouldn't be a problem # managing cacert.pem on Linux as well #if os.name == 'nt': try: import urllib2 import tempfile capath = os.path.join(tempfile.gettempdir(), 'tg-cacert.pem') # Check if tg-cacert.pem exists and if it's older than 7 days if not os.path.exists(capath) or (os.path.exists(capath) \ and (time.time() - os.path.getctime(capath)) // (24 * 3600) >= 7): CACERT_URL = "https://curl.haxx.se/ca/cacert.pem" request = urllib2.Request(CACERT_URL) file_contents = urllib2.urlopen(request).read() log.debug("## Telegramer downloaded "+os.path.realpath(capath)) cafile = open(os.path.realpath(capath), 'wb') cafile.write(file_contents) cafile.close() except: try: capath = certifi.where() except: capath = os.path.join(tempfile.gettempdir(), 'tg-cacert.pem') kwargs = dict( maxsize=con_pool_size, cert_reqs='CERT_REQUIRED', ca_certs=capath, #ca_certs=certifi.where(), socket_options=HTTPConnection.default_socket_options + [ (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), ]) # Set a proxy according to the following order: # * proxy defined in proxy_url (+ urllib3_proxy_kwargs) # * proxy set in `HTTPS_PROXY` env. var. # * proxy set in `https_proxy` env. var. # * None (if no proxy is configured) if not proxy_url: proxy_url = os.environ.get('HTTPS_PROXY') or os.environ.get('https_proxy') if not proxy_url: mgr = urllib3.PoolManager(**kwargs) else: kwargs.update(urllib3_proxy_kwargs) mgr = urllib3.proxy_from_url(proxy_url, **kwargs) if mgr.proxy.auth: # TODO: what about other auth types? auth_hdrs = urllib3.make_headers(proxy_basic_auth=mgr.proxy.auth) mgr.proxy_headers.update(auth_hdrs) self._con_pool = mgr except Exception as e: log.error(str(e) + '\n' + traceback.format_exc())
def start_daemon(self, port, config): """ Starts a daemon process. :param port: the port for the daemon to listen on :type port: int :param config: the path to the current config folder :type config: str :returns: True if started, False if not :rtype: bool :raises OSError: received from subprocess.call() """ try: if deluge.common.windows_check(): subprocess.Popen( ["deluged", "--port=%s" % port, "--config=%s" % config]) else: subprocess.call( ["deluged", "--port=%s" % port, "--config=%s" % config]) except OSError, e: from errno import ENOENT if e.errno == ENOENT: log.error( _("Deluge cannot find the 'deluged' executable, it is likely \ that you forgot to install the deluged package or it's not in your PATH.")) else: log.exception(e) raise e
def add_magnet(self, bot, update): if str(update.message.chat.id) in self.whitelist: try: user = update.message.chat.id log.debug("addmagnet of %s: %s" % (str(user), update.message.text)) try: #options = None metainfo = update.message.text """Adds a torrent with the given options. metainfo could either be base64 torrent data or a magnet link. Available options are listed in deluge.core.torrent.TorrentOptions. """ if self.opts is None: self.opts = {} if is_magnet(metainfo): log.debug( prelog() + 'Adding torrent from magnet URI `%s` using options `%s` ...', metainfo, self.opts) tid = self.core.add_torrent_magnet(metainfo, self.opts) self.apply_label(tid) else: update.message.reply_text( STRINGS['not_magnet'], reply_markup=ReplyKeyboardRemove()) except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc()) return ConversationHandler.END except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def __init__(self, options=None, args=None, classic=False): # Check for another running instance of the daemon if os.path.isfile(deluge.configmanager.get_config_dir("deluged.pid")): # Get the PID and the port of the supposedly running daemon try: (pid, port) = open(deluge.configmanager.get_config_dir("deluged.pid")).read().strip().split(";") pid = int(pid) port = int(port) except ValueError: pid = None port = None def process_running(pid): if deluge.common.windows_check(): # Do some fancy WMI junk to see if the PID exists in Windows from win32com.client import GetObject def get_proclist(): WMI = GetObject('winmgmts:') processes = WMI.InstancesOf('Win32_Process') return [process.Properties_('ProcessID').Value for process in processes] return pid in get_proclist() else: # We can just use os.kill on UNIX to test if the process is running try: os.kill(pid, 0) except OSError: return False else: return True if pid is not None and process_running(pid): # Ok, so a process is running with this PID, let's make doubly-sure # it's a deluged process by trying to open a socket to it's port. import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: s.connect(("127.0.0.1", port)) except socket.error: # Can't connect, so it must not be a deluged process.. pass else: # This is a deluged! s.close() raise deluge.error.DaemonRunningError("There is a deluge daemon running with this config directory!") # Initialize gettext try: locale.setlocale(locale.LC_ALL, '') if hasattr(locale, "bindtextdomain"): locale.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n")) if hasattr(locale, "textdomain"): locale.textdomain("deluge") gettext.bindtextdomain("deluge", pkg_resources.resource_filename("deluge", "i18n")) gettext.textdomain("deluge") gettext.install("deluge", pkg_resources.resource_filename("deluge", "i18n")) except Exception, e: log.error("Unable to initialize gettext/locale: %s", e) import __builtin__ __builtin__.__dict__["_"] = lambda x: x
def save_resume_data_file(self, resume_data=None): """ Saves the resume data file with the contents of self.resume_data. If `resume_data` is None, then we grab the resume_data from the file on disk, else, we update `resume_data` with self.resume_data and save that to disk. :param resume_data: the current resume_data, this will be loaded from disk if not provided :type resume_data: dict """ # Check to see if we're waiting on more resume data if self.num_resume_data or not self.resume_data: return filepath = os.path.join(get_config_dir(), "state", "torrents.fastresume") filepath_tmp = filepath + ".tmp" filepath_bak = filepath + ".bak" # First step is to load the existing file and update the dictionary if resume_data is None: resume_data = self.load_resume_data_file() resume_data.update(self.resume_data) self.resume_data = {} try: os.remove(filepath_bak) except OSError: pass try: log.debug("Creating backup of fastresume at: %s", filepath_bak) os.rename(filepath, filepath_bak) except OSError, ex: log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
def __init__(self, plugin_api, plugin_name): # Load the GtkUI portion of the plugin try: from webui import WebUI self.plugin = WebUI(plugin_api, plugin_name) except Exception, e: log.error("Failed to load PreventSuspend WebUI plugin: %s", e)
def enable(self): log.info("AutoTrackerEdit: started") self._edits = [] config_path = get_default_config_dir("autotrackeredit.json") try: with open(config_path) as f: items = json.load(f) for item in items: try: regex = re.compile(item['regex']) except re.error: log.info("AutoTrackerEdit: invalid regex %s" % item['regex']) else: self._edits.append((regex, item['repl'])) except IOError: log.error("AutoTrackerEdit: failed to open config file") log.info("AutoTrackerEdit: loaded %d regex from the config file", len(self._edits)) self._core = component.get("Core") self._em = component.get("EventManager") self._em.register_event_handler("TorrentAddedEvent", self._scan_torrent) self._em.register_event_handler("TorrentResumedEvent", self._scan_torrent) for id in self._core.get_session_state(): self._scan_torrent(id)
def _notify_email(self, subject='', message=''): log.debug("Email prepared") to_addrs = self.config['smtp_recipients'] to_addrs_str = ', '.join(self.config['smtp_recipients']) headers = """\ From: %(smtp_from)s To: %(smtp_recipients)s Subject: %(subject)s """ % {'smtp_from': self.config['smtp_from'], 'subject': subject, 'smtp_recipients': to_addrs_str, 'date': formatdate() } message = '\r\n'.join((headers + message).splitlines()) try: try: # Python 2.6 server = smtplib.SMTP(self.config["smtp_host"], self.config["smtp_port"], timeout=60) except: # Python 2.5 server = smtplib.SMTP(self.config["smtp_host"], self.config["smtp_port"]) except Exception, err: err_msg = _("There was an error sending the notification email:" " %s") % err log.error(err_msg) return err
def on_torrent_finished(self, torrent_id): """ Copy the torrent now. It will do this in a separate thread to avoid freezing up this thread (which causes freezes in the daemon and hence web/gtk UI.) """ torrent = component.get("TorrentManager").torrents[torrent_id] info = torrent.get_status([ "name", "save_path", "move_on_completed", "move_on_completed_path" ]) old_path = info["move_on_completed_path"] if info[ "move_on_completed"] else info["save_path"] new_path = self.config["copy_to"] files = torrent.get_files() umask = self.config["umask"] # validate parameters if new_path.strip() == "" or not os.path.isdir(new_path): log.error( "COPYCOMPLETED: No path to copy to was specified, or that path was invalid. Copy aborted." ) return log.info("COPYCOMPLETED: Copying %s from %s to %s" % (info["name"], old_path, new_path)) thread.start_new_thread(Core._thread_copy, (torrent_id, old_path, new_path, files, umask))
def delete_lockfile(): log.debug("Removing lockfile since it's stale.") try: os.remove(lockfile) os.remove(socket) except OSError, ex: log.error("Failed to delete lockfile: %s", ex)
def _notify_email(self, subject='', message=''): log.debug("Email prepared") to_addrs = self.config['smtp_recipients'] to_addrs_str = ', '.join(self.config['smtp_recipients']) headers = """\ From: %(smtp_from)s To: %(smtp_recipients)s Subject: %(subject)s """ % { 'smtp_from': self.config['smtp_from'], 'subject': subject, 'smtp_recipients': to_addrs_str, 'date': formatdate() } message = '\r\n'.join((headers + message).splitlines()) try: try: # Python 2.6 server = smtplib.SMTP(self.config["smtp_host"], self.config["smtp_port"], timeout=60) except: # Python 2.5 server = smtplib.SMTP(self.config["smtp_host"], self.config["smtp_port"]) except Exception, err: err_msg = _("There was an error sending the notification email:" " %s") % err log.error(err_msg) return err
def run_converter(self, input_range, output_version, func): """ Runs a function that will convert file versions in the `:param:input_range` to the `:param:output_version`. :param input_range: tuple, (int, int) the range of input versions this function will accept :param output_version: int, the version this function will return :param func: func, the function that will do the conversion, it will take the config dict as an argument and return the augmented dict :raises ValueError: if the output_version is less than the input_range """ if output_version in input_range or output_version <= max(input_range): raise ValueError( "output_version needs to be greater than input_range") if self.__version["file"] not in input_range: log.debug( "File version %s is not in input_range %s, ignoring converter function..", self.__version["file"], input_range) return try: self.__config = func(self.__config) except Exception, e: log.exception(e) log.error( "There was an exception try to convert config file %s %s to %s", self.__config_file, self.__version["file"], output_version) raise e
def run_converter(self, input_range, output_version, func): """ Runs a function that will convert file versions in the `:param:input_range` to the `:param:output_version`. :param input_range: tuple, (int, int) the range of input versions this function will accept :param output_version: int, the version this function will return :param func: func, the function that will do the conversion, it will take the config dict as an argument and return the augmented dict :raises ValueError: if the output_version is less than the input_range """ if output_version in input_range or output_version <= max(input_range): raise ValueError("output_version needs to be greater than input_range") if self.__version["file"] not in input_range: log.debug("File version %s is not in input_range %s, ignoring converter function..", self.__version["file"], input_range) return try: self.__config = func(self.__config) except Exception, e: log.exception(e) log.error("There was an exception try to convert config file %s %s to %s", self.__config_file, self.__version["file"], output_version) raise e
def add_torrent(self, bot, update): if str(update.message.chat.id) in self.whitelist: try: user = update.message.chat.id log.debug("addtorrent of %s: %s" % (str(user), update.message.document)) if update.message.document.mime_type == 'application/x-bittorrent': # Get file info file_info = self.bot.getFile(update.message.document.file_id) # Download file request = urllib2.Request(file_info.file_path, headers=HEADERS) status_code = urllib2.urlopen(request).getcode() if status_code == 200: file_contents = urllib2.urlopen(request).read() # Base64 encode file data metainfo = b64encode(file_contents) if self.opts is None: self.opts = {} log.info(prelog() + 'Adding torrent from base64 string' + 'using options `%s` ...', self.opts) tid = self.core.add_torrent_file(None, metainfo, self.opts) self.apply_label(tid) else: update.message.reply_text(STRINGS['download_fail'], reply_markup=ReplyKeyboardRemove()) else: update.message.reply_text(STRINGS['not_file'], reply_markup=ReplyKeyboardRemove()) return ConversationHandler.END except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def add( self, torrent_info=None, state=None, options=None, save_state=True, filedump=None, filename=None, magnet=None, resume_data=None, ): """Add a torrent to the manager and returns it's torrent_id""" if torrent_info is None and state is None and filedump is None and magnet is None: log.debug("You must specify a valid torrent_info, torrent state or magnet.") return log.debug("torrentmanager.add") add_torrent_params = {} if filedump is not None: try: torrent_info = lt.torrent_info(lt.bdecode(filedump)) except Exception, e: log.error("Unable to decode torrent file!: %s", e) # XXX: Probably should raise an exception here.. return
def add_magnet(self, bot, update): if str(update.message.chat.id) in self.whitelist: try: user = update.message.chat.id log.debug("addmagnet of %s: %s" % (str(user), update.message.text)) try: # options = None metainfo = update.message.text """Adds a torrent with the given options. metainfo could either be base64 torrent data or a magnet link. Available options are listed in deluge.core.torrent.TorrentOptions. """ if self.opts is None: self.opts = {} if is_magnet(metainfo): log.debug(prelog() + 'Adding torrent from magnet ' + 'URI `%s` using options `%s` ...', metainfo, self.opts) tid = self.core.add_torrent_magnet(metainfo, self.opts) self.apply_label(tid) else: update.message.reply_text(STRINGS['not_magnet'], reply_markup=ReplyKeyboardRemove()) except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc()) return ConversationHandler.END except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def torrent_type(self, bot, update): if str(update.message.chat.id) in self.whitelist: try: user = update.message.chat.id torrent_type_selected = update.message.text if torrent_type_selected == 'Magnet': update.message.reply_text(STRINGS['send_magnet'], reply_markup=ReplyKeyboardRemove()) return ADD_MAGNET elif torrent_type_selected == '.torrent': update.message.reply_text(STRINGS['send_file'], reply_markup=ReplyKeyboardRemove()) return ADD_TORRENT elif torrent_type_selected == 'URL': update.message.reply_text(STRINGS['send_url'], reply_markup=ReplyKeyboardRemove()) return ADD_URL else: update.message.reply_text(STRINGS['error'], reply_markup=ReplyKeyboardRemove()) return ConversationHandler.END except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def add(self, bot, update): # log.error(type(update.message.chat.id) + str(update.message.chat.id)) if str(update.message.chat.id) in self.whitelist: try: self.set_dirs = {} self.opts = {} keyboard_options = [] """Currently there are 3 possible categories so loop through cat1-3 and dir1-3, check if directories exist """ for i in range(3): i = i+1 if os.path.isdir(self.config['dir'+str(i)]): log.debug(prelog() + self.config['cat'+str(i)] + ' ' + self.config['dir'+str(i)]) self.set_dirs[self.config['cat'+str(i)]] = \ self.config['dir'+str(i)] if self.set_dirs: for k in self.set_dirs.keys(): log.debug(prelog() + k) keyboard_options.append([k]) keyboard_options.append([STRINGS['no_category']]) update.message.reply_text( '%s\n%s' % (STRINGS['which_cat'], STRINGS['cancel']), reply_markup=ReplyKeyboardMarkup(keyboard_options, one_time_keyboard=True)) return CATEGORY except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def save_stats(self): try: self.saved_stats.set("stats", self.stats) self.saved_stats.config.update(self.export_get_totals()) self.saved_stats.save() except Exception,e: log.error(e.message)
def on_extract(result, torrent_id, fpath, sonarr_radarr_support, extraction_count): # increment extraction_count complete extraction_count[1] += 1 # tmp logging log.debug( "EXTRACTOR: 1: extraction count total %d, complete %d", extraction_count[0], extraction_count[1]) # if sonarr_radarr_support is enabled and we have extracted all files if sonarr_radarr_support and extraction_count[ 0] == extraction_count[1]: log.info("EXTRACTOR: Setting is_finished to true: %s", tid_status["name"]) tid = component.get("TorrentManager").torrents[torrent_id] # set is_finished back to True tid.is_finished = True # Check command exit code. if not result[2]: log.info("EXTRACTOR: Extract successful: %s (%s)", fpath, torrent_id) else: log.error("EXTRACTOR: Extract failed: %s (%s) %s", fpath, torrent_id, result[1])
def add(self, torrent_info=None, state=None, options=None, save_state=True, filedump=None, filename=None, magnet=None, resume_data=None): """Add a torrent to the manager and returns it's torrent_id""" if torrent_info is None and state is None and filedump is None and magnet is None: log.debug( "You must specify a valid torrent_info, torrent state or magnet." ) return log.debug("torrentmanager.add") add_torrent_params = {} if filedump is not None: try: torrent_info = lt.torrent_info(lt.bdecode(filedump)) except Exception, e: log.error("Unable to decode torrent file!: %s", e) # XXX: Probably should raise an exception here.. return
def on_torrent_event(self, torrent_id, sqs_queue_name, msg_tpl): if self.config["aws_connect_to_region"].strip() == "": return if self.config["aws_access_key_id"].strip() == "": return if self.config["aws_secret_access_key"].strip() == "": return # setup sqs connection self.sqs_conn = boto.sqs.connect_to_region( self.config['aws_connect_to_region'], aws_access_key_id=self.config['aws_access_key_id'], aws_secret_access_key=self.config['aws_secret_access_key']) if (sqs_queue_name.strip() == ""): return try: msg_body = self.build_msg_body(torrent_id, msg_tpl) self.send_msg(sqs_queue_name, msg_body) except Exception, e: log.error("SQSNotify error %s" % e)
def get_localhost_auth(): """ Grabs the localclient auth line from the 'auth' file and creates a localhost uri :returns: with the username and password to login as :rtype: tuple """ auth_file = deluge.configmanager.get_config_dir("auth") if os.path.exists(auth_file): for line in open(auth_file): line = line.strip() if line.startswith("#") or not line: # This is a comment or blank line continue try: lsplit = line.split(":") except Exception, e: log.error("Your auth file is malformed: %s", e) continue if len(lsplit) == 2: username, password = lsplit elif len(lsplit) == 3: username, password, level = lsplit else: log.error("Your auth file is malformed: Incorrect number of fields!") continue if username == "localclient": return (username, password)
def on_apply_prefs(self): log.debug("Telegramer: applying prefs for Telegramer") config = { "telegram_notify_added": self.glade.get_widget("telegram_notify_added").get_active(), "telegram_notify_finished": self.glade.get_widget("telegram_notify_finished").get_active(), "telegram_token": self.glade.get_widget("telegram_token").get_text(), "telegram_user": self.glade.get_widget("telegram_user").get_text(), "telegram_users": self.glade.get_widget("telegram_users").get_text(), "telegram_users_notify": self.glade.get_widget("telegram_users_notify").get_text(), "categories": {self.glade.get_widget("cat1").get_text(): self.glade.get_widget("dir1").get_text(), self.glade.get_widget("cat2").get_text(): self.glade.get_widget("dir2").get_text(), self.glade.get_widget("cat3").get_text(): self.glade.get_widget("dir3").get_text() }, "regex_exp": {self.glade.get_widget("rname1").get_text(): self.glade.get_widget("reg1").get_text(), self.glade.get_widget("rname2").get_text(): self.glade.get_widget("reg2").get_text(), self.glade.get_widget("rname3").get_text(): self.glade.get_widget("reg3").get_text() }, "proxy_url": self.glade.get_widget("proxy_url").get_text(), "urllib3_proxy_kwargs_username": self.glade.get_widget("urllib3_proxy_kwargs_username").get_text(), "urllib3_proxy_kwargs_password": self.glade.get_widget("urllib3_proxy_kwargs_password").get_text() } #log.error(config) client.telegramer.set_config(config) for ind, (n, r) in enumerate(config["regex_exp"].items()): if REGEX_TMPL_FILE_NAME not in r: log.error("Your regex " + n + "template doesn't contains " + REGEX_TMPL_FILE_NAME + " string and wouldn't work") break
def telegram_poll_stop(self): try: log.debug(prelog() + 'Stop polling') if self.updater: self.updater.stop() except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def enable_plugin(self, plugin_name): """Enables a plugin""" if plugin_name not in self.available_plugins: log.warning("Cannot enable non-existant plugin %s", plugin_name) return if plugin_name in self.plugins: log.warning("Cannot enable already enabled plugin %s", plugin_name) return plugin_name = plugin_name.replace(" ", "-") egg = self.pkg_env[plugin_name][0] egg.activate() for name in egg.get_entry_map(self.entry_name): entry_point = egg.get_entry_info(self.entry_name, name) try: cls = entry_point.load() instance = cls(plugin_name.replace("-", "_")) except Exception, e: log.error("Unable to instantiate plugin!") log.exception(e) continue instance.enable() if self._component_state == "Started": component.start([instance.plugin._component_name]) plugin_name = plugin_name.replace("-", " ") self.plugins[plugin_name] = instance if plugin_name not in self.config["enabled_plugins"]: log.debug("Adding %s to enabled_plugins list in config", plugin_name) self.config["enabled_plugins"].append(plugin_name) log.info("Plugin %s enabled..", plugin_name)
def save_stats(self): try: self.saved_stats["stats"] = self.stats self.saved_stats.config.update(self.get_totals()) self.saved_stats.save() except Exception, e: log.error("Stats save error", e)
def load_libs(): egg = pkg_resources.require("Telegramer")[0] for name in egg.get_entry_map("telegramer.libpaths"): ep = egg.get_entry_info("telegramer.libpaths", name) location = "%s/%s" % (egg.location, ep.module_name.replace(".", "/")) sys.path.append(location) log.error("Appending to sys.path: '%s'" % location)
def email(self, status): """sends email notification of finished torrent""" import smtplib headers = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n" % ( self.config["ntf_email_add"], self.config["ntf_email_add"], "Finished torrent %s" % (status["name"])) text = _( "This email is to inform you that Deluge has finished downloading %(name)s , \ which includes %(num_files)i files.\nTo stop receiving these alerts, simply turn off \ email notification in Deluge's preferences.\n\nThank you,\nDeluge" ) % { "name": status["name"], "num_files": status["num_files"] } message = headers + text if self.config["ntf_security"] == 'SSL': port = 465 elif self.config["ntf_security"] == 'TLS': port = 587 elif self.config["ntf_security"] == None: port = 25 try: mailServer = smtplib.SMTP(self.config["ntf_server"], port) except Exception, e: log.error("There was an error sending the notification email: %s", e) return
def get_default_config_dir(filename=None): """ :param filename: if None, only the config path is returned, if provided, a path including the filename will be returned :type filename: string :returns: a file path to the config directory and optional filename :rtype: string """ if windows_check(): appDataPath = os.environ.get("APPDATA") if not appDataPath: import _winreg hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") appDataReg = _winreg.QueryValueEx(hkey, "AppData") appDataPath = appDataReg[0] _winreg.CloseKey(hkey) if filename: return os.path.join(appDataPath, "deluge", filename) else: return os.path.join(appDataPath, "deluge") else: from xdg.BaseDirectory import save_config_path try: if filename: return os.path.join(save_config_path("deluge"), filename) else: return save_config_path("deluge") except OSError, e: log.error("Unable to use default config directory, exiting... (%s)", e) sys.exit(1)
def add(self, bot, update): # log.error(type(update.message.chat.id) + str(update.message.chat.id)) if str(update.message.chat.id) in self.whitelist: try: self.set_dirs = {} self.opts = {} keyboard_options = [] """Currently there are 3 possible categories so loop through cat1-3 and dir1-3, check if directories exist """ for i in range(3): i = i + 1 if os.path.isdir(self.config['dir' + str(i)]): log.debug(prelog() + self.config['cat' + str(i)] + ' ' + self.config['dir' + str(i)]) self.set_dirs[self.config['cat'+str(i)]] = \ self.config['dir'+str(i)] if self.set_dirs: for k in self.set_dirs.keys(): log.debug(prelog() + k) keyboard_options.append([k]) keyboard_options.append([STRINGS['no_category']]) update.message.reply_text( '%s\n%s' % (STRINGS['which_cat'], STRINGS['cancel']), reply_markup=ReplyKeyboardMarkup(keyboard_options, one_time_keyboard=True)) return CATEGORY except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def _shutdown(self, *args, **kwargs): if os.path.exists(deluge.configmanager.get_config_dir("deluged.pid")): try: os.remove(deluge.configmanager.get_config_dir("deluged.pid")) except Exception, e: log.exception(e) log.error("Error removing deluged.pid!")
def load_limits(self): log.debug("TrafficLimits: Loading limits...") try: limits = open(deluge.configmanager.get_config_dir("trafficlimits")) limits_mtime = os.fstat(limits.fileno()).st_mtime label = limits.readline().rstrip(os.linesep) maximum_upload = int(limits.readline().rstrip(os.linesep)) maximum_download = int(limits.readline().rstrip(os.linesep)) line = limits.readline().rstrip(os.linesep) maximum_total = -1 if line == '' else int(line) except (IOError, OSError, ValueError) as error: log.error("TrafficLimits: " + deluge.configmanager.get_config_dir("trafficlimits") + ": " + str(error)) return self.limits_mtime = limits_mtime self.label = label self.config["maximum_upload"] = maximum_upload self.config["maximum_download"] = maximum_download self.config["maximum_total"] = maximum_total if self.label != self.config["label"]: self.config["label"] = self.label self.reset_initial() if self.paused: self.paused = False component.get("Core").session.resume() log.debug("TrafficLimits: Loaded limits.")
def associate_magnet_links(overwrite=False): """ Associates magnet links to Deluge. :param overwrite: if this is True, the current setting will be overwritten :type overwrite: bool :returns: True if association was set :rtype: bool """ if not deluge.common.windows_check(): # gconf method is only available in a GNOME environment try: import gconf except ImportError: log.debug("gconf not available, so will not attempt to register magnet uri handler") return False else: key = "/desktop/gnome/url-handlers/magnet/command" gconf_client = gconf.client_get_default() if (gconf_client.get(key) and overwrite) or not gconf_client.get(key): # We are either going to overwrite the key, or do it if it hasn't been set yet if gconf_client.set_string(key, "deluge '%s'"): gconf_client.set_bool("/desktop/gnome/url-handlers/magnet/needs_terminal", False) gconf_client.set_bool("/desktop/gnome/url-handlers/magnet/enabled", True) log.info("Deluge registered as default magnet uri handler!") return True else: log.error("Unable to register Deluge as default magnet uri handler.") return False return False
def enable(self): log.debug("[AutoShutDown] Enabling plugin...") if osx_check(): log.error("[AutoShutDown] OSX not currently supported") #Using subprocess could call osascript #subprocess.call(['osascript', '-e', 'tell app "System Events" to shut down']) self.disable() if not windows_check(): try: bus = dbus.SystemBus() try: self.bus_name = LOGIN1 self.bus_obj = bus.get_object(self.bus_name, LOGIN1_PATH) self.bus_iface = dbus.Interface(self.bus_obj, self.bus_name + '.Manager') except DBusException: self.bus_name = UPOWER self.bus_obj = bus.get_object(self.bus_name, UPOWER_PATH) self.bus_iface = dbus.Interface(self.bus_obj, self.bus_name) except: log.debug( "[AutoShutDown] Fallback to older dbus PowerManagement") bus = dbus.Bus(dbus.Bus.TYPE_SESSION) self.bus_name = POWERMAN self.bus_obj = bus.get_object(self.bus_name, POWERMAN_PATH) self.bus_iface = dbus.Interface(self.bus_obj, self.bus_name) self.config = deluge.configmanager.ConfigManager( "autoshutdown.conf", DEFAULT_PREFS) self.check_suspend_hibernate_flags() component.get("EventManager").register_event_handler( "TorrentFinishedEvent", self.on_event_torrent_finished)
def torrent_type(self, bot, update): if str(update.message.chat.id) in self.whitelist: try: user = update.message.chat.id torrent_type_selected = update.message.text if torrent_type_selected == 'Magnet': update.message.reply_text( STRINGS['send_magnet'], reply_markup=ReplyKeyboardRemove()) return ADD_MAGNET elif torrent_type_selected == '.torrent': update.message.reply_text( STRINGS['send_file'], reply_markup=ReplyKeyboardRemove()) return ADD_TORRENT elif torrent_type_selected == 'URL': update.message.reply_text( STRINGS['send_url'], reply_markup=ReplyKeyboardRemove()) return ADD_URL else: update.message.reply_text( STRINGS['error'], reply_markup=ReplyKeyboardRemove()) return ConversationHandler.END except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def start_daemon(self, port, config): """ Starts a daemon process. :param port: the port for the daemon to listen on :type port: int :param config: the path to the current config folder :type config: str :returns: True if started, False if not :rtype: bool :raises OSError: received from subprocess.call() """ try: if deluge.common.windows_check(): subprocess.Popen(["deluged", "--port=%s" % port, "--config=%s" % config]) else: subprocess.call(["deluged", "--port=%s" % port, "--config=%s" % config]) except OSError, e: from errno import ENOENT if e.errno == ENOENT: log.error(_("Deluge cannot find the 'deluged' executable, it is likely \ that you forgot to install the deluged package or it's not in your PATH.")) else: log.exception(e) raise e
def get_localhost_auth(): """ Grabs the localclient auth line from the 'auth' file and creates a localhost uri :returns: with the username and password to login as :rtype: tuple """ auth_file = deluge.configmanager.get_config_dir("auth") if os.path.exists(auth_file): for line in open(auth_file): if line.startswith("#"): # This is a comment line continue line = line.strip() try: lsplit = line.split(":") except Exception, e: log.error("Your auth file is malformed: %s", e) continue if len(lsplit) == 2: username, password = lsplit elif len(lsplit) == 3: username, password, level = lsplit else: log.error("Your auth file is malformed: Incorrect number of fields!") continue if username == "localclient": return (username, password)
def enable(self): log.debug("[AutoShutDown] Enabling plugin...") if osx_check(): log.error("[AutoShutDown] OSX not currently supported") #Using subprocess could call osascript #subprocess.call(['osascript', '-e', 'tell app "System Events" to shut down']) self.disable() if not windows_check(): self.bus_name = UPOWER bus_path = UPOWER_PATH try: bus = dbus.SystemBus() self.bus_obj = bus.get_object(self.bus_name, bus_path) except: log.debug("[AutoShutDown] Fallback to older dbus PowerManagement") self.bus_name = POWERMAN bus_path = POWERMAN_PATH bus = dbus.Bus(dbus.Bus.TYPE_SESSION) self.bus_obj = bus.get_object(self.bus_name, bus_path) self.bus_iface = dbus.Interface(self.bus_obj, self.bus_name) self.bus_iface_props = dbus.Interface(self.bus_obj, 'org.freedesktop.DBus.Properties') self.config = deluge.configmanager.ConfigManager("autoshutdown.conf", DEFAULT_PREFS) self.check_suspend_hibernate_flags() component.get("EventManager").register_event_handler("TorrentFinishedEvent", self.on_event_torrent_finished)
def disable(self): try: log.info(prelog() + 'Disable') reactor.callLater(2, self.disconnect_events) self.whitelist = [] self.telegram_poll_stop() # self.bot = None except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def adjust_windows_shutdown_privileges(self): if not windows_check(): log.error("Only usable on Windows platform") return flags = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY htoken = OpenProcessToken(GetCurrentProcess(), flags) id = LookupPrivilegeValue(None, SE_SHUTDOWN_NAME) newPrivileges = [(id, SE_PRIVILEGE_ENABLED)] AdjustTokenPrivileges(htoken, 0, newPrivileges)
def process_args(args): """Process arguments sent to already running Deluge""" # Make sure args is a list args = list(args) log.debug("Processing args from other process: %s", args) if not client.connected(): # We're not connected so add these to the queue log.debug("Not connected to host.. Adding to queue.") component.get("QueuedTorrents").add_to_queue(args) return config = ConfigManager("gtkui.conf") for arg in args: if not arg.strip(): continue log.debug("arg: %s", arg) if deluge.common.is_url(arg): log.debug("Attempting to add url (%s) from external source...", arg) if config["interactive_add"]: component.get("AddTorrentDialog").add_from_url(arg) component.get("AddTorrentDialog").show( config["focus_add_dialog"]) else: client.core.add_torrent_url(arg, None) elif deluge.common.is_magnet(arg): log.debug("Attempting to add magnet (%s) from external source...", arg) if config["interactive_add"]: component.get("AddTorrentDialog").add_from_magnets([arg]) component.get("AddTorrentDialog").show( config["focus_add_dialog"]) else: client.core.add_torrent_magnet(arg, {}) else: log.debug("Attempting to add file (%s) from external source...", arg) if urlparse(arg).scheme == "file": arg = url2pathname(urlparse(arg).path) path = os.path.abspath(deluge.common.decode_string(arg)) if not os.path.exists(path): log.error("No such file: %s", path) continue if config["interactive_add"]: component.get("AddTorrentDialog").add_from_files([path]) component.get("AddTorrentDialog").show( config["focus_add_dialog"]) else: with open(path, "rb") as _file: filedump = base64.encodestring(_file.read()) client.core.add_torrent_file( os.path.split(path)[-1], filedump, None)
def _on_torrent_finished(self, torrent_id): """ This is called when a torrent finishes and checks if any files to extract. """ tid = component.get("TorrentManager").torrents[torrent_id] tid_status = tid.get_status(["save_path", "name"]) files = tid.get_files() for f in files: file_root, file_ext = os.path.splitext(f["path"]) file_ext_sec = os.path.splitext(file_root)[1] if file_ext_sec and file_ext_sec + file_ext in EXTRACT_COMMANDS: file_ext = file_ext_sec + file_ext elif file_ext not in EXTRACT_COMMANDS or file_ext_sec == '.tar': log.warning( "EXTRACTOR: Can't extract file with unknown file type: %s" % f["path"]) continue cmd = EXTRACT_COMMANDS[file_ext] # Now that we have the cmd, lets run it to extract the files fpath = os.path.join(tid_status["save_path"], os.path.normpath(f["path"])) # Get the destination path dest = os.path.normpath(self.config["extract_path"]) if self.config["use_name_folder"]: name = tid_status["name"] dest = os.path.join(dest, name) # Create the destination folder if it doesn't exist if not os.path.exists(dest): try: os.makedirs(dest) except Exception, e: log.error( "EXTRACTOR: Error creating destination folder: %s", e) return def on_extract_success(result, torrent_id, fpath): # XXX: Emit an event log.info("EXTRACTOR: Extract successful: %s (%s)", fpath, torrent_id) def on_extract_failed(result, torrent_id, fpath): # XXX: Emit an event log.error("EXTRACTOR: Extract failed: %s (%s)", fpath, torrent_id) # Run the command and add some callbacks log.debug("EXTRACTOR: Extracting %s with %s %s to %s", fpath, cmd[0], cmd[1], dest) d = getProcessValue(cmd[0], cmd[1].split() + [str(fpath)], {}, str(dest)) d.addCallback(on_extract_success, torrent_id, fpath) d.addErrback(on_extract_failed, torrent_id, fpath)
def on_connect_fail(result, try_counter): log.error("Connection to host failed..") # We failed connecting to the daemon, but lets try again if try_counter: log.info("Retrying connection.. Retries left: %s", try_counter) try_counter -= 1 import time time.sleep(0.5) do_retry_connect(try_counter) return result
def save_state(self): """Save the state of the TorrentManager to the torrents.state file""" state = TorrentManagerState() # Create the state for each Torrent and append to the list for torrent in self.torrents.values(): if self.session.is_paused(): paused = torrent.handle.is_paused() elif torrent.forced_error: paused = torrent.forced_error.was_paused elif torrent.state == "Paused": paused = True else: paused = False torrent_state = TorrentState( torrent.torrent_id, torrent.filename, torrent.get_status(["total_uploaded"])["total_uploaded"], torrent.trackers, torrent.options["compact_allocation"], paused, torrent.options["download_location"], torrent.options["max_connections"], torrent.options["max_upload_slots"], torrent.options["max_upload_speed"], torrent.options["max_download_speed"], torrent.options["prioritize_first_last_pieces"], torrent.options["file_priorities"], torrent.get_queue_position(), torrent.options["auto_managed"], torrent.is_finished, torrent.options["stop_ratio"], torrent.options["stop_at_ratio"], torrent.options["remove_at_ratio"], torrent.options["move_completed"], torrent.options["move_completed_path"], torrent.magnet, torrent.time_added, ) state.torrents.append(torrent_state) # Pickle the TorrentManagerState object filepath = os.path.join(get_config_dir(), "state", "torrents.state") filepath_tmp = filepath + ".tmp" filepath_bak = filepath + ".bak" try: os.remove(filepath_bak) except OSError: pass try: log.debug("Creating backup of state at: %s", filepath_bak) os.rename(filepath, filepath_bak) except OSError, ex: log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
def enable(self): self.config = deluge.configmanager.ConfigManager("copycompleted.conf", DEFAULT_PREFS) # validate settings here as an aid to user # don't act differently, as this won't be called again if settings are # changed during the session. if self.config["copy_to"].strip() == "" or not os.path.isdir(self.config["copy_to"]): log.error("COPYCOMPLETED: No path to copy to was specified, or that path was invalid. Please amend.") # Get notified when a torrent finishes downloading component.get("EventManager").register_event_handler("TorrentFinishedEvent", self.on_torrent_finished)