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 update(self): # Get the first selected torrent torrent_id = component.get("TorrentView").get_selected_torrents() # Only use the first torrent in the list or return if None selected if len(torrent_id) != 0: torrent_id = torrent_id[0] else: # No torrent is selected in the torrentview self.clear() return status_keys = ["file_progress", "file_priorities"] if torrent_id != self.torrent_id: # We only want to do this if the torrent_id has changed self.treestore.clear() self.torrent_id = torrent_id status_keys += ["compact"] if self.torrent_id in self.files_list: # We already have the files list stored, so just update the view self.update_files() if self.torrent_id not in self.files_list or not self.files_list[self.torrent_id]: # We need to get the files list log.debug("Getting file list from core..") status_keys += ["files"] component.get("SessionProxy").get_torrent_status(self.torrent_id, status_keys).addCallback(self._on_get_torrent_status)
def remove(self, torrent_id, remove_data=False): """ Remove a torrent from the session. :param torrent_id: the torrent to remove :type torrent_id: string :param remove_data: if True, remove the downloaded data :type remove_data: bool :returns: True if removed successfully, False if not :rtype: bool :raises InvalidTorrentError: if the torrent_id is not in the session """ try: torrent_name = self.torrents[torrent_id].get_status(["name"])["name"] except KeyError: raise InvalidTorrentError("torrent_id not in session") # Emit the signal to the clients component.get("EventManager").emit(PreTorrentRemovedEvent(torrent_id)) try: self.session.remove_torrent(self.torrents[torrent_id].handle, 1 if remove_data else 0) except (RuntimeError, KeyError), e: log.warning("Error removing torrent: %s", e) return False
def remove_replacement(self, replacement_id): for replacement in self.config["replacements"]: if replacement[REPLACEMENT_ID] == replacement_id: self.config["replacements"].remove(replacement) component.get("EventManager").emit(ReplacementRemovedEvent(replacement_id)) break 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 add_torrent(model, path, iter, data): torrent_path = model.get_value(iter, 1) if deluge.common.is_url(torrent_path): if self.config["interactive_add"]: def on_show(result): component.get("AddTorrentDialog").add_from_url(torrent_path) d = component.get("AddTorrentDialog").show(self.config["focus_add_dialog"]) d.addCallback(on_show) else: client.core.add_torrent_url(torrent_path, None) elif deluge.common.is_magnet(torrent_path): if self.config["interactive_add"]: def on_show(result): component.get("AddTorrentDialog").add_from_magnets([torrent_path]) d = component.get("AddTorrentDialog").show(self.config["focus_add_dialog"]) d.addCallback(on_show) else: client.core.add_magnet_uris([torrent_path], []) else: if self.config["interactive_add"]: def on_show(result): component.get("AddTorrentDialog").add_from_files([torrent_path]) d = component.get("AddTorrentDialog").show(self.config["focus_add_dialog"]) d.addCallback(on_show) else: client.core.add_torrent_file( os.path.split(torrent_path)[-1], base64.encodestring(open(torrent_path, "rb").read()), None )
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 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 update(self): # Get the first selected torrent torrent_id = component.get("TorrentView").get_selected_torrents() # Only use the first torrent in the list or return if None selected if len(torrent_id) != 0: torrent_id = torrent_id[0] self._child_widget.set_sensitive(True) else: # No torrent is selected in the torrentview self._child_widget.set_sensitive(False) return if torrent_id != self.prev_torrent_id: self.prev_status = None component.get("SessionProxy").get_torrent_status(torrent_id, ["max_download_speed", "max_upload_speed", "max_connections", "max_upload_slots", "private", "prioritize_first_last", "is_auto_managed", "stop_at_ratio", "stop_ratio", "remove_at_ratio", "move_on_completed", "move_on_completed_path"]).addCallback(self._on_get_torrent_status) self.prev_torrent_id = torrent_id
def enable(self): log.debug('\n\nEnabling %s', self.__class__.__name__) for event in self.events: if self.__imp == 'core': # component.get('CorePlugin.Notifications').register_custom_email_notification( component.get('Notifications').register_custom_email_notification( event.__class__.__name__, self.custom_email_message_provider ) elif self.__imp == 'gtk': notifications_component = component.get('Notifications') notifications_component.register_custom_popup_notification( event.__class__.__name__, self.custom_popup_message_provider ) notifications_component.register_custom_blink_notification( event.__class__.__name__, self.custom_blink_message_provider ) notifications_component.register_custom_sound_notification( event.__class__.__name__, self.custom_sound_message_provider ) self.lc.start(60, False)
def enable(self): log.info("applying prefs for automove") component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs) component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs) self.load_ui() self.dirty = False
def enable(self): self.glade_cfg = gtk.glade.XML(get_resource("config.glade")) self._pieces_tab = PiecesTab() component.get("TorrentDetails").add_tab(self._pieces_tab) # client.pieces.get_config().addCallback(self.set_colors) component.get("Preferences").add_page("Pieces", self.glade_cfg.get_widget("prefs_box"))
def _create_session(self, request, login='******'): """ Creates a new session. :keyword login: the username of the user logging in, currently \ only for future use currently. :type login: string """ m = hashlib.md5() m.update(login) m.update(str(time.time())) m.update(str(random.getrandbits(40))) m.update(m.hexdigest()) session_id = m.hexdigest() config = component.get("DelugeWeb").config expires, expires_str = make_expires(config["session_timeout"]) checksum = str(make_checksum(session_id)) request.addCookie('_session_id', session_id + checksum, path=request.base+"json", expires=expires_str) log.debug("Creating session for %s", login) config = component.get("DelugeWeb").config if type(config["sessions"]) is list: config.config["sessions"] = {} config["sessions"][session_id] = { "login": login, "level": AUTH_LEVEL_NORMAL, "expires": expires } return True
def disable(self): log.debug("[%s] Disabling Core...", PLUGIN_NAME) self.initialized = False deluge.component.get("EventManager").deregister_event_handler( "SessionStartedEvent", self._on_session_started) Torrent.move_storage = self.orig_move_storage for id in self.torrents: self._cancel_remove(id) component.get("FilterManager").deregister_tree_field(STATUS_NAME) component.get("CorePluginManager").deregister_status_field(STATUS_MESSAGE) component.get("CorePluginManager").deregister_status_field(STATUS_NAME) component.get("AlertManager").deregister_handler( self.on_storage_moved) component.get("AlertManager").deregister_handler( self.on_storage_moved_failed) self.config.save() deluge.configmanager.close(CONFIG_FILE) self._rpc_deregister(PLUGIN_NAME) log.debug("[%s] Core disabled", PLUGIN_NAME)
def hide(self): component.get('TorrentView').save_state() component.pause(self.child_components) # Store the x, y positions for when we restore the window self.config['window_x_pos'], self.config['window_y_pos'] = self.window.get_position() self.window.hide()
def disable(self): try: self.timer.cancel() except: pass component.get("EventManager").deregister_event_handler("ConfigValueChangedEvent", self.on_config_value_changed) self.__apply_set_functions()
def _exec_remote(self, method, params, request): """ Executes methods using the Deluge client. """ component.get("Auth").check_request(request, level=AUTH_LEVEL_DEFAULT) core_component, method = method.split(".") return getattr(getattr(client, core_component), method)(*params)
def remove_command(self, command_id): for command in self.config['commands']: if command[EXECUTE_ID] == command_id: self.config['commands'].remove(command) component.get('EventManager').emit(ExecuteCommandRemovedEvent(command_id)) break self.config.save()
def refresh(self): """ This method just shows each line of the event log """ events = component.get('ConsoleUI').events self.stdscr.erase() self.draw_statusbars() if events: for i, event in enumerate(events): if i - self.offset >= self.rows - 2: more = len(events) - self.offset - self.rows + 2 if more > 0: self.add_string(i - self.offset, ' (And %i more)' % more) break elif i - self.offset < 0: continue try: self.add_string(i + 1 - self.offset, event) except curses.error: pass # This'll just cut the line. Note: This seriously should be fixed in a better way else: self.add_string(1, '{!white,black,bold!}No events to show yet') if not component.get('ConsoleUI').is_active_mode(self): return self.stdscr.noutrefresh() curses.doupdate()
def back_to_overview(self): component.stop(["TorrentDetail"]) component.deregister(self) self.stdscr.erase() component.get("ConsoleUI").set_mode(self.alltorrentmode) self.alltorrentmode._go_top = False self.alltorrentmode.resume()
def stream_torrent(self, infohash=None, url=None, filedump=None, filepath_or_index=None): tor = component.get("TorrentManager").torrents.get(infohash, None) if tor is None: logger.info('Did not find torrent, must add it') if not filedump and url: filedump = yield client.getPage(url) if not filedump: defer.returnValue({'status': 'error', 'message': 'unable to find torrent, provide infohash, url or filedump'}) torrent_info = lt.torrent_info(lt.bdecode(filedump)) infohash = str(torrent_info.info_hash()) core = component.get("Core") try: yield core.add_torrent_file('file.torrent', filedump.encode('base64'), {'add_paused': True}) except: defer.returnValue({'status': 'error', 'message': 'failed to add torrent'}) try: tf = self.torrent_handler.get_stream(infohash, filepath_or_index) except UnknownTorrentException: defer.returnValue({'status': 'error', 'message': 'unable to find torrent, probably failed to add it'}) defer.returnValue({ 'status': 'success', 'use_stream_urls': self.config['use_stream_urls'], 'auto_open_stream_urls': self.config['auto_open_stream_urls'], 'url': 'http://%s:%s/file/%s/%s' % (self.config.config['ip'], self.config.config['port'], self.fsr.add_file(tf), urllib.quote_plus(os.path.basename(tf.path))) })
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 _register_handler(self): #log.error("register handler") # from pprint import pprint # pprint(vars(self)) component.get("EventManager").register_event_handler( "TorrentFinishedEvent", self._on_torrent_finished_event )
def rssfeed_update_handler(self, rssfeed_key=None, subscription_key=None): """Goes through all the feeds and runs the active ones. Multiple subscriptions on one RSS Feed will download the RSS feed page only once """ if subscription_key: self.log.info("Running Subscription '%s'" % (self.yarss_config.get_config()["subscriptions"][subscription_key]["name"])) elif rssfeed_key: if self.yarss_config.get_config()["rssfeeds"][rssfeed_key]["active"] is False: return self.log.info("Running RSS Feed '%s'" % (self.yarss_config.get_config()["rssfeeds"][rssfeed_key]["name"])) fetch_result = self.rssfeedhandler.fetch_subscription_torrents(self.yarss_config.get_config(), rssfeed_key, subscription_key=subscription_key) def save_subscription_func(subscription_data): self.yarss_config.generic_save_config("subscriptions", data_dict=subscription_data) self.add_torrent_func(save_subscription_func, fetch_result["matching_torrents"], self.yarss_config.get_config()) # Update TTL value? if fetch_result.has_key("ttl"): # Subscription is run directly. Get RSS Feed key if not rssfeed_key: rssfeed_key = self.yarss_config.get_config()["subscriptions"][subscription_key]["rssfeed_key"] self.log.info("Rescheduling RSS Feed '%s' with interval '%s' according to TTL." % (self.yarss_config.get_config()["rssfeeds"][rssfeed_key]["name"], fetch_result["ttl"])) self.set_timer(rssfeed_key, fetch_result["ttl"]) # Set new interval in config self.yarss_config.get_config()["rssfeeds"][rssfeed_key]["update_interval"] = fetch_result["ttl"] # Send YARSSConfigChangedEvent to GUI with updated config. try: # Tests throws KeyError for EventManager when running this method, so wrap this in try/except component.get("EventManager").emit(YARSSConfigChangedEvent(self.yarss_config.get_config())) except KeyError: pass
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 enable(self): self.log_handlers = [] self.init_logging() self.log.info('Initializing Sickbeard plugin.') self.config = ConfigManager("sickbeard.conf", DEFAULT_PREFS) self.eventmanager = component.get("EventManager") self.pluginmanager = component.get('CorePluginManager') self.sickbeard = Sickbeard(self.config) self.manager = Manager(self.config, self.sickbeard) self.log.info('Enabling Sickbeard plugin.') self.pluginmanager.register_status_field('sickbeard_download_status' , self.get_field_download_status) self.pluginmanager.register_status_field('sickbeard_processing_status' , self.get_field_processing_status) self.pluginmanager.register_status_field('sickbeard_processing_completed_time', self.get_field_processing_completed_time) self.pluginmanager.register_status_field('sickbeard_downloading' , self.get_field_downloading) self.pluginmanager.register_status_field('sickbeard_download_unavailable' , self.get_field_download_unavailable) self.pluginmanager.register_status_field('sickbeard_time_added' , self.get_field_time_added) self.manager.start()
def enable(self): self.config = deluge.configmanager.ConfigManager("scene_extractor.conf", DEFAULT_PREFS) if 'extract_base' not in self.config['extract_base']: self.config["extract_base"] = os.path.join(deluge.configmanager.ConfigManager("core.conf")["download_location"], 'To Watch') component.get("EventManager").register_event_handler("TorrentFinishedEvent", self._on_torrent_finished)
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 __init__(self, method, label_id="", label_name=""): self.config = component.get("GtkPlugin." + PLUGIN_NAME)._config self.method = method self.label_id = label_id self.label_name = label_name self.base_name = label_name.rpartition("/")[2] self.close_func = None self.icon = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, 16, 16) self.icon.fill(0) self.type = DIALOG_TYPES[self.method] self.we = WidgetEncapsulator(get_resource("wnd_name_input.glade")) self.we.wnd_name_input.set_transient_for( component.get("MainWindow").window) self.we.wnd_name_input.set_destroy_with_parent(True) self.we.wnd_name_input.set_title(self.type[DIALOG_NAME]) icon = self.we.wnd_name_input.render_icon(self.type[DIALOG_ICON], gtk.ICON_SIZE_SMALL_TOOLBAR) self.we.wnd_name_input.set_icon(icon) pos = self.config["common"]["name_input_pos"] if pos: self.we.wnd_name_input.move(*pos) size = self.config["common"]["name_input_size"] if size: size[1] = 1 self.we.wnd_name_input.resize(*size) if self.method == "add": self.we.blk_header.hide() else: self.we.lbl_selected_label.set_text(self.base_name) self.we.lbl_selected_label.set_tooltip_text(self.label_name) if self.method == "rename": self.we.lbl_header.set_markup("<b>%s: </b>" % _("Current")) self.we.txt_name.set_text(self.base_name) self.we.txt_name.select_region(0, -1) elif self.method == "sublabel": self.we.lbl_header.set_markup("<b>%s: </b>" % _("Parent")) else: self.we.lbl_header.set_markup( "<b>%s</b>" % self.we.lbl_header.get_text()) self.we.model.signal_autoconnect({ "cb_do_submit" : self.cb_do_submit, "cb_do_close" : self.cb_do_close, "on_txt_changed" : self.on_txt_changed, }) self.we.btn_ok.set_sensitive(False) self.we.wnd_name_input.show()
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 on_menuitem_updatetracker_activate(self, data=None): log.debug("on_menuitem_updatetracker_activate") client.core.force_reannounce( component.get("TorrentView").get_selected_torrents())
def on_menuitem_set_automanaged_on(self, widget): for torrent in component.get("TorrentView").get_selected_torrents(): client.core.set_torrent_auto_managed(torrent, True)
def on_menuitem_statusbar_toggled(self, value): log.debug("on_menuitem_statusbar_toggled") component.get("StatusBar").visible(value.get_active())
def on_menuitem_toolbar_toggled(self, value): log.debug("on_menuitem_toolbar_toggled") component.get("ToolBar").visible(value.get_active())
def on_menuitem_queue_bottom_activate(self, value): log.debug("on_menuitem_queue_bottom_activate") client.core.queue_bottom( component.get("TorrentView").get_selected_torrents())
def on_menuitem_recheck_activate(self, data=None): log.debug("on_menuitem_recheck_activate") client.core.force_recheck( component.get("TorrentView").get_selected_torrents())
def on_menuitem_remove_activate(self, data=None): log.debug("on_menuitem_remove_activate") torrent_ids = component.get("TorrentView").get_selected_torrents() if torrent_ids: from removetorrentdialog import RemoveTorrentDialog RemoveTorrentDialog(torrent_ids).run()
def on_menuitem_connectionmanager_activate(self, data=None): log.debug("on_menuitem_connectionmanager_activate") component.get("ConnectionManager").show()
def on_menuitem_addtorrent_activate(self, data=None): log.debug("on_menuitem_addtorrent_activate") component.get("AddTorrentDialog").show()
def on_menuitem_resume_activate(self, data=None): log.debug("on_menuitem_resume_activate") client.core.resume_torrent( component.get("TorrentView").get_selected_torrents())
def get_torrent_status(self, torrent_id): component.get("SessionProxy").get_torrent_status( torrent_id, ["name", "num_files", "total_payload_download"]).addCallback( self._on_get_torrent_status)
def on_menuitem_preferences_activate(self, data=None): log.debug("on_menuitem_preferences_activate") component.get("Preferences").show()
def enable(self): self.plugin = component.get("PluginManager") self.preferences = ExecutePreferences(self.plugin) self.preferences.load()
def show_other_dialog(header, type_str, image_stockid=None, image_filename=None, default=0): """ Shows a dialog with `header` as the header text and `type_str` as the type text. The type of spinbutton (int or float) is determined by `default` type. :param header: str, the header label text :param type_str: str, the type label text, what comes after the spinbutton :param image_stockid: gtkStockId, the stock id of the image in the header :param image_filename: str, filename of icon in pixmaps folder :param default: the default value in the spinbutton :returns: None, int or float from spinbutton depending on `default`. None is returned if the user clicks on Cancel. :rtype: None, int or float :raises TypeError: if `default` is not of type int or float """ if type(default) != int and type(default) != float: raise TypeError("default value needs to be an int or float") builder = gtk.Builder() builder.add_from_file( deluge.common.resource_filename( "deluge.ui.gtkui", os.path.join("glade", "other_dialog.ui"))) dialog = builder.get_object("other_dialog") dialog.set_transient_for(component.get("MainWindow").window) dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) dialog.set_title("") builder.get_object("label_header").set_markup("<b>" + header + "</b>") builder.get_object("label_type").set_text(type_str) if image_stockid: builder.get_object("image").set_from_stock(image_stockid, gtk.ICON_SIZE_LARGE_TOOLBAR) if image_filename: # Hack for Windows since it doesn't support svg if os.path.splitext(image_filename)[1] == ".svg" and ( deluge.common.windows_check() or deluge.common.osx_check()): image_filename = os.path.splitext(image_filename)[0] + "16.png" pixbuf = gtk.gdk.pixbuf_new_from_file_at_size( deluge.common.get_pixmap(image_filename), 32, 32) builder.get_object("image").set_from_pixbuf(pixbuf) spinbutton = builder.get_object("spinbutton") if type(default) == float: spinbutton.set_digits(1) # Set default value and select text spinbutton.set_value(default) spinbutton.select_region(0, -1) value = None response = dialog.run() if response == gtk.RESPONSE_OK: if type(default) == int: value = spinbutton.get_value_as_int() else: value = spinbutton.get_value() dialog.destroy() return value
def __init__(self, handle, options, state=None, filename=None, magnet=None): log.debug("Creating torrent object %s", str(handle.info_hash())) # Get the core config self.config = ConfigManager("core.conf") self.rpcserver = component.get("RPCServer") # This dict holds previous status dicts returned for this torrent # We use this to return dicts that only contain changes from the previous # {session_id: status_dict, ...} self.prev_status = {} from twisted.internet.task import LoopingCall self.prev_status_cleanup_loop = LoopingCall(self.cleanup_prev_status) self.prev_status_cleanup_loop.start(10) # Set the libtorrent handle self.handle = handle # Set the torrent_id for this torrent self.torrent_id = str(handle.info_hash()) # Let's us know if we're waiting on a lt alert self.waiting_on_resume_data = False # Keep a list of file indexes we're waiting for file_rename alerts on # This also includes the old_folder and new_folder to know what signal to send # This is so we can send one folder_renamed signal instead of multiple # file_renamed signals. # [(old_folder, new_folder, [*indexes]), ...] self.waiting_on_folder_rename = [] # We store the filename just in case we need to make a copy of the torrentfile if not filename: # If no filename was provided, then just use the infohash filename = self.torrent_id self.filename = filename # Store the magnet uri used to add this torrent if available self.magnet = magnet # Torrent state e.g. Paused, Downloading, etc. self.state = None # Holds status info so that we don't need to keep getting it from lt self.status = self.handle.status() try: self.torrent_info = self.handle.get_torrent_info() except RuntimeError: self.torrent_info = None # Default total_uploaded to 0, this may be changed by the state self.total_uploaded = 0 # Set the default options self.options = TorrentOptions() self.options.update(options) # We need to keep track if the torrent is finished in the state to prevent # some weird things on state load. self.is_finished = False # Load values from state if we have it if state: # This is for saving the total uploaded between sessions self.total_uploaded = state.total_uploaded # Set the trackers self.set_trackers(state.trackers) # Set the filename self.filename = state.filename self.is_finished = state.is_finished else: # Set trackers from libtorrent self.set_trackers(None) # Various torrent options self.handle.resolve_countries(True) # Details of torrent forced into error state (i.e. not by libtorrent). self.forced_error = None # Status message holds error info about the torrent self.statusmsg = "OK" self.set_options(self.options) # The torrents state self.update_state() # The tracker status self.tracker_status = "" # This gets updated when get_tracker_host is called self.tracker_host = None if state: self.time_added = state.time_added else: self.time_added = time.time() # Keep track if we're forcing a recheck of the torrent so that we can # repause it after its done if necessary self.forcing_recheck = False self.forcing_recheck_paused = False
def __init__(self): self.config = ConfigManager("gtkui.conf") self.tray = component.get("SystemTray")
def on_status_item_clicked(self, widget, event): component.get('Preferences').show('Scheduler')
def disable(self): component.get("Preferences").remove_page("Telegramer") component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs) component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs)
def complete(self, line): # We use the ConsoleUI torrent tab complete method return component.get("ConsoleUI").tab_complete_torrent(line)
def create_prefs_page(self): # Select Widget hover = gtk.Label() self.scheduler_select = SchedulerSelectWidget(hover) vbox = gtk.VBox(False, 5) hbox = gtk.HBox(False, 5) vbox_days = gtk.VBox() for day in DAYS: vbox_days.pack_start(gtk.Label(day)) hbox.pack_start(vbox_days, False, False) hbox.pack_start(self.scheduler_select, True, True) frame = gtk.Frame() label = gtk.Label() label.set_markup('<b>Schedule</b>') frame.set_label_widget(label) frame.set_shadow_type(gtk.SHADOW_NONE) frame.add(hbox) vbox.pack_start(frame, True, True) vbox.pack_start(hover) table = gtk.Table(3, 4) label = gtk.Label(_('Download Limit:')) label.set_alignment(0.0, 0.6) table.attach(label, 0, 1, 0, 1, gtk.FILL) self.spin_download = gtk.SpinButton() self.spin_download.set_numeric(True) self.spin_download.set_range(-1.0, 99999.0) self.spin_download.set_increments(1, 10) table.attach(self.spin_download, 1, 2, 0, 1, gtk.FILL) label = gtk.Label(_('Upload Limit:')) label.set_alignment(0.0, 0.6) table.attach(label, 0, 1, 1, 2, gtk.FILL) self.spin_upload = gtk.SpinButton() self.spin_upload.set_numeric(True) self.spin_upload.set_range(-1.0, 99999.0) self.spin_upload.set_increments(1, 10) table.attach(self.spin_upload, 1, 2, 1, 2, gtk.FILL) label = gtk.Label(_('Active Torrents:')) label.set_alignment(0.0, 0.6) table.attach(label, 2, 3, 0, 1, gtk.FILL) self.spin_active = gtk.SpinButton() self.spin_active.set_numeric(True) self.spin_active.set_range(-1, 9999) self.spin_active.set_increments(1, 10) table.attach(self.spin_active, 3, 4, 0, 1, gtk.FILL) label = gtk.Label(_('Active Downloading:')) label.set_alignment(0.0, 0.6) table.attach(label, 2, 3, 1, 2, gtk.FILL) self.spin_active_down = gtk.SpinButton() self.spin_active_down.set_numeric(True) self.spin_active_down.set_range(-1, 9999) self.spin_active_down.set_increments(1, 10) table.attach(self.spin_active_down, 3, 4, 1, 2, gtk.FILL) label = gtk.Label(_('Active Seeding:')) label.set_alignment(0.0, 0.6) table.attach(label, 2, 3, 2, 3, gtk.FILL) self.spin_active_up = gtk.SpinButton() self.spin_active_up.set_numeric(True) self.spin_active_up.set_range(-1, 9999) self.spin_active_up.set_increments(1, 10) table.attach(self.spin_active_up, 3, 4, 2, 3, gtk.FILL) eventbox = gtk.EventBox() eventbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#EDD400')) eventbox.add(table) frame = gtk.Frame() label = gtk.Label() label.set_markup(_('<b>Slow Settings</b>')) frame.set_label_widget(label) frame.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#CDB400')) frame.set_border_width(2) frame.add(eventbox) vbox.pack_start(frame, False, False) vbox.show_all() component.get('Preferences').add_page(_('Scheduler'), vbox)
def _on_row_activated(self, tree, path, view_column): if client.is_localhost: component.get("SessionProxy").get_torrent_status( self.torrent_id, ["save_path", "files"]).addCallback(self._on_open_file)
def read_input(self): # Read the character affected_lines = None c = self.stdscr.getch() # Either ESC or ALT+<some key> if c == util.KEY_ESC: n = self.stdscr.getch() if n == -1: # Means it was the escape key pass else: # ALT+<some key> c = [c, n] if self.popup: ret = self.popup.handle_read(c) if self.popup and self.popup.closed(): self.pop_popup() self.refresh() return ret if util.is_printable_chr(c): if chr(c) == 'Q': component.get('ConsoleUI').quit() elif chr(c) == 'C': self.consoleui.set_mode('ConnectionManager') return elif chr(c) == 'q': self.torrentview.update_marked(self.torrentview.cursel) self.set_minor_mode( QueueMode(self, self.torrentview._selected_torrent_ids())) return elif chr(c) == '/': self.set_minor_mode(SearchMode(self)) return if self.sidebar.has_focus() and c not in [curses.KEY_RIGHT]: self.sidebar.handle_read(c) self.refresh() return if self.torrentview.numtorrents < 0: return elif self.minor_mode: self.minor_mode.handle_read(c) return affected_lines = None # Hand off to torrentview if self.torrentview.handle_read(c) == util.ReadState.CHANGED: affected_lines = self.torrentview.get_input_result() if c == curses.KEY_LEFT: if not self.sidebar.has_focus(): self.sidebar.set_focused(True) self.refresh() return elif c == curses.KEY_RIGHT: if self.sidebar.has_focus(): self.sidebar.set_focused(False) self.refresh() return # We enter a new mode for the selected torrent here tid = self.torrentview.current_torrent_id() if tid: self.show_torrent_details(tid) return elif util.is_printable_chr(c): if chr(c) == 'a': show_torrent_add_popup(self) elif chr(c) == 'v': self._show_visible_columns_popup() elif chr(c) == 'h': self.push_popup( MessagePopup(self, 'Help', HELP_STR, width_req=0.65)) elif chr(c) == 'p': mode = self.consoleui.set_mode('Preferences') mode.load_config() return elif chr(c) == 'e': self.consoleui.set_mode('EventView') return elif chr(c) == 'S': self.config['torrentview']['show_sidebar'] = self.config[ 'torrentview']['show_sidebar'] is False self.config.save() self.toggle_sidebar() elif chr(c) == 'l': self.consoleui.set_mode('CmdLine', refresh=True) return self.refresh(affected_lines)
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) # Override destination if in_place_extraction is set # if self.config["in_place_extraction"]: name = tid_status["name"] save_path = tid_status["save_path"] dest = os.path.join(save_path, 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 enable(self): self.config = deluge.configmanager.ConfigManager( "notifications-gtk.conf", DEFAULT_PREFS) self.glade = gtk.glade.XML(get_resource("config.glade")) self.glade.get_widget("smtp_port").set_value(25) self.prefs = self.glade.get_widget("prefs_box") self.prefs.show_all() self.build_recipients_model_populate_treeview() self.build_sounds_model_populate_treeview() self.build_notifications_model_populate_treeview() client.notifications.get_handled_events().addCallback( self.popuplate_what_needs_handled_events) self.glade.signal_autoconnect({ 'on_add_button_clicked': (self.on_add_button_clicked, self.recipients_treeview), 'on_delete_button_clicked': (self.on_delete_button_clicked, self.recipients_treeview), 'on_enabled_toggled': self.on_enabled_toggled, 'on_sound_enabled_toggled': self.on_sound_enabled_toggled, 'on_sounds_edit_button_clicked': self.on_sounds_edit_button_clicked, 'on_sounds_revert_button_clicked': \ self.on_sounds_revert_button_clicked, 'on_sound_path_update_preview': self.on_sound_path_update_preview }) prefs = component.get("Preferences") parent = self.prefs.get_parent() if parent: parent.remove(self.prefs) index = prefs.notebook.append_page(self.prefs) prefs.liststore.append([index, _("Notifications")]) component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs) component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs) if not POPUP_AVAILABLE: self.glade.get_widget("popup_enabled").set_property( 'sensitive', False) if not SOUND_AVAILABLE: # for widget_name in ('sound_enabled', 'sound_path', 'sounds_page', # 'sounds_page_label'): # self.glade.get_widget(widget_name).set_property('sensitive', # False) self.glade.get_widget("sound_enabled").set_property( 'sensitive', False) self.glade.get_widget('sound_path').set_property( 'sensitive', False) self.glade.get_widget('sounds_page').set_property( 'sensitive', False) self.glade.get_widget('sounds_page_label').set_property( 'sensitive', False) self.systray = component.get("SystemTray") if not hasattr(self.systray, 'tray'): # Tray is not beeing used self.glade.get_widget('blink_enabled').set_property( 'sensitive', False) GtkUiNotifications.enable(self)
def action_torrent_info(mode=None, torrent_ids=None, **kwargs): popup = MessagePopup(mode, 'Torrent options', 'Querying core, please wait...') mode.push_popup(popup) torrents = torrent_ids options = {} def _do_set_torrent_options(torrent_ids, result): options = {} for opt, val in result.items(): if val['value'] not in ['multiple', None]: options[opt] = val['value'] client.core.set_torrent_options(torrent_ids, options) def on_torrent_status(status): for key in status: if key not in options: options[key] = status[key] elif options[key] != status[key]: options[key] = 'multiple' def create_popup(status): mode.pop_popup() def cb(result, **kwargs): if result is None: return _do_set_torrent_options(torrent_ids, result) if kwargs.get('close', False): mode.pop_popup() return True option_popup = InputPopup( mode, ' Set Torrent Options ', close_cb=cb, border_off_west=1, border_off_north=1, base_popup=kwargs.get('base_popup', None), ) for field in TORRENT_OPTIONS: caption = '{!info!}' + TORRENT_DATA_FIELD[field]['name'] value = options[field] if isinstance(value, ''.__class__): option_popup.add_text_input(field, caption, value) elif isinstance(value, bool): choices = (['Yes', 'No'], [True, False], [True, False].index(value)) option_popup.add_select_input( field, caption, choices[0], choices[1], choices[2] ) elif isinstance(value, float): option_popup.add_float_spin_input( field, caption, value=value, min_val=-1 ) elif isinstance(value, int): option_popup.add_int_spin_input(field, caption, value=value, min_val=-1) mode.push_popup(option_popup) callbacks = [] for tid in torrents: deferred = component.get('SessionProxy').get_torrent_status( tid, list(TORRENT_OPTIONS) ) callbacks.append(deferred.addCallback(on_torrent_status)) callbacks = defer.DeferredList(callbacks) callbacks.addCallback(create_popup)
def __init__(self): Tab.__init__(self) glade = component.get("MainWindow").get_glade() self._name = "Files" self._child_widget = glade.get_widget("files_tab") self._tab_label = glade.get_widget("files_tab_label") self.listview = glade.get_widget("files_listview") # filename, size, progress string, progress value, priority, file index, icon id self.treestore = gtk.TreeStore(str, gobject.TYPE_UINT64, str, float, int, int, str) # We need to store the row that's being edited to prevent updating it until # it's been done editing self._editing_index = None # Filename column self.filename_column_name = _("Filename") column = gtk.TreeViewColumn(self.filename_column_name) render = gtk.CellRendererPixbuf() column.pack_start(render, False) column.add_attribute(render, "stock-id", 6) render = gtk.CellRendererText() render.set_property("editable", True) render.connect("edited", self._on_filename_edited) render.connect("editing-started", self._on_filename_editing_start) render.connect("editing-canceled", self._on_filename_editing_canceled) column.pack_start(render, True) column.add_attribute(render, "text", 0) column.set_sort_column_id(0) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(200) column.set_reorderable(True) self.listview.append_column(column) # Size column column = gtk.TreeViewColumn(_("Size")) render = gtk.CellRendererText() column.pack_start(render, False) column.set_cell_data_func(render, deluge.ui.gtkui.listview.cell_data_size, 1) column.set_sort_column_id(1) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(50) column.set_reorderable(True) self.listview.append_column(column) # Progress column column = gtk.TreeViewColumn(_("Progress")) render = gtk.CellRendererProgress() column.pack_start(render) column.set_cell_data_func(render, cell_progress, (2, 3)) column.set_sort_column_id(3) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(100) column.set_reorderable(True) self.listview.append_column(column) # Priority column column = gtk.TreeViewColumn(_("Priority")) render = gtk.CellRendererPixbuf() column.pack_start(render, False) column.set_cell_data_func(render, cell_priority_icon, 4) render = gtk.CellRendererText() column.pack_start(render, False) column.set_cell_data_func(render, cell_priority, 4) column.set_sort_column_id(4) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(100) # Bugfix: Last column needs max_width set to stop scrollbar appearing column.set_max_width(200) column.set_reorderable(True) self.listview.append_column(column) self.listview.set_model(self.treestore) self.listview.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.file_menu = glade.get_widget("menu_file_tab") self.file_menu_priority_items = [ glade.get_widget("menuitem_donotdownload"), glade.get_widget("menuitem_normal"), glade.get_widget("menuitem_high"), glade.get_widget("menuitem_highest"), glade.get_widget("menuitem_priority_sep") ] self.localhost_widgets = [ glade.get_widget("menuitem_open_file"), glade.get_widget("menuitem3") ] self.listview.connect("row-activated", self._on_row_activated) self.listview.connect("key-press-event", self._on_key_press_event) self.listview.connect("button-press-event", self._on_button_press_event) self.listview.enable_model_drag_source( gtk.gdk.BUTTON1_MASK, [('text/plain', 0, 0)], gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE) self.listview.enable_model_drag_dest([('text/plain', 0, 0)], gtk.gdk.ACTION_DEFAULT) self.listview.connect("drag_data_get", self._on_drag_data_get_data) self.listview.connect("drag_data_received", self._on_drag_data_received_data) glade.signal_autoconnect({ "on_menuitem_open_file_activate": self._on_menuitem_open_file_activate, "on_menuitem_donotdownload_activate": self._on_menuitem_donotdownload_activate, "on_menuitem_normal_activate": self._on_menuitem_normal_activate, "on_menuitem_high_activate": self._on_menuitem_high_activate, "on_menuitem_highest_activate": self._on_menuitem_highest_activate, "on_menuitem_expand_all_activate": self._on_menuitem_expand_all_activate }) # Connect to various events from the daemon client.register_event_handler("TorrentFileRenamedEvent", self._on_torrentfilerenamed_event) client.register_event_handler("TorrentFolderRenamedEvent", self._on_torrentfolderrenamed_event) client.register_event_handler("TorrentRemovedEvent", self._on_torrentremoved_event) # Attempt to load state self.load_state() # torrent_id: (filepath, size) self.files_list = {} self.torrent_id = None
def _initialize(self): def move_storage(torrent, dest_path): id = str(torrent.handle.info_hash()) log.debug("[%s] Queueing (%s)", PLUGIN_NAME, id) if id in self.torrents: if self.torrents[id].status in ALIVE_STATUS: log.debug("[%s] Unable to move torrent: already moving", PLUGIN_NAME) return False else: self._remove_job(id) self.torrents[id] = Progress(torrent, dest_path) if not dest_path: self._report_result(id, "error", "Error", "Empty path") return False if self.torrents[id].src_path == dest_path: self._report_result(id, "error", "Error", "Same path") return False self.queue.append(id) return True self.config = deluge.configmanager.ConfigManager( CONFIG_FILE, copy.deepcopy(DEFAULT_PREFS)) self.general = self.config["general"] self.timeout = self.config["timeout"] normalize_dict(self.general, DEFAULT_PREFS["general"]) normalize_dict(self.timeout, DEFAULT_PREFS["timeout"]) self.torrents = {} self.calls = {} self.queue = [] self.active = None component.get("AlertManager").register_handler("storage_moved_alert", self.on_storage_moved) component.get("AlertManager").register_handler( "storage_moved_failed_alert", self.on_storage_moved_failed) component.get("CorePluginManager").register_status_field( STATUS_NAME, self.get_move_status) component.get("CorePluginManager").register_status_field( STATUS_MESSAGE, self.get_move_message) component.get("FilterManager").register_tree_field( STATUS_NAME, INIT_FILTERS) self.orig_move_storage = Torrent.move_storage Torrent.move_storage = move_storage self.initialized = True log.debug("[%s] Core enabled", PLUGIN_NAME) self._update_loop()
def disable(self): component.get("EventManager").deregister_event_handler( "TorrentFinishedEvent", self._on_torrent_finished)
def disable(self): component.get("Preferences").remove_page("Copy Completed") component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs) component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs) del self.glade
def __on_connected(self,result): component.start() self.stdscr.clear() at = AllTorrents(self.stdscr, self.encoding) component.get("ConsoleUI").set_mode(at) at.resume()