summaryrefslogtreecommitdiffstats
path: root/deluge/plugins/Label/deluge_label/core.py
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/plugins/Label/deluge_label/core.py')
-rw-r--r--deluge/plugins/Label/deluge_label/core.py351
1 files changed, 351 insertions, 0 deletions
diff --git a/deluge/plugins/Label/deluge_label/core.py b/deluge/plugins/Label/deluge_label/core.py
new file mode 100644
index 0000000..b16156c
--- /dev/null
+++ b/deluge/plugins/Label/deluge_label/core.py
@@ -0,0 +1,351 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
+#
+# Basic plugin template created by:
+# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
+# Copyright (C) 2007-2008 Andrew Resch <andrewresch@gmail.com>
+#
+# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+# the additional special exception to link portions of this program with the OpenSSL library.
+# See LICENSE for more details.
+#
+
+"""
+torrent-label core plugin.
+adds a status field for tracker.
+"""
+from __future__ import unicode_literals
+
+import logging
+import re
+
+import deluge.component as component
+from deluge.configmanager import ConfigManager
+from deluge.core.rpcserver import export
+from deluge.plugins.pluginbase import CorePluginBase
+
+log = logging.getLogger(__name__)
+
+RE_VALID = re.compile(r'[a-z0-9_\-\.]*\Z')
+
+KNOWN_STATES = ['Downloading', 'Seeding', 'Paused', 'Checking', 'Queued', 'Error']
+STATE = 'state'
+TRACKER = 'tracker'
+KEYWORD = 'keyword'
+LABEL = 'label'
+CONFIG_DEFAULTS = {
+ 'torrent_labels': {}, # torrent_id:label_id
+ 'labels': {}, # label_id:{name:value}
+}
+
+CORE_OPTIONS = ['auto_add_trackers']
+
+OPTIONS_DEFAULTS = {
+ 'apply_max': False,
+ 'max_download_speed': -1,
+ 'max_upload_speed': -1,
+ 'max_connections': -1,
+ 'max_upload_slots': -1,
+ 'prioritize_first_last': False,
+ 'apply_queue': False,
+ 'is_auto_managed': False,
+ 'stop_at_ratio': False,
+ 'stop_ratio': 2.0,
+ 'remove_at_ratio': False,
+ 'apply_move_completed': False,
+ 'move_completed': False,
+ 'move_completed_path': '',
+ 'auto_add': False,
+ 'auto_add_trackers': [],
+}
+
+NO_LABEL = 'No Label'
+
+
+def check_input(cond, message):
+ if not cond:
+ raise Exception(message)
+
+
+class Core(CorePluginBase):
+ """
+ self.labels = {label_id:label_options_dict}
+ self.torrent_labels = {torrent_id:label_id}
+ """
+
+ def enable(self):
+ log.info('*** Start Label plugin ***')
+ self.plugin = component.get('CorePluginManager')
+ self.plugin.register_status_field('label', self._status_get_label)
+
+ # __init__
+ core = component.get('Core')
+ self.config = ConfigManager('label.conf', defaults=CONFIG_DEFAULTS)
+ self.core_cfg = ConfigManager('core.conf')
+
+ # reduce typing, assigning some values to self...
+ self.torrents = core.torrentmanager.torrents
+ self.labels = self.config['labels']
+ self.torrent_labels = self.config['torrent_labels']
+
+ self.clean_initial_config()
+
+ component.get('EventManager').register_event_handler(
+ 'TorrentAddedEvent', self.post_torrent_add
+ )
+ component.get('EventManager').register_event_handler(
+ 'TorrentRemovedEvent', self.post_torrent_remove
+ )
+
+ # register tree:
+ component.get('FilterManager').register_tree_field(
+ 'label', self.init_filter_dict
+ )
+
+ log.debug('Label plugin enabled..')
+
+ def disable(self):
+ self.plugin.deregister_status_field('label')
+ component.get('FilterManager').deregister_tree_field('label')
+ component.get('EventManager').deregister_event_handler(
+ 'TorrentAddedEvent', self.post_torrent_add
+ )
+ component.get('EventManager').deregister_event_handler(
+ 'TorrentRemovedEvent', self.post_torrent_remove
+ )
+
+ def update(self):
+ pass
+
+ def init_filter_dict(self):
+ filter_dict = {label: 0 for label in self.labels}
+ filter_dict['All'] = len(self.torrents)
+ return filter_dict
+
+ # Plugin hooks #
+ def post_torrent_add(self, torrent_id, from_state):
+ if from_state:
+ return
+ log.debug('post_torrent_add')
+ torrent = self.torrents[torrent_id]
+
+ for label_id, options in self.labels.items():
+ if options['auto_add']:
+ if self._has_auto_match(torrent, options):
+ self.set_torrent(torrent_id, label_id)
+ return
+
+ def post_torrent_remove(self, torrent_id):
+ log.debug('post_torrent_remove')
+ if torrent_id in self.torrent_labels:
+ del self.torrent_labels[torrent_id]
+
+ # Utils #
+ def clean_config(self):
+ """remove invalid data from config-file"""
+ for torrent_id, label_id in list(self.torrent_labels.items()):
+ if (label_id not in self.labels) or (torrent_id not in self.torrents):
+ log.debug('label: rm %s:%s', torrent_id, label_id)
+ del self.torrent_labels[torrent_id]
+
+ def clean_initial_config(self):
+ """
+ *add any new keys in OPTIONS_DEFAULTS
+ *set all None values to default <-fix development config
+ """
+ log.debug(list(self.labels))
+ for key in self.labels:
+ options = dict(OPTIONS_DEFAULTS)
+ options.update(self.labels[key])
+ self.labels[key] = options
+
+ for label, options in self.labels.items():
+ for key, value in options.items():
+ if value is None:
+ self.labels[label][key] = OPTIONS_DEFAULTS[key]
+
+ def save_config(self):
+ self.clean_config()
+ self.config.save()
+
+ @export
+ def get_labels(self):
+ return sorted(self.labels)
+
+ # Labels:
+ @export
+ def add(self, label_id):
+ """add a label
+ see label_set_options for more options.
+ """
+ label_id = label_id.lower()
+ check_input(
+ RE_VALID.match(label_id), _('Invalid label, valid characters:[a-z0-9_-]')
+ )
+ check_input(label_id, _('Empty Label'))
+ check_input(not (label_id in self.labels), _('Label already exists'))
+
+ self.labels[label_id] = dict(OPTIONS_DEFAULTS)
+ self.config.save()
+
+ @export
+ def remove(self, label_id):
+ """remove a label"""
+ check_input(label_id in self.labels, _('Unknown Label'))
+ del self.labels[label_id]
+ self.clean_config()
+ self.config.save()
+
+ def _set_torrent_options(self, torrent_id, label_id):
+ options = self.labels[label_id]
+ torrent = self.torrents[torrent_id]
+
+ if not options['move_completed_path']:
+ options['move_completed_path'] = '' # no None.
+
+ if options['apply_max']:
+ torrent.set_max_download_speed(options['max_download_speed'])
+ torrent.set_max_upload_speed(options['max_upload_speed'])
+ torrent.set_max_connections(options['max_connections'])
+ torrent.set_max_upload_slots(options['max_upload_slots'])
+ torrent.set_prioritize_first_last_pieces(options['prioritize_first_last'])
+
+ if options['apply_queue']:
+ torrent.set_auto_managed(options['is_auto_managed'])
+ torrent.set_stop_at_ratio(options['stop_at_ratio'])
+ torrent.set_stop_ratio(options['stop_ratio'])
+ torrent.set_remove_at_ratio(options['remove_at_ratio'])
+
+ if options['apply_move_completed']:
+ torrent.set_options(
+ {
+ 'move_completed': options['move_completed'],
+ 'move_completed_path': options['move_completed_path'],
+ }
+ )
+
+ def _unset_torrent_options(self, torrent_id, label_id):
+ options = self.labels[label_id]
+ torrent = self.torrents[torrent_id]
+
+ if options['apply_max']:
+ torrent.set_max_download_speed(
+ self.core_cfg.config['max_download_speed_per_torrent']
+ )
+ torrent.set_max_upload_speed(
+ self.core_cfg.config['max_upload_speed_per_torrent']
+ )
+ torrent.set_max_connections(
+ self.core_cfg.config['max_connections_per_torrent']
+ )
+ torrent.set_max_upload_slots(
+ self.core_cfg.config['max_upload_slots_per_torrent']
+ )
+ torrent.set_prioritize_first_last_pieces(
+ self.core_cfg.config['prioritize_first_last_pieces']
+ )
+
+ if options['apply_queue']:
+ torrent.set_auto_managed(self.core_cfg.config['auto_managed'])
+ torrent.set_stop_at_ratio(self.core_cfg.config['stop_seed_at_ratio'])
+ torrent.set_stop_ratio(self.core_cfg.config['stop_seed_ratio'])
+ torrent.set_remove_at_ratio(self.core_cfg.config['remove_seed_at_ratio'])
+
+ if options['apply_move_completed']:
+ torrent.set_options(
+ {
+ 'move_completed': self.core_cfg.config['move_completed'],
+ 'move_completed_path': self.core_cfg.config['move_completed_path'],
+ }
+ )
+
+ def _has_auto_match(self, torrent, label_options):
+ """match for auto_add fields"""
+ for tracker_match in label_options['auto_add_trackers']:
+ for tracker in torrent.trackers:
+ if tracker_match in tracker['url']:
+ return True
+ return False
+
+ @export
+ def set_options(self, label_id, options_dict):
+ """update the label options
+
+ options_dict :
+ {"max_download_speed":float(),
+ "max_upload_speed":float(),
+ "max_connections":int(),
+ "max_upload_slots":int(),
+ #"prioritize_first_last":bool(),
+ "apply_max":bool(),
+ "move_completed_to":string() or None
+ }
+ """
+ check_input(label_id in self.labels, _('Unknown Label'))
+ for key in options_dict:
+ if key not in OPTIONS_DEFAULTS:
+ raise Exception('label: Invalid options_dict key:%s' % key)
+
+ self.labels[label_id].update(options_dict)
+
+ # apply
+ for torrent_id, label in self.torrent_labels.items():
+ if label_id == label and torrent_id in self.torrents:
+ self._set_torrent_options(torrent_id, label_id)
+
+ # auto add
+ options = self.labels[label_id]
+ if options['auto_add']:
+ for torrent_id, torrent in self.torrents.items():
+ if self._has_auto_match(torrent, options):
+ self.set_torrent(torrent_id, label_id)
+
+ self.config.save()
+
+ @export
+ def get_options(self, label_id):
+ """returns the label options"""
+ return self.labels[label_id]
+
+ @export
+ def set_torrent(self, torrent_id, label_id):
+ """
+ assign a label to a torrent
+ removes a label if the label_id parameter is empty.
+ """
+ if label_id == NO_LABEL:
+ label_id = None
+
+ check_input((not label_id) or (label_id in self.labels), _('Unknown Label'))
+ check_input(torrent_id in self.torrents, _('Unknown Torrent'))
+
+ if torrent_id in self.torrent_labels:
+ self._unset_torrent_options(torrent_id, self.torrent_labels[torrent_id])
+ del self.torrent_labels[torrent_id]
+ self.clean_config()
+ if label_id:
+ self.torrent_labels[torrent_id] = label_id
+ self._set_torrent_options(torrent_id, label_id)
+
+ self.config.save()
+
+ @export
+ def get_config(self):
+ """see : label_set_config"""
+ return {
+ key: self.config[key] for key in CORE_OPTIONS if key in self.config.config
+ }
+
+ @export
+ def set_config(self, options):
+ """global_options:"""
+ if options:
+ for key, value in options.items:
+ if key in CORE_OPTIONS:
+ self.config[key] = value
+
+ self.config.save()
+
+ def _status_get_label(self, torrent_id):
+ return self.torrent_labels.get(torrent_id) or ''