Example #1
0
def get_default_config_dir(filename=None):
    """
    :param filename: if None, only the config path is returned, if provided, a path including the filename will be returned
    :type filename: string
    :returns: a file path to the config directory and optional filename
    :rtype: string

    """
    if windows_check():
        appDataPath = os.environ.get("APPDATA")
        if not appDataPath:
            import _winreg
            hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")
            appDataReg = _winreg.QueryValueEx(hkey, "AppData")
            appDataPath = appDataReg[0]
            _winreg.CloseKey(hkey)
        if filename:
            return os.path.join(appDataPath, "deluge", filename)
        else:
            return os.path.join(appDataPath, "deluge")
    else:
        from xdg.BaseDirectory import save_config_path
        try:
            if filename:
                return os.path.join(save_config_path("deluge"), filename)
            else:
                return save_config_path("deluge")
        except OSError, e:
            log.error("Unable to use default config directory, exiting... (%s)", e)
            sys.exit(1)
Example #2
0
    def __init__(self, icon_dir=None, no_icon=None):
        """
        Initialises a new TrackerIcons object

        :param icon_dir: the (optional) directory of where to store the icons
        :type icon_dir: string
        :param no_icon: the (optional) path name of the icon to show when no icon
                       can be fetched
        :type no_icon: string
        """
        Component.__init__(self, "TrackerIcons")
        if not icon_dir:
            icon_dir = get_config_dir("icons")
        self.dir = icon_dir
        if not os.path.isdir(self.dir):
            os.makedirs(self.dir)

        self.icons = {}
        for icon in os.listdir(self.dir):
            if icon != no_icon:
                host = icon_name_to_host(icon)
                try:
                    self.icons[host] = TrackerIcon(os.path.join(self.dir, icon))
                except KeyError:
                    log.warning("invalid icon %s", icon)
        if no_icon:
            self.icons[None] = TrackerIcon(no_icon)
        else:
            self.icons[None] = None
        self.icons[''] = self.icons[None]

        self.pending = {}
        self.redirects = {}
Example #3
0
 def _shutdown(self, *args, **kwargs):
     if os.path.exists(deluge.configmanager.get_config_dir("deluged.pid")):
         try:
             os.remove(deluge.configmanager.get_config_dir("deluged.pid"))
         except Exception, e:
             log.exception(e)
             log.error("Error removing deluged.pid!")
Example #4
0
 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)
Example #5
0
 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
Example #6
0
 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
Example #7
0
    def start_daemon(self, port, config):
        """
        Starts a daemon process.

        :param port: the port for the daemon to listen on
        :type port: int
        :param config: the path to the current config folder
        :type config: str
        :returns: True if started, False if not
        :rtype: bool

        :raises OSError: received from subprocess.call()

        """
        try:
            if deluge.common.windows_check():
                subprocess.Popen(["deluged", "--port=%s" % port, "--config=%s" % config])
            else:
                subprocess.call(["deluged", "--port=%s" % port, "--config=%s" % config])
        except OSError, e:
            from errno import ENOENT
            if e.errno == ENOENT:
                log.error(_("Deluge cannot find the 'deluged' executable, it is likely \
that you forgot to install the deluged package or it's not in your PATH."))
            else:
                log.exception(e)
            raise e
Example #8
0
 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()
Example #9
0
    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()
Example #10
0
 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
Example #11
0
    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,))
Example #12
0
    def add_torrent_url(self, url, options, headers=None):
        """
        Adds a torrent from a url. Deluge will attempt to fetch the torrent
        from url prior to adding it to the session.

        :param url: the url pointing to the torrent file
        :type url: string
        :param options: the options to apply to the torrent on add
        :type options: dict
        :param headers: any optional headers to send
        :type headers: dict

        :returns: a Deferred which returns the torrent_id as a str or None
        """
        log.info("Attempting to add url %s", url)
        def on_download_success(filename):
            # We got the file, so add it to the session
            f = open(filename, "rb")
            data = f.read()
            f.close()
            try:
                os.remove(filename)
            except Exception, e:
                log.warning("Couldn't remove temp file: %s", e)
            return self.add_torrent_file(filename, base64.encodestring(data), options)
Example #13
0
 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()
Example #14
0
 def __load_session_state(self):
     """Loads the libtorrent session state"""
     try:
         self.session.load_state(lt.bdecode(
             open(deluge.configmanager.get_config_dir("session.state"), "rb").read()))
     except Exception, e:
         log.warning("Failed to load lt state: %s", e)
Example #15
0
 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"])
Example #16
0
	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
Example #17
0
	def populate_list(self):
		if self.dirty :
			log.info("List in dirty state, don't reload prefs")
			return
		self.liststore.clear()
		for t in self.config["trackers"]:
			self.liststore.append(row=[ t["url"], t["dst"], t["cmd"] ])
Example #18
0
    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")
Example #19
0
    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)
Example #20
0
 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
Example #21
0
 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()
Example #22
0
 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()
Example #23
0
    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
Example #24
0
 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)
Example #25
0
 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
Example #26
0
    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)
Example #27
0
 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
Example #28
0
    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)
Example #29
0
 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()
Example #30
0
    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)
Example #31
0
 def start_looping(self):
     log.info('check interval loop starting')
     self.looping_call.start(self.config['interval'] * 3600.0)
Example #32
0
    def blacklistCommand(self, torrent_ids):
        log.info("blacklistCommand torrent running for {}".format(torrent_ids))

        use_sonarr = self.config['enable_sonarr'] if self.config[
            'enable_sonarr'] else False
        use_radarr = self.config['enable_radarr'] if self.config[
            'enable_radarr'] else False
        use_lidarr = self.config['enable_lidarr'] if self.config[
            'enable_lidarr'] else False

        sonarr_list = self.sonarr.get_queue() if use_sonarr else {}
        radarr_list = self.radarr.get_queue() if use_radarr else {}
        lidarr_list = self.lidarr.get_queue() if use_lidarr else {}
        try:
            total_size = len(sonarr_list) + len(lidarr_list) + len(radarr_list)
            log.info("Size of lists: sonarr:{}, lidarr:{}, radarr:{}".format(
                len(sonarr_list), len(lidarr_list), len(radarr_list)))
        except Exception as e:
            log.error("Error summing lists: {}".format(e))
            return

        if not total_size or total_size == 0:
            log.warning("No torrents found in queue")
            return

        label_str = None
        blackListedNum = 0

        if not hasattr(torrent_ids, '__iter__'):
            torrent_ids = [torrent_ids]

        for i in torrent_ids:
            t = self.torrentmanager.torrents.get(i, None)
            log.debug("i = {}, t = {}, types = {}/{}".format(
                i, t, type(i), type(t)))
            if not t:
                log.warning("No torrent object for: {}".format(i))
                continue
            else:
                name = t.get_status(['name'])['name']

                if not name:
                    log.warning(
                        "Skipping blacklisting of torrent {}: could not get name"
                        .format(i))
                    continue
                else:
                    #try:
                    label_str = component.get(
                        "CorePlugin.Label")._status_get_label(i)
                    if label_str and label_str in self.accepted_labels:
                        if (label_str == 'tv-sonarr' and use_sonarr) or (
                                label_str == 'radarr'
                                and use_radarr) or (label_str == 'lidarr'
                                                    and use_lidarr):
                            result = self.blacklistTorrent(
                                i, t, label_str, name)
                            if result:
                                blackListedNum += 1
                            log.info("Blacklist request returned: {}".format(
                                result))
                        else:
                            log.info("Blacklisting not enabled for  {}".format(
                                label_str))
                    #except Exception as e:
                    #   log.warning("Error getting label for torrent {}: {}".format(name,e))
                    #   continue

        self.torrent_states.save()
        return blackListedNum
    def enable(self):
        log.debug("Enabling AutoRemovePlus...")
        self.builder = Gtk.Builder.new_from_file(get_resource("config.ui"))
        component.get("Preferences").add_page(
            "AutoRemovePlus", self.builder.get_object("prefs_box"))
        component.get("PluginManager").register_hook("on_apply_prefs",
                                                     self.on_apply_prefs)
        component.get("PluginManager").register_hook("on_show_prefs",
                                                     self.on_show_prefs)

        # Create and fill remove rule list
        self.rules = Gtk.ListStore(str, str)
        client.autoremoveplus.get_remove_rules().addCallback(self.cb_get_rules)

        # Fill list with logical functions
        self.sel_func_store = Gtk.ListStore(str)
        self.sel_func_store.append(["and"])
        self.sel_func_store.append(["or"])

        # Buttons to add/delete rules
        self._new_rule = self.builder.get_object("new_rule")
        self._new_rule.connect("clicked", self._do_new_rule)
        self._delete_rule = self.builder.get_object("delete_rule")
        self._delete_rule.connect("clicked", self._do_delete_rule)

        # Table to keep all rules
        self._blk_rules = self.builder.get_object("blk_rules")
        self._view = self._build_view_rules()
        window_rules = Gtk.ScrolledWindow()
        window_rules.set_policy(Gtk.PolicyType.AUTOMATIC,
                                Gtk.PolicyType.AUTOMATIC)
        window_rules.set_shadow_type(Gtk.ShadowType.IN)
        window_rules.add(self._view)
        self._blk_rules.add(window_rules)
        self._blk_rules.show_all()

        cell = Gtk.CellRendererText()

        cbo_remove = self.builder.get_object("cbo_remove")
        cbo_remove.pack_start(cell, True)
        cbo_remove.add_attribute(cell, 'text', 1)
        cbo_remove.set_model(self.rules)

        cbo_remove1 = self.builder.get_object("cbo_remove1")
        cbo_remove1.pack_start(cell, True)
        cbo_remove1.add_attribute(cell, 'text', 1)
        cbo_remove1.set_model(self.rules)

        cbo_sel_func = self.builder.get_object("cbo_sel_func")
        cbo_sel_func.set_model(self.sel_func_store)
        cbo_sel_func.set_active(0)
        self.builder.get_object("dummy").set_model(self.sel_func_store)

        self._new_tracker = self.builder.get_object("new_tracker")
        self._new_tracker.connect("clicked", self._do_new_tracker)
        self._delete_tracker = self.builder.get_object("delete_tracker")
        self._delete_tracker.connect("clicked", self._do_delete_tracker)

        self._blk_trackers = self.builder.get_object("blk_trackers")
        self._view_trackers = self._build_view_trackers()
        window = Gtk.ScrolledWindow()
        window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        window.set_shadow_type(Gtk.ShadowType.IN)
        window.add(self._view_trackers)
        self._blk_trackers.add(window)
        self._blk_trackers.show_all()

        self.builder.get_object("chk_remove").connect("toggled",
                                                      self.on_click_remove)

        self.builder.get_object("chk_enabled").connect("toggled",
                                                       self.on_click_enabled)

        self.builder.get_object("chk_rule_1").connect("toggled",
                                                      self.on_click_chk_rule_1)

        self.builder.get_object("chk_rule_2").connect("toggled",
                                                      self.on_click_chk_rule_2)

        def on_menu_show(menu, xxx_todo_changeme):
            (menu_item, toggled) = xxx_todo_changeme

            def set_ignored(ignored):
                # set_active will raise the 'toggled'/'activated' signals
                # so block it to not reset the value
                menu_item.handler_block(toggled)
                menu_item.set_active(False not in ignored)
                menu_item.handler_unblock(toggled)

            client.autoremoveplus.get_ignore([
                t
                for t in component.get("TorrentView").get_selected_torrents()
            ]).addCallback(set_ignored)

        def on_menu_toggled(menu):
            client.autoremoveplus.set_ignore(
                component.get("TorrentView").get_selected_torrents(),
                menu.get_active())

        self.menu = Gtk.CheckMenuItem(_("AutoRemovePlus Exempt"))
        self.menu.show()

        toggled = self.menu.connect('toggled', on_menu_toggled)

        torrentmenu = component.get("MenuBar").torrentmenu
        self.show_sig = torrentmenu.connect('show', on_menu_show,
                                            (self.menu, toggled))
        self.realize_sig = torrentmenu.connect('realize', on_menu_show,
                                               (self.menu, toggled))
        torrentmenu.append(self.menu)

        self.on_show_prefs()
Example #34
0
 def on_set_max_download_speed_per_torrent(self, key, value):
     log.debug("max_download_speed_per_torrent set to %s..", value)
     for key in self.torrents.keys():
         self.torrents[key].set_max_download_speed(value)
Example #35
0
 def on_set_max_connections_per_torrent(self, key, value):
     """Sets the per-torrent connection limit"""
     log.debug("max_connections_per_torrent set to %s..", value)
     for key in self.torrents.keys():
         self.torrents[key].set_max_connections(value)
    def enable_plugin(self, plugin_name):
        """Enables a plugin"""
        if plugin_name not in self.available_plugins:
            log.warning("Cannot enable non-existant plugin %s", plugin_name)
            return

        if plugin_name in self.plugins:
            log.warning("Cannot enable already enabled plugin %s", plugin_name)
            return

        plugin_name = plugin_name.replace(" ", "-")
        egg = self.pkg_env[plugin_name][0]
        egg.activate()
        for name in egg.get_entry_map(self.entry_name):
            entry_point = egg.get_entry_info(self.entry_name, name)
            try:
                cls = entry_point.load()
                instance = cls(plugin_name.replace("-", "_"))
            except Exception, e:
                log.error("Unable to instantiate plugin!")
                log.exception(e)
                continue
            instance.enable()
            if self._component_state == "Started":
                component.start([instance.plugin._component_name])
            plugin_name = plugin_name.replace("-", " ")
            self.plugins[plugin_name] = instance
            if plugin_name not in self.config["enabled_plugins"]:
                log.debug("Adding %s to enabled_plugins list in config",
                          plugin_name)
                self.config["enabled_plugins"].append(plugin_name)
            log.info("Plugin %s enabled..", plugin_name)
Example #37
0
    def __init__(self):
        component.Component.__init__(self, "TorrentManager", interval=5, depend=["CorePluginManager"])
        log.debug("TorrentManager init..")
        # Set the libtorrent session
        self.session = component.get("Core").session
        # Set the alertmanager
        self.alerts = component.get("AlertManager")
        # Get the core config
        self.config = ConfigManager("core.conf")

        # Make sure the state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), "state")):
            os.makedirs(os.path.join(get_config_dir(), "state"))

        # Create the torrents dict { torrent_id: Torrent }
        self.torrents = {}
        self.queued_torrents = set()

        # This is a list of torrent_id when we shutdown the torrentmanager.
        # We use this list to determine if all active torrents have been paused
        # and that their resume data has been written.
        self.shutdown_torrent_pause_list = []

        # self.num_resume_data used to save resume_data in bulk
        self.num_resume_data = 0

        # Keep track of torrents finished but moving storage
        self.waiting_on_finish_moving = []

        # Keeps track of resume data that needs to be saved to disk
        self.resume_data = {}

        # Workaround to determine if TorrentAddedEvent is from state file
        self.session_started = False

        # Register set functions
        self.config.register_set_function("max_connections_per_torrent",
            self.on_set_max_connections_per_torrent)
        self.config.register_set_function("max_upload_slots_per_torrent",
            self.on_set_max_upload_slots_per_torrent)
        self.config.register_set_function("max_upload_speed_per_torrent",
            self.on_set_max_upload_speed_per_torrent)
        self.config.register_set_function("max_download_speed_per_torrent",
            self.on_set_max_download_speed_per_torrent)

        # Register alert functions
        self.alerts.register_handler("torrent_finished_alert",
            self.on_alert_torrent_finished)
        self.alerts.register_handler("torrent_paused_alert",
            self.on_alert_torrent_paused)
        self.alerts.register_handler("torrent_checked_alert",
            self.on_alert_torrent_checked)
        self.alerts.register_handler("tracker_reply_alert",
            self.on_alert_tracker_reply)
        self.alerts.register_handler("tracker_announce_alert",
            self.on_alert_tracker_announce)
        self.alerts.register_handler("tracker_warning_alert",
            self.on_alert_tracker_warning)
        self.alerts.register_handler("tracker_error_alert",
            self.on_alert_tracker_error)
        self.alerts.register_handler("storage_moved_alert",
            self.on_alert_storage_moved)
        self.alerts.register_handler("storage_moved_failed_alert",
            self.on_alert_storage_moved_failed)
        self.alerts.register_handler("torrent_resumed_alert",
            self.on_alert_torrent_resumed)
        self.alerts.register_handler("state_changed_alert",
            self.on_alert_state_changed)
        self.alerts.register_handler("save_resume_data_alert",
            self.on_alert_save_resume_data)
        self.alerts.register_handler("save_resume_data_failed_alert",
            self.on_alert_save_resume_data_failed)
        self.alerts.register_handler("file_renamed_alert",
            self.on_alert_file_renamed)
        self.alerts.register_handler("metadata_received_alert",
            self.on_alert_metadata_received)
        self.alerts.register_handler("file_error_alert",
            self.on_alert_file_error)
        self.alerts.register_handler("file_completed_alert",
            self.on_alert_file_completed)
Example #38
0
class Config(object):
    """
    This class is used to access/create/modify config files

    :param filename: the name of the config file
    :param defaults: dictionary of default values
    :param config_dir: the path to the config directory

    """
    def __init__(self, filename, defaults=None, config_dir=None):
        self.__config = {}
        self.__set_functions = {}
        self.__change_callbacks = []

        # These hold the version numbers and they will be set when loaded
        self.__version = {"format": 1, "file": 1}

        # This will get set with a reactor.callLater whenever a config option
        # is set.
        self._save_timer = None

        if defaults:
            for key, value in defaults.iteritems():
                self.set_item(key, value)

        # Load the config from file in the config_dir
        if config_dir:
            self.__config_file = os.path.join(config_dir, filename)
        else:
            self.__config_file = deluge.common.get_default_config_dir(filename)

        self.load()

    def __contains__(self, item):
        return item in self.__config

    def __setitem__(self, key, value):
        """
        See
        :meth:`set_item`
        """

        return self.set_item(key, value)

    def set_item(self, key, value):
        """
        Sets item 'key' to 'value' in the config dictionary, but does not allow
        changing the item's type unless it is None.  If the types do not match,
        it will attempt to convert it to the set type before raising a ValueError.

        :param key: string, item to change to change
        :param value: the value to change item to, must be same type as what is currently in the config

        :raises ValueError: raised when the type of value is not the same as\
what is currently in the config and it could not convert the value

        **Usage**

        >>> config = Config("test.conf")
        >>> config["test"] = 5
        >>> config["test"]
        5

        """
        if isinstance(value, basestring):
            value = deluge.common.utf8_encoded(value)

        if not self.__config.has_key(key):
            self.__config[key] = value
            log.debug("Setting '%s' to %s of %s", key, value, type(value))
            return

        if self.__config[key] == value:
            return

        # Do not allow the type to change unless it is None
        oldtype, newtype = type(self.__config[key]), type(value)

        if value is not None and oldtype != type(None) and oldtype != newtype:
            try:
                if oldtype == unicode:
                    value = oldtype(value, "utf8")
                elif oldtype == bool:
                    value = str_to_bool[value]
                else:
                    value = oldtype(value)
            except (ValueError, KeyError):
                log.warning("Type '%s' invalid for '%s'", newtype, key)
                raise

        log.debug("Setting '%s' to %s of %s", key, value, type(value))

        self.__config[key] = value
        # Run the set_function for this key if any
        from twisted.internet import reactor
        try:
            for func in self.__set_functions[key]:
                reactor.callLater(0, func, key, value)
        except KeyError:
            pass
        try:

            def do_change_callbacks(key, value):
                for func in self.__change_callbacks:
                    func(key, value)

            reactor.callLater(0, do_change_callbacks, key, value)
        except:
            pass

        # We set the save_timer for 5 seconds if not already set
        if not self._save_timer or not self._save_timer.active():
            self._save_timer = reactor.callLater(5, self.save)

    def __getitem__(self, key):
        """
        See
        :meth:`get_item`
        """
        return self.get_item(key)

    def get_item(self, key):
        """
        Gets the value of item 'key'

        :param key: the item for which you want it's value
        :return: the value of item 'key'

        :raises KeyError: if 'key' is not in the config dictionary

        **Usage**

        >>> config = Config("test.conf", defaults={"test": 5})
        >>> config["test"]
        5

        """
        if isinstance(self.__config[key], str):
            try:
                return self.__config[key].decode("utf8")
            except UnicodeDecodeError:
                return self.__config[key]
        else:
            return self.__config[key]

    def register_change_callback(self, callback):
        """
        Registers a callback function that will be called when a value is changed in the config dictionary

        :param callback: the function, callback(key, value)

        **Usage**

        >>> config = Config("test.conf", defaults={"test": 5})
        >>> def cb(key, value):
        ...     print key, value
        ...
        >>> config.register_change_callback(cb)

        """
        self.__change_callbacks.append(callback)

    def register_set_function(self, key, function, apply_now=True):
        """
        Register a function to be called when a config value changes

        :param key: the item to monitor for change
        :param function: the function to call when the value changes, f(key, value)
        :keyword apply_now: if True, the function will be called after it's registered

        **Usage**

        >>> config = Config("test.conf", defaults={"test": 5})
        >>> def cb(key, value):
        ...     print key, value
        ...
        >>> config.register_set_function("test", cb, apply_now=True)
        test 5

        """
        log.debug("Registering function for %s key..", key)
        if key not in self.__set_functions:
            self.__set_functions[key] = []

        self.__set_functions[key].append(function)

        # Run the function now if apply_now is set
        if apply_now:
            function(key, self.__config[key])
        return

    def apply_all(self):
        """
        Calls all set functions

        **Usage**

        >>> config = Config("test.conf", defaults={"test": 5})
        >>> def cb(key, value):
        ...     print key, value
        ...
        >>> config.register_set_function("test", cb, apply_now=False)
        >>> config.apply_all()
        test 5

        """
        log.debug("Calling all set functions..")
        for key, value in self.__set_functions.iteritems():
            for func in value:
                func(key, self.__config[key])

    def apply_set_functions(self, key):
        """
        Calls set functions for `:param:key`.

        :param key: str, the config key

        """
        log.debug("Calling set functions for key %s..", key)
        if key in self.__set_functions:
            for func in self.__set_functions[key]:
                func(key, self.__config[key])

    def load(self, filename=None):
        """
        Load a config file

        :param filename: if None, uses filename set in object initialization


        """
        if not filename:
            filename = self.__config_file

        try:
            data = open(filename, "rb").read()
        except IOError, e:
            log.warning("Unable to open config file %s: %s", filename, e)
            return

        objects = find_json_objects(data)

        if not len(objects):
            # No json objects found, try depickling it
            try:
                self.__config.update(pickle.loads(data))
            except Exception, e:
                log.exception(e)
                log.warning("Unable to load config file: %s", filename)
Example #39
0
# Initialize gettext
try:
    locale.setlocale(locale.LC_ALL, '')
    if hasattr(locale, "bindtextdomain"):
        locale.bindtextdomain(
            "deluge", pkg_resources.resource_filename("deluge", "i18n"))
    if hasattr(locale, "textdomain"):
        locale.textdomain("deluge")
    gettext.bindtextdomain("deluge",
                           pkg_resources.resource_filename("deluge", "i18n"))
    gettext.textdomain("deluge")
    gettext.install("deluge",
                    pkg_resources.resource_filename("deluge", "i18n"))
except Exception, e:
    log.error("Unable to initialize gettext/locale!")
    log.exception(e)
    import __builtin__
    __builtin__.__dict__["_"] = lambda x: x

import deluge.component as component
from deluge.ui.client import client
from mainwindow import MainWindow
from menubar import MenuBar
from toolbar import ToolBar
from torrentview import TorrentView
from torrentdetails import TorrentDetails
from sidebar import SideBar
from filtertreeview import FilterTreeView
from preferences import Preferences
from systemtray import SystemTray
Example #40
0

try:
    from deluge.log import LOG as log
except Exception as e:
    print 'Telegramer: Exception - %s' % str(e)

try:
    import gtk
    import deluge.common
    from common import get_resource, REGEX_TMPL_FILE_NAME
    from deluge.ui.client import client
    import deluge.component as component
    from deluge.plugins.pluginbase import GtkPluginBase
except ImportError as e:
    log.error('Telegramer: Import error - %s', str(e))


class GtkUI(GtkPluginBase):
    def enable(self):
        self.glade = gtk.glade.XML(get_resource("config.glade"))
        self.glade.signal_autoconnect({
            "on_button_test_clicked": self.on_button_test_clicked,
            "on_button_save_clicked": self.on_button_save_clicked,
            "on_button_reload_clicked": self.on_button_reload_clicked
        })
        component.get("Preferences").add_page("Telegramer", self.glade.get_widget("prefs_box"))
        component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs)
        component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs)

    def disable(self):
Example #41
0
 def on_set_max_upload_slots_per_torrent(self, key, value):
     """Sets the per-torrent upload slot limit"""
     log.debug("max_upload_slots_per_torrent set to %s..", value)
     for key in self.torrents.keys():
         self.torrents[key].set_max_upload_slots(value)
Example #42
0
    def periodicScan(self, *args, **kwargs):
        log.info(
            "AutoRemovePlus: Running check. Interval is {} minutes".format(
                round(self.config['interval'] * 60.0, 1)))

        try:
            max_seeds = int(self.config['max_seeds'])
            count_exempt = self.config['count_exempt']
            remove_data = self.config['remove_data']
            seed_remove_data = self.config['seed_remove_data']
            exemp_trackers = self.config['trackers']
            exemp_labels = self.config['labels']
            min_val = float(self.config['min'])
            max_val2 = float(self.config['min2'])
            remove = self.config['remove']
            enabled = self.config['enabled']
            tracker_rules = self.config['tracker_rules']
            rule_1_chk = self.config['rule_1_enabled']
            rule_2_chk = self.config['rule_2_enabled']
            seedtime_limit = float(self.config['seedtime_limit'])
            seedtime_pause = float(self.config['seedtime_pause'])
            pause_torrents = self.config['pause_torrents']
            labels_enabled = False
            use_sonarr = self.config['enable_sonarr'] if self.config[
                'enable_sonarr'] else False
            use_radarr = self.config['enable_radarr'] if self.config[
                'enable_radarr'] else False
            use_lidarr = self.config['enable_lidarr'] if self.config[
                'enable_lidarr'] else False

            sonarr_list = self.sonarr.get_queue() if use_sonarr else {}
            radarr_list = self.radarr.get_queue() if use_radarr else {}
            lidarr_list = self.lidarr.get_queue() if use_lidarr else {}

            #prevent hit & run
            seedtime_pause = seedtime_pause if seedtime_pause > 20.0 else 20.0
            seedtime_limit = seedtime_limit if seedtime_limit > 24.0 else 24.0

            log.debug("Using sonarr: {}, radarr: {}, lidarr: {}".format(
                use_sonarr, use_radarr, use_lidarr))
            log.info("Size of lists: sonarr:{}, lidarr:{}, radarr:{}".format(
                len(sonarr_list), len(lidarr_list), len(radarr_list)))

            #response = self.sonarr.delete_queueitem('1771649588')
            #log.info("Delete response:{}".format(response))

        except Exception as e:
            log.error("Error reading config: {}".format(e))
            return False

        if 'Label' in component.get("CorePluginManager").get_enabled_plugins():
            labels_enabled = True
            label_rules = self.config['label_rules']
        else:
            log.warning("WARNING! Label plugin not active")
            log.debug("No labels will be checked for exemptions!")
            label_rules = []

        # Negative max means unlimited seeds are allowed, so don't do anything
        if max_seeds < 0:
            return

        torrent_ids = self.torrentmanager.get_torrent_list()

        log.info("Number of torrents: {0}".format(len(torrent_ids)))

        # If there are less torrents present than we allow
        # then there can be nothing to do
        if len(torrent_ids) <= max_seeds:
            return

        torrents = []
        ignored_torrents = []

        # relevant torrents to us exist and are finished
        for i in torrent_ids:
            t = self.torrentmanager.torrents.get(i, None)

            try:
                ignored = self.torrent_states[i]
            except KeyError as e:
                ignored = False

            ex_torrent = False
            trackers = t.trackers

            # check if trackers in exempted tracker list
            for tracker, ex_tracker in ((t, ex_t) for t in trackers
                                        for ex_t in exemp_trackers):
                if (tracker['url'].find(ex_tracker.lower()) != -1):
                    log.debug("Found exempted tracker: %s" % (ex_tracker))
                    ex_torrent = True

            # check if labels in exempted label list if Label plugin is enabled
            if labels_enabled:
                try:
                    # get label string
                    label_str = component.get(
                        "CorePlugin.Label")._status_get_label(i)

                    # if torrent has labels check them
                    labels = [label_str] if len(label_str) > 0 else []

                    for label, ex_label in ((l, ex_l) for l in labels
                                            for ex_l in exemp_labels):
                        if (label.find(ex_label.lower()) != -1):
                            log.debug("Found exempted label: %s" % (ex_label))
                            ex_torrent = True
                except Exception as e:
                    log.warning("Cannot obtain torrent label: {}".format(e))

            # if torrent tracker or label in exemption list, or torrent ignored
            # insert in the ignored torrents list
            (ignored_torrents if ignored or ex_torrent else torrents)\
                .append((i, t))

        log.info("Number of ignored torrents: {0}".format(
            len(ignored_torrents)))

        # now that we have trimmed active torrents
        # check again to make sure we still need to proceed
        if len(torrents) +\
                (len(ignored_torrents) if count_exempt else 0) <= max_seeds:
            return

        # if we are counting ignored torrents towards our maximum
        # then these have to come off the top of our allowance
        if count_exempt:
            max_seeds -= len(ignored_torrents)
            if max_seeds < 0:
                max_seeds = 0

        # Alternate sort by primary and secondary criteria
        torrents.sort(
            key=lambda x:
            (filter_funcs.get(self.config['filter'], _get_ratio)
             (x), filter_funcs.get(self.config['filter2'], _get_ratio)(x)),
            reverse=False)

        changed = False

        # remove or pause these torrents
        for i, t in reversed(torrents[max_seeds:]):
            name = t.get_status(['name'])['name']
            log.debug("Now processing name = {}, type = {}".format(
                name, type(name)))
            # check if free disk space below minimum
            if self.check_min_space():
                break  # break the loop, we have enough space

            if enabled:
                # Get result of first condition test
                filter_1 = filter_funcs.get(self.config['filter'], _get_ratio)(
                    (i, t)) <= min_val
                # Get result of second condition test

                #chosen_func = self.config['filter2']
                # prevent hit and runs
                max_val2 = max_val2 if max_val2 > 0.5 else 0.5
                #log.info("Chosen filter2 : {}, cut-off: {}".format(chosen_func,max_val2))

                filter_2 = filter_funcs.get(self.config['filter2'],
                                            _get_ratio)((i, t)) >= max_val2

                specific_rules = self.get_torrent_rules(
                    i, t, tracker_rules, label_rules)

                # Sort rules according to logical operators, AND is evaluated first
                specific_rules.sort(key=lambda rule: rule[0])

                remove_cond = False
                seed_remove_cond = False  #for removing finished torrents

                # If there are specific rules, ignore general remove rules
                if specific_rules:
                    remove_cond = filter_funcs.get(specific_rules[0][1])((i,t)) \
                        >= specific_rules[0][2]
                    for rule in specific_rules[1:]:
                        check_filter = filter_funcs.get(rule[1])((i,t)) \
                            >= rule[2]
                        remove_cond = sel_funcs.get(rule[0])(
                            (check_filter, remove_cond))
                    seed_remove_cond = remove_cond
                elif rule_1_chk and rule_2_chk:
                    # If both rules active use custom logical function
                    remove_cond = sel_funcs.get(self.config['sel_func'])(
                        (filter_1, filter_2))
                elif rule_1_chk and not rule_2_chk:
                    # Evaluate only first rule, since the other is not active
                    remove_cond = filter_1
                elif not rule_1_chk and rule_2_chk:
                    # Evaluate only second rule, since the other is not active
                    remove_cond = filter_2

                # If logical functions are satisfied remove or pause torrent
                # add check that torrent is not completed
                try:
                    name = t.get_status(['name'])['name']
                    age = _age_in_days((i, t))  # age in days
                    seedtime = round(
                        t.get_status(['seeding_time'])['seeding_time'] / 3600,
                        2)  #seed time in hours
                    ratio = t.get_status(['ratio'])['ratio']
                    availability = t.get_status(['distributed_copies'
                                                 ])['distributed_copies']
                    time_last_transfer = _time_last_transfer(
                        (i, t))  # in hours
                    time_seen_complete = _time_seen_complete(
                        (i, t))  #seen complete in hours
                    isFinished = t.get_status(['is_finished'])['is_finished']
                    paused = t.get_status(['paused'])['paused']
                    hash = t.get_status(['hash'])['hash'].upper()
                except Exception as e:
                    log.error("Error with torrent: {}".format(e))
                    continue
                if time_seen_complete:
                    log.debug(
                        "Processing torrent: {}, last transfer: {} h, last seen complete: {} h, paused: {}"
                        .format(name, time_last_transfer, time_seen_complete,
                                paused))

                if not isFinished:
                    try:
                        label_str = component.get(
                            "CorePlugin.Label")._status_get_label(i)
                        if not label_str:
                            log.warning("Torrent: {}, label = {}".format(
                                name, label_str))
                    except Exception as e:
                        log.error(
                            "Error getting label for torrent {}: {}".format(
                                name, e))
                        label_str = 'none'
                    log.debug(
                        "Processing unfinished torrent {}, label = {}".format(
                            name, label_str))
                    if remove_cond:
                        #pause torrents if selected
                        if pause_torrents:
                            if not paused:
                                log.info(
                                    "AutoRemovePlus: Pausing torrent {} due to availability = {}, age = {}, time_last_transfer = {}"
                                    .format(name, availability, age,
                                            time_last_transfer))
                                self.pause_torrent(t)

                        #user has selected to remove torrents
                        if remove:
                            # blacklist
                            if label_str and label_str in self.accepted_labels:
                                if (label_str == 'tv-sonarr' and use_sonarr
                                    ) or (label_str == 'radarr' and
                                          use_radarr) or (label_str == 'lidarr'
                                                          and use_lidarr):
                                    result = self.blacklistTorrent(
                                        i, t, label_str, name)
                                    log.info(
                                        "Blacklist request for {} returned: {}"
                                        .format(name, result))
                            else:
                                log.warning(
                                    "No matching label {} for torrent {}".
                                    format(label_str, name))

                            # remove using local method
                            result = self.remove_torrent(i, remove_data)
                            log.info(
                                "AutoRemovePlus: removing unfinished torrent {} with data = {} using internal method: {}"
                                .format(name, remove_data, result))

                else:  # is finished

                    log.debug(
                        "Fin.: {}, seed time:{}/{}, ratio: {}, spec. rules = {}, sr cond. = {}/{},isfinished = {}, hash = {}"
                        .format(name, seedtime, seedtime_limit, ratio,
                                specific_rules, remove_cond, seed_remove_cond,
                                isFinished, hash))
                    if (not specific_rules) or (seed_remove_cond):
                        #remove condition
                        if seedtime > seedtime_limit:
                            #seed_remove_data decides if user wants data removed or not
                            self.remove_torrent(i, seed_remove_data)
                            changed = True
                            log.info(
                                "AutoRemovePlus: removing torrent from seed: {} due to seed time = {}/{} h"
                                .format(name, seedtime, seedtime_limit))

                        #pause condition
                        elif seedtime > seedtime_pause:
                            if pause_torrents:
                                try:
                                    #paused = t.get_status(['paused'])['paused']
                                    if not paused:
                                        self.pause_torrent(t)
                                        #changed = True
                                        log.info(
                                            "AutoRemovePlus: pausing finished torrent {} with seedtime = {}/{} h, ratio = {}, rules = {}, sr-cond = {}/{}"
                                            .format(name, seedtime,
                                                    seedtime_pause, ratio,
                                                    specific_rules,
                                                    remove_cond,
                                                    seed_remove_cond))
                                    else:
                                        log.debug(
                                            "AutoRemovePlus: torrent is already paused: {}"
                                            .format(name))
                                except Exception as e:
                                    log.warning(
                                        "AutoRemovePlus: error with pausing torrent: {}"
                                        .format(name))

        # If a torrent exemption state has been removed save changes
        if changed:
            self.torrent_states.save()
Example #43
0
 def on_statusbar_click(self, widget, event):
     log.debug("on_statusbar_click")
     self.run()
Example #44
0
def _get_ratio(i_t):
    (i, t) = i_t
    log.debug("Get ratio: i = {}, t = {}".format(i, t))
    return t.get_ratio()
Example #45
0
 def win_handler(ctrl_type):
     log.debug("ctrl_type: %s", ctrl_type)
     if ctrl_type in (CTRL_CLOSE_EVENT, CTRL_SHUTDOWN_EVENT):
         reactor.stop()
         return 1
Example #46
0
 def pause_torrent(self, torrent):
     try:
         torrent.pause()
     except Exception as e:
         log.warning(
             "AutoRemovePlus: Problems pausing torrent: {}".format(e))
Example #47
0
 def enable(self):
     self.config = deluge.configmanager.ConfigManager(
         "notifications-web.conf", DEFAULT_PREFS
     )
     log.debug("Enabling Web UI notifications")
Example #48
0
 def cb_get_config(self, config):
     """callback for on show_prefs"""
     log.debug('cb get config seedtime')
     self.glade.get_widget("chk_apply_stop_time").set_active(config["apply_stop_time"])
     self.glade.get_widget("chk_remove_torrent").set_active(config["remove_torrent"])
     self.glade.get_widget("txt_default_stop_time").set_text('%.02f' % config["default_stop_time"])
Example #49
0
        objects = find_json_objects(data)

        if not len(objects):
            # No json objects found, try depickling it
            try:
                self.__config.update(pickle.loads(data))
            except Exception, e:
                log.exception(e)
                log.warning("Unable to load config file: %s", filename)
        elif len(objects) == 1:
            start, end = objects[0]
            try:
                self.__config.update(json.loads(data[start:end]))
            except Exception, e:
                log.exception(e)
                log.warning("Unable to load config file: %s", filename)
        elif len(objects) == 2:
            try:
                start, end = objects[0]
                self.__version.update(json.loads(data[start:end]))
                start, end = objects[1]
                self.__config.update(json.loads(data[start:end]))
            except Exception, e:
                log.exception(e)
                log.warning("Unable to load config file: %s", filename)

        log.debug("Config %s version: %s.%s loaded: %s", filename,
                  self.__version["format"], self.__version["file"],
                  self.__config)
Example #50
0
 def stop_reactor(result):
     try:
         reactor.stop()
     except ReactorNotRunning:
         log.debug("Attempted to stop the reactor but it is not running...")
Example #51
0
    def set_item(self, key, value):
        """
        Sets item 'key' to 'value' in the config dictionary, but does not allow
        changing the item's type unless it is None.  If the types do not match,
        it will attempt to convert it to the set type before raising a ValueError.

        :param key: string, item to change to change
        :param value: the value to change item to, must be same type as what is currently in the config

        :raises ValueError: raised when the type of value is not the same as\
what is currently in the config and it could not convert the value

        **Usage**

        >>> config = Config("test.conf")
        >>> config["test"] = 5
        >>> config["test"]
        5

        """
        if isinstance(value, basestring):
            value = deluge.common.utf8_encoded(value)

        if not self.__config.has_key(key):
            self.__config[key] = value
            log.debug("Setting '%s' to %s of %s", key, value, type(value))
            return

        if self.__config[key] == value:
            return

        # Do not allow the type to change unless it is None
        oldtype, newtype = type(self.__config[key]), type(value)

        if value is not None and oldtype != type(None) and oldtype != newtype:
            try:
                if oldtype == unicode:
                    value = oldtype(value, "utf8")
                elif oldtype == bool:
                    value = str_to_bool[value]
                else:
                    value = oldtype(value)
            except (ValueError, KeyError):
                log.warning("Type '%s' invalid for '%s'", newtype, key)
                raise

        log.debug("Setting '%s' to %s of %s", key, value, type(value))

        self.__config[key] = value
        # Run the set_function for this key if any
        from twisted.internet import reactor
        try:
            for func in self.__set_functions[key]:
                reactor.callLater(0, func, key, value)
        except KeyError:
            pass
        try:

            def do_change_callbacks(key, value):
                for func in self.__change_callbacks:
                    func(key, value)

            reactor.callLater(0, do_change_callbacks, key, value)
        except:
            pass

        # We set the save_timer for 5 seconds if not already set
        if not self._save_timer or not self._save_timer.active():
            self._save_timer = reactor.callLater(5, self.save)
Example #52
0
    def blacklistTorrent(self, i, t, label_str, name):
        hash = t.get_status(['hash'])['hash'].upper()

        if label_str and label_str in self.accepted_labels:
            mediaObject = self.sonarr if label_str == 'tv-sonarr' else self.radarr if label_str == 'radarr' else self.lidarr
        elif not label_str:
            log.warning("No label for {}".format(name))
            return
        else:
            log.warning("Unknown label for torrrent {}".format(name))
            return

        if mediaObject:
            mediaList = mediaObject.get_queue()
            log.debug("Size of media list: {}".format(len(mediaList)))
            if hash in mediaList:
                id = str(mediaList[hash].get('id'))
                log.info("hash: {}, id: {},type = {}".format(
                    hash, id, type(id)))

                #blacklist from PVR
                response = mediaObject.delete_queueitem(id)
                changed = True
                log.info("Blacklist request for torrent {} returned {}".format(
                    name, response))

                isFinished = t.get_status(['is_finished'])['is_finished']
                remove_data = self.config[
                    'seed_remove_data'] if isFinished else self.config[
                        'remove_data']

                #remove from deluge
                result = self.remove_torrent(i, remove_data)
                log.info("Removing {} torrent {} {} data returned: {}".format(
                    'unfinished' if not isFinished else 'finished', name,
                    'with' if remove_data else 'without', result))

                return result
            else:
                log.warning(
                    "Could not blacklist torrent {}: not in server queue: {}".
                    format(name, hash))
                log.debug("List: {}".format(mediaList))

                isFinished = t.get_status(['is_finished'])['is_finished']
                remove_data = self.config[
                    'seed_remove_data'] if isFinished else self.config[
                        'remove_data']

                #remove from deluge
                result = self.remove_torrent(i, remove_data)
                log.info("Removing {} torrent {} {} data. Result: {}".format(
                    'unfinished' if not isFinished else 'finished', name,
                    'with' if remove_data else 'without', result))

                return result
        else:
            log.warning(
                "Upstream server not found for label: {}".format(label_str))
            return
Example #53
0
 def on_select_time(self, widget=None, time=None):
     log.debug("select seed stop time:%s,%s" % (time ,self.get_torrent_ids()) )
     for torrent_id in self.get_torrent_ids():
         client.seedtime.set_torrent(torrent_id, time)
Example #54
0
 def on_apply_prefs(self):
     log.debug("applying prefs for Ratio")
     config = {
         'persistent': self.glade.get_widget("persistent").get_active(),
     }
     client.ratio.set_config(config)
Example #55
0
 def log_failure(failure, action):
     log.error("Encountered error attempting to %s: %s" % \
               (action, failure.getErrorMessage()))
Example #56
0
 def on_reset_ratio_button_clicked(self, widget):
     log.debug('on_reset_ratio_button_clicked')
     client.ratio.reset_ratio()
Example #57
0
    def __update_buttons(self):
        """
        Updates the buttons states.
        """
        if len(self.liststore) == 0:
            # There is nothing in the list
            self.glade.get_widget("button_startdaemon").set_sensitive(True)
            self.glade.get_widget("button_connect").set_sensitive(False)
            self.glade.get_widget("button_removehost").set_sensitive(False)
            self.glade.get_widget("image_startdaemon").set_from_stock(
                gtk.STOCK_EXECUTE, gtk.ICON_SIZE_MENU)
            self.glade.get_widget("label_startdaemon").set_text("_Start Daemon")

        model, row = self.hostlist.get_selection().get_selected()
        if not row:
            return

        # Get some values about the selected host
        status = model[row][HOSTLIST_COL_STATUS]
        host = model[row][HOSTLIST_COL_HOST]

        log.debug("Status: %s", status)
        # Check to see if we have a localhost entry selected
        localhost = False
        if host in ("127.0.0.1", "localhost"):
            localhost = True

        # Make sure buttons are sensitive at start
        self.glade.get_widget("button_startdaemon").set_sensitive(True)
        self.glade.get_widget("button_connect").set_sensitive(True)
        self.glade.get_widget("button_removehost").set_sensitive(True)

        # See if this is the currently connected host
        if status == "Connected":
            # Display a disconnect button if we're connected to this host
            self.glade.get_widget("button_connect").set_label("gtk-disconnect")
            self.glade.get_widget("button_removehost").set_sensitive(False)
        else:
            self.glade.get_widget("button_connect").set_label("gtk-connect")
            if status == "Offline" and not localhost:
                self.glade.get_widget("button_connect").set_sensitive(False)

        # Check to see if the host is online
        if status == "Connected" or status == "Online":
            self.glade.get_widget("image_startdaemon").set_from_stock(
                gtk.STOCK_STOP, gtk.ICON_SIZE_MENU)
            self.glade.get_widget("label_startdaemon").set_text(
                _("_Stop Daemon"))

        # Update the start daemon button if the selected host is localhost
        if localhost and status == "Offline":
            # The localhost is not online
            self.glade.get_widget("image_startdaemon").set_from_stock(
                gtk.STOCK_EXECUTE, gtk.ICON_SIZE_MENU)
            self.glade.get_widget("label_startdaemon").set_text(
                _("_Start Daemon"))

        if not localhost:
            # An offline host
            self.glade.get_widget("button_startdaemon").set_sensitive(False)

        # Make sure label is displayed correctly using mnemonics
        self.glade.get_widget("label_startdaemon").set_use_underline(
            True)
Example #58
0
            options["stop_at_ratio"] = state.stop_at_ratio
            options["stop_ratio"] = state.stop_ratio
            options["remove_at_ratio"] = state.remove_at_ratio
            options["move_completed"] = state.move_completed
            options["move_completed_path"] = state.move_completed_path
            options["add_paused"] = state.paused

            ti = self.get_torrent_info_from_file(
                    os.path.join(get_config_dir(),
                                    "state", state.torrent_id + ".torrent"))
            if ti:
                add_torrent_params["ti"] = ti
            elif state.magnet:
                magnet = state.magnet
            else:
                log.error("Unable to add torrent!")
                return

            # Handle legacy case with storing resume data in individual files
            # for each torrent
            if resume_data is None:
                resume_data = self.legacy_get_resume_data_from_file(state.torrent_id)
                self.legacy_delete_resume_data(state.torrent_id)

            if resume_data:
                add_torrent_params["resume_data"] = resume_data
        else:
            # We have a torrent_info object or magnet uri so we're not loading from state.
            if torrent_info:
                add_torrent_id = str(torrent_info.info_hash())
                # If this torrent id is already in the session, merge any additional trackers.
Example #59
0
 def disable(self):
     log.debug("Disabling Web UI notifications")
Example #60
0
    def __init__(self, args=None):
        component.Component.__init__(self, "ConsoleUI", 2)

        self.batch_write = False

        try:
            locale.setlocale(locale.LC_ALL, '')
            self.encoding = locale.getpreferredencoding()
        except:
            self.encoding = sys.getdefaultencoding()

        log.debug("Using encoding: %s", self.encoding)
        # Load all the commands
        self._commands = load_commands(os.path.join(UI_PATH, 'commands'))

        client.set_disconnect_callback(self.on_client_disconnect)

        # Set the interactive flag to indicate where we should print the output
        self.interactive = True
        if args:
            # Multiple commands split by ";"
            commands = [arg.strip() for arg in ' '.join(args).split(';')]
            self.interactive = False

        # Try to connect to the daemon (localhost by default)
        def on_connect(result):
            def on_started(result):
                if not self.interactive:
                    def on_started(result):
                        def do_command(result, cmd):
                            return self.do_command(cmd)

                        d = defer.succeed(None)
                        # If we have commands, lets process them, then quit.
                        for command in commands:
                            d.addCallback(do_command, command)

                        if "quit" not in commands and "exit" not in commands:
                            d.addCallback(do_command, "quit")

                    # We need to wait for the rpcs in start() to finish before processing
                    # any of the commands.
                    self.started_deferred.addCallback(on_started)
            component.start().addCallback(on_started)

        def on_connect_fail(result):
            if not self.interactive:
                self.do_command('quit')

        connect_cmd = 'connect'
        if not self.interactive:
            if commands[0].startswith(connect_cmd):
                connect_cmd = commands.pop(0)
            elif 'help' in commands:
                self.do_command('help')
                return
        d = self.do_command(connect_cmd)
        d.addCallback(on_connect)
        d.addErrback(on_connect_fail)

        self.coreconfig = CoreConfig()
        if self.interactive and not deluge.common.windows_check():
            # We use the curses.wrapper function to prevent the console from getting
            # messed up if an uncaught exception is experienced.
            import curses.wrapper
            curses.wrapper(self.run)
        elif self.interactive and deluge.common.windows_check():
            print """\nDeluge-console does not run in interactive mode on Windows. \n
Please use commands from the command line, eg:\n
    deluge-console.exe help
    deluge-console.exe info
    deluge-console.exe "add --help"
    deluge-console.exe "add -p c:\\mytorrents c:\\new.torrent"
            """
        else:
            reactor.run()