def show_move_storage_dialog(self, status): log.debug("show_move_storage_dialog") glade = gtk.glade.XML(pkg_resources.resource_filename( "deluge.ui.gtkui", "glade/move_storage_dialog.glade" )) # Keep it referenced: # https://bugzilla.gnome.org/show_bug.cgi?id=546802 self.move_storage_dialog = glade.get_widget("move_storage_dialog") self.move_storage_dialog.set_transient_for(self.window.window) self.move_storage_dialog_entry = glade.get_widget("entry_destination") self.move_storage_dialog_entry.set_text(status["save_path"]) def on_dialog_response_event(widget, response_id): def on_core_result(result): # Delete references del self.move_storage_dialog del self.move_storage_dialog_entry if response_id == gtk.RESPONSE_OK: log.debug("Moving torrents to %s", self.move_storage_dialog_entry.get_text()) path = self.move_storage_dialog_entry.get_text() client.core.move_storage( component.get("TorrentView").get_selected_torrents(), path ).addCallback(on_core_result) self.move_storage_dialog.hide() self.move_storage_dialog.connect("response", on_dialog_response_event) self.move_storage_dialog.show()
def run_on_show_prefs(self): """This hook is run before the user is shown the preferences dialog. It is designed so that plugins can update their preference page with the config.""" log.debug("run_on_show_prefs") for function in self.hooks["on_show_prefs"]: function()
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 get_tab_label(self): parent = self._tab_label.get_parent() log.debug("parent: %s", parent) if parent is not None: parent.remove(self._tab_label) return self._tab_label
def wrapper(obj, dest): id = str(obj.handle.info_hash()) log.debug("[%s] (Wrapped) Move storage on: %s", PLUGIN_NAME, id) status = self.status.get(id, None) if status == "Moving": log.debug("[%s] Unable to move torrent: already moving", PLUGIN_NAME) return False self._cancel_deferred(id) old_path = obj.get_status(["save_path"])["save_path"] if old_path == dest: self.status[id] = "%s: %s" % ("Error", "Same path") self._clear_move_status(id, self.timeout["error"]) return False _orig_move_storage = self.orig_move_storage result = _orig_move_storage(obj, dest) if result: self.status[id] = "Moving" self.progress[id] = Progress(obj, old_path, dest) if self.general["remove_empty"]: self.paths[id] = old_path else: self.status[id] = "%s: %s" % ("Error", "General failure") self._clear_move_status(id, self.timeout["error"]) return result
def on_menuitem_edittrackers_activate(self, data=None): log.debug("on_menuitem_edittrackers_activate") from edittrackersdialog import EditTrackersDialog dialog = EditTrackersDialog( component.get("TorrentView").get_selected_torrent(), component.get("MainWindow").window) dialog.run()
def force_reannounce(self): """Force a tracker reannounce""" try: self.handle.force_reannounce() except Exception, e: log.debug("Unable to force reannounce: %s", e) return False
def resume(self): """Resumes this torrent""" if self.handle.is_paused() and self.handle.is_auto_managed(): log.debug("Torrent is being auto-managed, cannot resume!") elif self.forced_error and self.forced_error.was_paused: log.debug("Skip resuming Error state torrent that was originally paused.") else: # Reset the status message just in case of resuming an Error'd torrent self.set_status_message("OK") if self.handle.is_finished(): # If the torrent has already reached it's 'stop_seed_ratio' then do not do anything if self.options["stop_at_ratio"]: if self.get_ratio() >= self.options["stop_ratio"]: #XXX: This should just be returned in the RPC Response, no event #self.signals.emit_event("torrent_resume_at_stop_ratio") return if self.options["auto_managed"]: # This torrent is to be auto-managed by lt queueing self.handle.auto_managed(True) try: self.handle.resume() except: pass return True if self.forced_error and not self.forced_error.restart_to_resume: self.clear_forced_error_state() elif self.state == "Error" and not self.forced_error: self.handle.clear_error()
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 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 set_config(self, config): """Sets the config dictionary""" log.debug('seedtime %r' % config) log.debug('component state %r, component timer %r' % (self._component_state, self._component_timer)) for key in config.keys(): self.config[key] = config[key] self.config.save()
def check_new_release(self): if self.new_release: log.debug("new_release: %s", self.new_release) if deluge.common.VersionSplit(self.new_release) > deluge.common.VersionSplit(deluge.common.get_version()): component.get("EventManager").emit(NewVersionAvailableEvent(self.new_release)) return self.new_release return False
def post_torrent_add(self, torrent_id): if not self.torrent_manager.session_started: return log.debug("seedtime post_torrent_add") if self.config["apply_stop_time"]: log.debug('applying stop.... time %r' % self.config['default_stop_time']) self.set_torrent(torrent_id, self.config["default_stop_time"])
def on_drag_data_received_event(self, widget, drag_context, x, y, selection_data, info, timestamp): log.debug("Selection(s) dropped on main window %s", selection_data.data) if selection_data.get_uris(): process_args(selection_data.get_uris()) else: process_args(selection_data.data.split()) drag_context.finish(True, True)
def run_on_apply_prefs(self): """This hook is run after the user clicks Apply or OK in the preferences dialog. """ log.debug("run_on_apply_prefs") for function in self.hooks["on_apply_prefs"]: function()
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 path = os.path.join(get_config_dir(), "state", "torrents.fastresume") # 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: log.debug("Saving fastresume file: %s", path) fastresume_file = open(path, "wb") fastresume_file.write(lt.bencode(resume_data)) fastresume_file.flush() os.fsync(fastresume_file.fileno()) fastresume_file.close() except IOError: log.warning("Error trying to save fastresume file")
def on_alert_file_error(self, alert): log.debug("on_alert_file_error: %s", decode_string(alert.message())) try: torrent = self.torrents[str(alert.handle.info_hash())] except: return torrent.update_state()
def get_selected_torrents(self): """Returns a list of selected torrents or None""" torrent_ids = [] try: paths = self.treeview.get_selection().get_selected_rows()[1] except AttributeError: # paths is likely None .. so lets return [] return [] try: for path in paths: try: row = self.treeview.get_model().get_iter(path) except Exception, e: log.debug("Unable to get iter from path: %s", e) continue child_row = self.treeview.get_model().convert_iter_to_child_iter(None, row) child_row = self.treeview.get_model().get_model().convert_iter_to_child_iter(child_row) if self.liststore.iter_is_valid(child_row): try: value = self.liststore.get_value(child_row, self.columns["torrent_id"].column_indices[0]) except Exception, e: log.debug("Unable to get value from row: %s", e) else: torrent_ids.append(value)
def on_alert_metadata_received(self, alert): log.debug("on_alert_metadata_received") try: torrent = self.torrents[str(alert.handle.info_hash())] except: return torrent.on_metadata_received()
def scrape_tracker(self): """Scrape the tracker""" try: self.handle.scrape_tracker() except Exception, e: log.debug("Unable to scrape tracker: %s", e) return False
def on_alert_file_renamed(self, alert): log.debug("on_alert_file_renamed") log.debug("index: %s name: %s", alert.index, decode_string(alert.name)) try: torrent = self.torrents[str(alert.handle.info_hash())] torrent_id = str(alert.handle.info_hash()) except: return # We need to see if this file index is in a waiting_on_folder list folder_rename = False for i, wait_on_folder in enumerate(torrent.waiting_on_folder_rename): if alert.index in wait_on_folder[2]: folder_rename = True if len(wait_on_folder[2]) == 1: # This is the last alert we were waiting for, time to send signal component.get("EventManager").emit(TorrentFolderRenamedEvent(torrent_id, wait_on_folder[0], wait_on_folder[1])) # Empty folders are removed after libtorrent folder renames self.remove_empty_folders(torrent_id, wait_on_folder[0]) del torrent.waiting_on_folder_rename[i] self.save_resume_data((torrent_id,)) break # This isn't the last file to be renamed in this folder, so just # remove the index and continue torrent.waiting_on_folder_rename[i][2].remove(alert.index) if not folder_rename: # This is just a regular file rename so send the signal component.get("EventManager").emit(TorrentFileRenamedEvent(torrent_id, alert.index, alert.name)) self.save_resume_data((torrent_id,))
def connect_peer(self, ip, port): """adds manual peer""" try: self.handle.connect_peer((ip, int(port)), 0) except Exception, e: log.debug("Unable to connect to peer: %s", e) return False
def enable(self): # Create the defaults with the core config core_config = component.get("Core").config DEFAULT_PREFS["low_down"] = core_config["max_download_speed"] DEFAULT_PREFS["low_up"] = core_config["max_upload_speed"] DEFAULT_PREFS["low_active"] = core_config["max_active_limit"] DEFAULT_PREFS["low_active_down"] = core_config["max_active_downloading"] DEFAULT_PREFS["low_active_up"] = core_config["max_active_seeding"] self.config = deluge.configmanager.ConfigManager("myscheduler.conf", DEFAULT_PREFS) self.torrent_states = deluge.configmanager.ConfigManager("myschedulerstates.conf", DEFAULT_STATES) self._cleanup_states() self.state = self.get_state() # Apply the scheduling rules self.do_schedule(False) # Schedule the next do_schedule() call for on the next hour now = time.localtime(time.time()) secs_to_next_hour = ((60 - now[4]) * 60) + (60 - now[5]) log.debug("Next schedule check in %s seconds" % secs_to_next_hour) self.timer = reactor.callLater(secs_to_next_hour, self.do_schedule) eventmanager = component.get("EventManager") eventmanager.register_event_handler("TorrentAddedEvent", self.update_torrent) eventmanager.register_event_handler("TorrentResumedEvent", self.update_torrent) eventmanager.register_event_handler("TorrentRemovedEvent", self._remove_torrent) eventmanager.register_event_handler("TorrentFinishedEvent", self._on_torrent_finished) # Register for config changes so state isn't overridden eventmanager.register_event_handler("ConfigValueChangedEvent", self.on_config_value_changed)
def set_trackers(self, trackers, reannounce=True): """Sets trackers""" if trackers == None: trackers = [] for value in self.handle.trackers(): if lt.version_major == 0 and lt.version_minor < 15: tracker = {} tracker["url"] = value.url tracker["tier"] = value.tier else: tracker = value trackers.append(tracker) self.trackers = trackers self.tracker_host = None return log.debug("Setting trackers for %s: %s", self.torrent_id, trackers) tracker_list = [] for tracker in trackers: new_entry = lt.announce_entry(tracker["url"]) new_entry.tier = tracker["tier"] tracker_list.append(new_entry) self.handle.replace_trackers(tracker_list) # Print out the trackers #for t in self.handle.trackers(): # log.debug("tier: %s tracker: %s", t["tier"], t["url"]) # Set the tracker list in the torrent object self.trackers = trackers if len(trackers) > 0 and reannounce: # Force a reannounce if there is at least 1 tracker self.force_reannounce() self.tracker_host = None
def _on_menuitem_add_peer_activate(self, menuitem): """This is a callback for manually adding a peer""" log.debug("on_menuitem_add_peer") dialog_glade = gtk.glade.XML( pkg_resources.resource_filename("deluge.ui.gtkui", "glade/dgtkpopups.glade")) peer_dialog = dialog_glade.get_widget("connect_peer_dialog") txt_ip = dialog_glade.get_widget("txt_ip") response = peer_dialog.run() if response: value = txt_ip.get_text() if value and ':' in value: if ']' in value: #ipv6 ip = value.split("]")[0][1:] port = value.split("]")[1][1:] else: #ipv4 ip = value.split(":")[0] port = value.split(":")[1] if deluge.common.is_ip(ip): log.debug("adding peer %s to %s", value, self.torrent_id) client.core.connect_peer(self.torrent_id, ip, port) peer_dialog.destroy() return True
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 _on_button_press_event(self, widget, event): """This is a callback for showing the right-click context menu.""" log.debug("on_button_press_event") # We only care about right-clicks if self.torrent_id and event.button == 3: self.peer_menu.popup(None, None, None, event.button, event.time) return True
def on_menuitem_open_folder_activate(self, data=None): log.debug("on_menuitem_open_folder") def _on_torrent_status(status): timestamp = gtk.get_current_event_time() deluge.common.open_file(status["save_path"], timestamp=timestamp) for torrent_id in component.get("TorrentView").get_selected_torrents(): component.get("SessionProxy").get_torrent_status(torrent_id, ["save_path"]).addCallback(_on_torrent_status)
def save_state(self): filename = "peers_tab.state" # Get the current sort order of the view column_id, sort_order = self.liststore.get_sort_column_id() # Setup state dict state = { "columns": {}, "sort_id": column_id, "sort_order": int(sort_order) if sort_order else None } for index, column in enumerate(self.listview.get_columns()): state["columns"][column.get_title()] = { "position": index, "width": column.get_width() } # Get the config location for saving the state file config_location = deluge.configmanager.get_config_dir() try: log.debug("Saving FilesTab state file: %s", filename) state_file = open(os.path.join(config_location, filename), "wb") cPickle.dump(state, state_file) state_file.close() except IOError, e: log.warning("Unable to save state file: %s", e)
def set_tab_visible(self, tab_name, visible): """Sets the tab to visible""" log.debug("set_tab_visible name: %s visible: %s", tab_name, visible) if visible and not self.tabs[tab_name].is_visible: self.show_tab(tab_name) elif not visible and self.tabs[tab_name].is_visible: self.hide_tab(tab_name)
def enable(self): log.debug('Blocklist: Plugin enabled..') self.is_url = True self.is_downloading = False self.is_importing = False self.has_imported = False self.up_to_date = False self.need_to_resume_session = False self.num_blocked = 0 self.file_progress = 0.0 self.core = component.get("Core") self.config = deluge.configmanager.ConfigManager("blocklist.conf", DEFAULT_PREFS) self.reader = create_reader(self.config["list_type"], self.config["list_compression"]) if type(self.config["last_update"]) is not float: self.config.config["last_update"] = 0.0 update_now = False if self.config["load_on_start"]: self.pause_session() if self.config["check_after_days"] > 0: if self.config["last_update"]: last_update = datetime.fromtimestamp(self.config["last_update"]) check_period = timedelta(days=self.config["check_after_days"]) if not self.config["last_update"] or last_update + check_period < datetime.now(): update_now = True if not update_now: d = self.import_list(deluge.configmanager.get_config_dir("blocklist.cache")) d.addCallbacks(self.on_import_complete, self.on_import_error) if self.need_to_resume_session: d.addBoth(self.resume_session) # This function is called every 'check_after_days' days, to download # and import a new list if needed. if self.config["check_after_days"] > 0: self.update_timer = LoopingCall(self.check_import) self.update_timer.start(self.config["check_after_days"] * 24 * 60 * 60, update_now)
def on_download_error(self, f): """ Recovers from download error :param f: failure that occurred :type f: Failure :returns: a Deferred if recovery was possible else the original failure :rtype: Deferred or Failure """ self.is_downloading = False error_msg = f.getErrorMessage() d = f if f.check(error.PageRedirect): # Handle redirect errors location = urljoin(self.config["url"], error_msg.split(" to ")[1]) if "Moved Permanently" in error_msg: log.debug("Setting blocklist url to %s", location) self.config["url"] = location d = self.download_list(location) d.addCallbacks(self.on_download_complete, self.on_download_error) else: if "Not Modified" in error_msg: log.debug("Blocklist is up-to-date!") self.up_to_date = True blocklist = deluge.configmanager.get_config_dir("blocklist.cache") d = threads.deferToThread(self.update_info, blocklist) else: log.warning("Blocklist download failed: %s", error_msg) if self.failed_attempts < self.config["try_times"]: log.debug("Let's try again") self.failed_attempts += 1 d = self.download_list() d.addCallbacks(self.on_download_complete, self.on_download_error) return d
def on_selection_changed(self, selection): try: (model, row) = self.label_view.get_selection().get_selected() if not row: log.debug("nothing selected") return cat = model.get_value(row, 0) value = model.get_value(row, 1) filter_dict = {cat: [value]} if value == "All" or cat == "cat": filter_dict = {} component.get("TorrentView").set_filter(filter_dict) self.selected_path = model.get_path(row) except Exception, e: log.debug(e) # paths is likely None .. so lets return None return None
def get_torrent_rules(self, id, torrent, tracker_rules, label_rules): total_rules = [] try: for t in torrent.trackers: for name, rules in list(tracker_rules.items()): log.debug( "Get_torrent_rules: processing name = {}, rules = {}, url = {}, find = {} " .format(name, rules, t['url'], t['url'].find(name.lower()))) if (t['url'].find(name.lower()) != -1): for rule in rules: total_rules.append(rule) except Exception as e: log.warning( "Get_torrent_rules: Exception with getting torrent rules for {}: {}" .format(id, e)) return total_rules if label_rules: try: # get label string label_str = component.get( "CorePlugin.Label")._status_get_label(id) # if torrent has labels check them labels = [label_str] if len(label_str) > 0 else [] for label in labels: if label in label_rules: for rule in label_rules[label]: total_rules.append(rule) except Exception as e: log.warning("Cannot obtain torrent label for {}: {}".format( id, e)) log.debug("Get_torrent_rules: returning rules for {}: {}".format( id, total_rules)) return total_rules
def on_show(self, widget=None, data=None): "No Label:disable options/del" log.debug("label-sidebar-popup:on-show") cat = self.treeview.cat label = self.treeview.value if cat == "label" or (cat == "cat" and label == "label"): #is a label : show menu-items for item in self.items: item.show() #default items sensitive = ((label not in (NO_LABEL, None, "", "All")) and (cat != "cat")) for item in self.items: item.set_sensitive(sensitive) #add is allways enabled. self.item_add.set_sensitive(True) else: #not a label -->hide everything. for item in self.items: item.hide()
def on_apply_prefs(self): log.debug("applying prefs for Streaming") config = { "ip": self.glade.get_widget("input_ip").get_text(), "port": int(self.glade.get_widget("input_port").get_text()), "use_stream_urls": self.glade.get_widget("input_use_stream_urls").get_active(), "auto_open_stream_urls": self.glade.get_widget("input_auto_open_stream_urls").get_active(), "allow_remote": self.glade.get_widget("input_allow_remote").get_active(), "reset_complete": self.glade.get_widget("input_reset_complete").get_active(), "remote_username": self.glade.get_widget("input_remote_username").get_text(), "remote_password": self.glade.get_widget("input_remote_password").get_text(), } client.streaming.set_config(config)
def on_menuitem_move_activate(self, data=None): log.debug("on_menuitem_move_activate") if client.is_localhost(): from deluge.configmanager import ConfigManager config = ConfigManager("gtkui.conf") chooser = gtk.FileChooserDialog(_("Choose a directory to move files to"\ ) , component.get("MainWindow").window, \ gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_CANCEL, \ gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) chooser.set_local_only(True) if not deluge.common.windows_check(): chooser.set_icon(common.get_deluge_icon()) chooser.set_property("skip-taskbar-hint", True) chooser.set_current_folder(config["choose_directory_dialog_path"]) if chooser.run() == gtk.RESPONSE_OK: result = chooser.get_filename() config["choose_directory_dialog_path"] = result client.core.move_storage( component.get("TorrentView").get_selected_torrents(), result) chooser.destroy() else: component.get("SessionProxy").get_torrent_status(component.get("TorrentView").get_selected_torrent(), ["save_path"]).addCallback(self.show_move_storage_dialog)
def _on_reactor_start(self): log.debug("_on_reactor_start") self.mainwindow.first_show() if self.config["classic_mode"]: def on_dialog_response(response): if response != Gtk.ResponseType.YES: # The user does not want to turn Classic Mode off, so just quit self.mainwindow.quit() return # Turning off classic_mode self.config["classic_mode"] = False self.__start_non_classic() try: try: client.start_classic_mode() except deluge.error.DaemonRunningError: d = dialogs.YesNoDialog( _("Turn off Classic Mode?"), _("It appears that a Deluge daemon process (deluged) is already running.\n\n\ You will either need to stop the daemon or turn off Classic Mode to continue.") ).run() self.started_in_classic = False d.addCallback(on_dialog_response) except ImportError, e: if "No module named libtorrent" in e.message: d = dialogs.YesNoDialog( _("Enable Thin Client Mode?"), _("Thin client mode is only available because libtorrent is not installed.\n\n\ To use Deluge standalone (Classic mode) please install libtorrent.")).run() self.started_in_classic = False d.addCallback(on_dialog_response) else: raise else: component.start() return
def on_button_addhost_clicked(self, widget): log.debug("on_button_addhost_clicked") dialog = self.glade.get_widget("addhost_dialog") dialog.set_transient_for(self.connection_manager) dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) hostname_entry = self.glade.get_widget("entry_hostname") port_spinbutton = self.glade.get_widget("spinbutton_port") username_entry = self.glade.get_widget("entry_username") password_entry = self.glade.get_widget("entry_password") response = dialog.run() if response == 1: username = username_entry.get_text() password = password_entry.get_text() hostname = hostname_entry.get_text() # We add the host try: self.add_host(hostname, port_spinbutton.get_value_as_int(), username, password) except Exception, e: dialogs.ErrorDialog(_("Error Adding Host"), e, parent=dialog).run()
def on_alert_torrent_paused(self, alert): log.debug("on_alert_torrent_paused") try: torrent = self.torrents[str(alert.handle.info_hash())] torrent_id = str(alert.handle.info_hash()) except: return # Set the torrent state old_state = torrent.state torrent.update_state() if torrent.state != old_state: component.get("EventManager").emit( TorrentStateChangedEvent(torrent_id, torrent.state)) # Don't save resume data for each torrent after self.stop() was called. # We save resume data in bulk in self.stop() in this case. if self.save_resume_data_timer.running: # Write the fastresume file self.save_resume_data((torrent_id, )) if torrent_id in self.shutdown_torrent_pause_list: self.shutdown_torrent_pause_list.remove(torrent_id)
def __init__(self): version = deluge.common.get_version() if version < '2.0': log.debug('mediainfo: deluge version is "%s". using glade' % version) self.glade = gtk.glade.XML(get_resource('mediainfo.glade')) self.window = self.glade.get_widget('mediainfoWindow') self.buffer = self.glade.get_widget( 'textviewMediaInfo').get_buffer() self.glade.signal_autoconnect( {'on_close_clicked': self.on_close_clicked}) else: log.debug('mediainfo: deluge version is "%s". using Builder' % version) self.builder = gtk.Builder() self.builder.add_from_file(get_resource('mediainfo.ui')) self.window = self.builder.get_object('dlg_mediainfo') self.buffer = self.builder.get_object( 'textviewMediaInfo').get_buffer() self.builder.connect_signals(self) self.window.set_transient_for(component.get('MainWindow').window) self.window.set_title('MediaInfo - Deluge')
def on_button_press_event(self, widget, event): """This is a callback for showing the right-click context menu.""" log.debug("on_button_press_event") # We only care about right-clicks if event.button == 3: x, y = event.get_coords() path = self.treeview.get_path_at_pos(int(x), int(y)) if not path: return row = self.model_filter.get_iter(path[0]) if self.get_selected_torrents(): if self.model_filter.get_value( row, self.columns["torrent_id"].column_indices[0] ) not in self.get_selected_torrents(): self.treeview.get_selection().unselect_all() self.treeview.get_selection().select_iter(row) else: self.treeview.get_selection().select_iter(row) torrentmenu = component.get("MenuBar").torrentmenu torrentmenu.popup(None, None, None, event.button, event.time) return True
def makeButtons(self): log.debug('starting to add/connect buttons...') if self.mainWindow is None: self.mainWindow = self.findDialog("MainWindow", "window") if self.addDialog is None: self.addDialog = self.findDialog("AddTorrentDialog", "dialog") if self.prefDialog is None: self.prefDialog = self.findDialog("Preferences", "pref_dialog") if self.moveDialog is None: self.moveDialog = self.makeMoveStorageDialog() if PY3: self.buttons.append(ButtonRec('hbox_download_location_chooser' , self.addDialog)) self.buttons.append(ButtonRec('hbox_move_completed_chooser' , self.addDialog)) self.buttons.append(ButtonRec('hbox_move_completed_path_chooser', self.mainWindow)) self.buttons.append(ButtonRec('hbox_root_path_chooser', self.prefDialog)) self.buttons.append(ButtonRec('hbox_destination_chooser', self.moveDialog)) self.buttons.append(ButtonRec('hbox_download_to_path_chooser', self.prefDialog)) self.buttons.append(ButtonRec('hbox_move_completed_to_path_chooser', self.prefDialog)) self.buttons.append(ButtonRec('hbox_copy_torrent_files_path_chooser', self.prefDialog)) else: self.buttons.append(ButtonRec('entry_download_path' , self.addDialog)) self.buttons.append(ButtonRec('entry_move_completed_path' , self.addDialog)) self.buttons.append(ButtonRec('entry_move_completed' , self.mainWindow)) self.buttons.append(ButtonRec('entry_root_path' , self.configPage)) self.buttons.append(ButtonRec('entry_destination' , self.moveDialog)) self.buttons.append(ButtonRec('entry_download_path' , self.prefDialog)) self.buttons.append(ButtonRec('entry_move_completed_path' , self.prefDialog)) self.buttons.append(ButtonRec('entry_torrents_path' , self.prefDialog)) self.buttons.append(ButtonRec('entry_autoadd' , self.prefDialog)) for btnRec in self.buttons : editbox = self.findEditor(btnRec) if editbox is None: self.handleError() continue btnRec.editbox = editbox btn = self.findButton(btnRec) if btn is None: self.handleError() continue log.debug("connecting button to browse dialog:"+btnRec.id) btnRec.click_handler_id = btn.connect("clicked", self.on_browse_button_clicked) log.debug("button connected:"+btnRec.id) btnRec.widget = btn log.debug('all buttons connected.')
def enable(self): log.debug("AutoRemovePlus: Enabled") self.config = deluge.configmanager.ConfigManager( "autoremoveplus.conf", DEFAULT_PREFS ) self.torrent_states = deluge.configmanager.ConfigManager( "autoremoveplusstates.conf", {} ) # Safe after loading to have a default configuration if no gtkui self.config.save() self.torrent_states.save() # it appears that if the plugin is enabled on boot then it is called # before the torrents are properly loaded and so do_remove receives an # empty list. So we must listen to SessionStarted for when deluge boots # but we still have apply_now so that if the plugin is enabled # mid-program do_remove is still run self.looping_call = LoopingCall(self.do_remove) deferLater(reactor, 5, self.start_looping) apikey_sonarr = self.config['api_sonarr'] apikey_radarr = self.config['api_radarr'] apikey_lidarr = self.config['api_lidarr'] use_sonarr = self.config['enable_sonarr'] use_radarr = self.config['enable_radarr'] use_lidarr = self.config['enable_lidarr'] server = self.config['server_url'] log.info("Sonarr: {}, {}, Radarr: {}, {}, Lidarr: {}, {}, Server: {}".format(use_sonarr,apikey_sonarr,use_radarr,apikey_radarr,use_lidarr,apikey_lidarr,server)) self.sonarr = Mediaserver(server,apikey_sonarr,'sonarr') self.lidarr = Mediaserver(server,apikey_lidarr,'lidarr') self.radarr = Mediaserver(server,apikey_radarr,'radarr')
def _on_button_add_clicked(self, widget): log.debug("_on_button_add_clicked") glade = gtk.glade.XML( pkg_resources.resource_filename("deluge.ui.gtkui", "glade/edit_trackers.glade")) dialog = glade.get_widget("add_tracker_dialog") dialog.set_transient_for(self.dialog) textview = glade.get_widget("textview_trackers") if self.config["createtorrent.trackers"]: textview.get_buffer().set_text("\n".join( self.config["createtorrent.trackers"])) else: textview.get_buffer().set_text("") textview.grab_focus() response = dialog.run() if response == gtk.RESPONSE_OK: # Create a list of trackers from the textview buffer trackers = [] b = textview.get_buffer() lines = b.get_text(b.get_start_iter(), b.get_end_iter()).strip().split("\n") self.config["createtorrent.trackers"] = lines log.debug("lines: %s", lines) for l in lines: if deluge.common.is_url(l): trackers.append(l) # We are going to add these trackers to the heighest tier + 1 tier = 0 for row in self.trackers_liststore: if row[0] > tier: tier = row[0] for tracker in trackers: self.trackers_liststore.append([tier, tracker]) dialog.destroy()
def load_options(self, options): log.debug(options.keys()) for id in self.spin_ids + self.spin_int_ids: self.glade.get_widget(id).set_value(options[id]) for id in self.chk_ids: self.glade.get_widget(id).set_active(bool(options[id])) if client.is_localhost(): self.glade.get_widget("move_completed_path").set_filename( options["move_completed_path"]) self.glade.get_widget("move_completed_path").show() self.glade.get_widget("move_completed_path_entry").hide() else: self.glade.get_widget("move_completed_path_entry").set_text( options["move_completed_path"]) self.glade.get_widget("move_completed_path_entry").show() self.glade.get_widget("move_completed_path").hide() self.glade.get_widget("auto_add_trackers").get_buffer().set_text( "\n".join(options["auto_add_trackers"])) self.apply_sensitivity()
def handle_alerts(self, wait=False): """ Pops all libtorrent alerts in the session queue and handles them appropriately. :param wait: bool, if True then the handler functions will be run right away and waited to return before processing the next alert """ alert = self.session.pop_alert() # Loop through all alerts in the queue while alert is not None: alert_type = type(alert).__name__ # Display the alert message log.debug("%s: %s", alert_type, alert.message()) # Call any handlers for this alert type if alert_type in self.handlers: for handler in self.handlers[alert_type]: if not wait: self.delayed_calls.append(reactor.callLater(0, handler, alert)) else: handler(alert) alert = self.session.pop_alert()
def set_label(self, bot, update): if str(update.message.chat.id) in self.whitelist: try: user = update.message.chat.id self.label = update.message.text log.debug(prelog() + "Label: %s" % (update.message.text)) # Request torrent type keyboard_options = [] keyboard_options.append(['Magnet']) keyboard_options.append(['.torrent']) keyboard_options.append(['URL']) update.message.reply_text(STRINGS['what_kind'], reply_markup=ReplyKeyboardMarkup( keyboard_options, one_time_keyboard=True)) return TORRENT_TYPE except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def enable(self): log.debug("AutoRemovePlus: Enabled") self.config = deluge.configmanager.ConfigManager( "autoremoveplus.conf", DEFAULT_PREFS ) self.torrent_states = deluge.configmanager.ConfigManager( "autoremoveplusstates.conf", {} ) # Safe after loading to have a default configuration if no gtkui self.config.save() self.torrent_states.save() # it appears that if the plugin is enabled on boot then it is called # before the torrents are properly loaded and so do_remove receives an # empty list. So we must listen to SessionStarted for when deluge boots # but we still have apply_now so that if the plugin is enabled # mid-program do_remove is still run self.looping_call = LoopingCall(self.do_remove) deferLater(reactor, 5, self.start_looping)
def load_interface(self): #sidebar #disabled if not self.sidebar_menu: self.sidebar_menu = sidebar_menu.LabelSidebarMenu() #self.sidebar.load() #menu: log.debug("add items to torrentview-popup menu.") torrentmenu = component.get("MenuBar").torrentmenu self.label_menu = submenu.LabelMenu() torrentmenu.append(self.label_menu) self.label_menu.show_all() #columns: self.load_columns() #config: if not self.labelcfg: self.labelcfg = label_config.LabelConfig(self.plugin) self.labelcfg.load() log.debug('Finished loading Label plugin')
def on_apply_prefs(self): log.debug("applying prefs for Notifications") current_popup_subscriptions = [] current_blink_subscriptions = [] current_sound_subscriptions = [] current_email_subscriptions = [] for event, doc, email, popup, blink, sound in self.subscriptions_model: if email: current_email_subscriptions.append(event) if popup: current_popup_subscriptions.append(event) if blink: current_blink_subscriptions.append(event) if sound: current_sound_subscriptions.append(event) old_sound_file = self.config['sound_path'] new_sound_file = self.glade.get_widget("sound_path").get_filename() log.debug("Old Default sound file: %s New one: %s", old_sound_file, new_sound_file) custom_sounds = {} for event_name, event_doc, filename, filepath in self.sounds_model: log.debug("Custom sound for event \"%s\": %s", event_name, filename) if filepath == old_sound_file: continue custom_sounds[event_name] = filepath self.config.config.update({ "popup_enabled": self.glade.get_widget("popup_enabled").get_active(), "blink_enabled": self.glade.get_widget("blink_enabled").get_active(), "sound_enabled": self.glade.get_widget("sound_enabled").get_active(), "sound_path": new_sound_file, "subscriptions": { "popup": current_popup_subscriptions, "blink": current_blink_subscriptions, "sound": current_sound_subscriptions }, "custom_sounds": custom_sounds }) self.config.save() core_config = { "smtp_enabled": self.glade.get_widget("smtp_enabled").get_active(), "smtp_host": self.glade.get_widget("smtp_host").get_text(), "smtp_port": self.glade.get_widget("smtp_port").get_value(), "smtp_user": self.glade.get_widget("smtp_user").get_text(), "smtp_pass": self.glade.get_widget("smtp_pass").get_text(), "smtp_from": self.glade.get_widget("smtp_from").get_text(), "smtp_tls": self.glade.get_widget("smtp_tls").get_active(), "smtp_recipients": [dest[0] for dest in self.recipients_model if dest[0]!='USER@HOST'], "subscriptions": {"email": current_email_subscriptions} } client.notifications.set_config(core_config) client.notifications.get_config().addCallback(self.cb_get_config)
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 = component.get('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 _age_in_days(i_t): (i, t) = i_t log.debug("Age in hours called: i = {}, t = {}".format(i,t)) now = time.time() added = t.get_status(['time_added'])['time_added'] log.debug("Now = {}, added = {}".format(now,added)) age_in_days = (now - added)/86400.0 # age in hours log.debug("Returning age: {}".format(age_in_days)) return age_in_days
def resume(self): """Resumes this torrent""" if self.handle.is_paused() and self.handle.is_auto_managed(): log.debug("Torrent is being auto-managed, cannot resume!") elif self.forced_error and self.forced_error.was_paused: log.debug( "Skip resuming Error state torrent that was originally paused." ) else: # Reset the status message just in case of resuming an Error'd torrent self.set_status_message("OK") if self.handle.is_finished(): # If the torrent has already reached it's 'stop_seed_ratio' then do not do anything if self.options["stop_at_ratio"]: if self.get_ratio() >= self.options["stop_ratio"]: #XXX: This should just be returned in the RPC Response, no event #self.signals.emit_event("torrent_resume_at_stop_ratio") return if self.options["auto_managed"]: # This torrent is to be auto-managed by lt queueing self.handle.auto_managed(True) try: self.handle.resume() except: pass return True if self.forced_error and not self.forced_error.restart_to_resume: self.clear_forced_error_state() elif self.state == "Error" and not self.forced_error: self.handle.clear_error()
def rename_folder(self, folder, new_folder): """Renames a folder within a torrent. This basically does a file rename on all of the folders children.""" log.debug("attempting to rename folder: %s to %s", folder, new_folder) if len(new_folder) < 1: log.error( "Attempting to rename a folder with an invalid folder name: %s", new_folder) return new_folder = sanitize_filepath(new_folder, folder=True) wait_on_folder = (folder, new_folder, []) for f in self.get_files(): if f["path"].startswith(folder): # Keep a list of filerenames we're waiting on wait_on_folder[2].append(f["index"]) new_path = f["path"].replace(folder, new_folder, 1) try: self.handle.rename_file(f["index"], new_path) except TypeError: self.handle.rename_file(f["index"], new_path.encode("utf-8")) self.waiting_on_folder_rename.append(wait_on_folder)
def update_view(self, columns=None): """Update the view. If columns is not None, it will attempt to only update those columns selected. """ filter_column = self.columns["filter"].column_indices[0] # Update the torrent view model with data we've received status = self.status status_keys = status.keys() for row in self.liststore: torrent_id = row[self.columns["torrent_id"].column_indices[0]] if not torrent_id in status_keys: if row[filter_column] is True: row[filter_column] = False else: if row[filter_column] is False: row[filter_column] = True if torrent_id in self.prev_status and status[ torrent_id] == self.prev_status[torrent_id]: # The status dict is the same, so do not update continue # Set values for each column in the row for column in self.columns_to_update: column_index = self.get_column_index(column) for i, status_field in enumerate( self.columns[column].status_field): if status_field in status[torrent_id]: try: # Only update if different row_value = status[torrent_id][status_field] if row[column_index[i]] != row_value: row[column_index[i]] = row_value except Exception, e: log.debug("%s", e)
def _on_button_remote_path_clicked(self, widget): log.debug("_on_button_remote_path_clicked") dialog = self.glade.get_widget("remote_path_dialog") entry = self.glade.get_widget("entry_path") dialog.set_transient_for(self.dialog) entry.set_text("/") entry.grab_focus() response = dialog.run() if response == gtk.RESPONSE_OK: result = entry.get_text() def _on_get_path_size(size): log.debug("size: %s", size) if size > 0: self.files_treestore.clear() self.files_treestore.append( None, [result, gtk.STOCK_NETWORK, size]) self.adjust_piece_size() client.core.get_path_size(result).addCallback(_on_get_path_size) client.force_call(True) dialog.hide()
def on_sounds_edit_button_clicked(self, widget): log.debug("on_sounds_edit_button_clicked") selection = self.sounds_treeview.get_selection() model, iter = selection.get_selected() if iter: path = model.get(iter, SND_PATH)[0] dialog = gtk.FileChooserDialog( title=_("Choose Sound File"), buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_filename(path) def update_model(response): if response == gtk.RESPONSE_OK: new_filename = dialog.get_filename() dialog.destroy() print new_filename model.set(iter, SND_PATH, new_filename, SND_NAME, basename(new_filename)) d = defer.maybeDeferred(dialog.run) d.addCallback(update_model) log.debug("dialog should have been shown")
def enable(self): self.config = ConfigManager("execute.conf", DEFAULT_CONFIG) event_manager = component.get("EventManager") self.torrent_manager = component.get("TorrentManager") self.registered_events = {} self.preremoved_cache = {} # Go through the commands list and register event handlers for command in self.config["commands"]: event = command[EXECUTE_EVENT] if event in self.registered_events: continue def create_event_handler(event): def event_handler(torrent_id): self.execute_commands(torrent_id, event) return event_handler event_handler = create_event_handler(event) event_manager.register_event_handler(EVENT_MAP[event], event_handler) if event == "removed": event_manager.register_event_handler("PreTorrentRemovedEvent", self.on_preremoved) self.registered_events[event] = event_handler log.debug("Execute core plugin enabled!")
def scan_for_plugins(self): """Scans for available plugins""" base_plugin_dir = os.path.join(os.path.dirname(__file__), "plugins") pkg_resources.working_set.add_entry(base_plugin_dir) user_plugin_dir = os.path.join(deluge.configmanager.get_config_dir(), "plugins") plugins_dirs = [base_plugin_dir] for dirname in os.listdir(base_plugin_dir): plugin_dir = os.path.join(base_plugin_dir, dirname) pkg_resources.working_set.add_entry(plugin_dir) plugins_dirs.append(plugin_dir) pkg_resources.working_set.add_entry(user_plugin_dir) plugins_dirs.append(user_plugin_dir) self.pkg_env = pkg_resources.Environment(plugins_dirs) self.available_plugins = [] for name in self.pkg_env: log.debug("Found plugin: %s %s at %s", self.pkg_env[name][0].project_name, self.pkg_env[name][0].version, self.pkg_env[name][0].location) self.available_plugins.append(self.pkg_env[name][0].project_name)