source: deluge/core/core.py@ e6498b

2.0.x develop
Last change on this file since e6498b was e6498b, checked in by Calum Lind <calumlind+deluge@gmail.com>, 12 years ago

Fix #2277 : Plugins keys weren't fetched in filter_torrent_ids

Fixed bug introduced in 8c106ce8c4c0794ddd63e8e8f98b097221a56a52
where keys for plugins weren't fetched in filter_torrent_ids.

  • Property mode set to 100644
File size: 32.3 KB
Line 
1#
2# core.py
3#
4# Copyright (C) 2007-2009 Andrew Resch <andrewresch@gmail.com>
5# Copyright (C) 2011 Pedro Algarvio <pedro@algarvio.me>
6#
7# Deluge is free software.
8#
9# You may redistribute it and/or modify it under the terms of the
10# GNU General Public License, as published by the Free Software
11# Foundation; either version 3 of the License, or (at your option)
12# any later version.
13#
14# deluge is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17# See the GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with deluge. If not, write to:
21# The Free Software Foundation, Inc.,
22# 51 Franklin Street, Fifth Floor
23# Boston, MA 02110-1301, USA.
24#
25# In addition, as a special exception, the copyright holders give
26# permission to link the code of portions of this program with the OpenSSL
27# library.
28# You must obey the GNU General Public License in all respects for all of
29# the code used other than OpenSSL. If you modify file(s) with this
30# exception, you may extend this exception to your version of the file(s),
31# but you are not obligated to do so. If you do not wish to do so, delete
32# this exception statement from your version. If you delete this exception
33# statement from all source files in the program, then also delete it here.
34#
35#
36
37from deluge._libtorrent import lt
38
39import os
40import glob
41import base64
42import logging
43import threading
44import tempfile
45from urlparse import urljoin
46
47import twisted.web.client
48import twisted.web.error
49
50from deluge.httpdownloader import download_file
51
52import deluge.configmanager
53import deluge.common
54import deluge.component as component
55from deluge.event import *
56from deluge.error import *
57from deluge.core.authmanager import AUTH_LEVEL_ADMIN, AUTH_LEVEL_NONE
58from deluge.core.authmanager import AUTH_LEVELS_MAPPING, AUTH_LEVELS_MAPPING_REVERSE
59from deluge.core.torrentmanager import TorrentManager
60from deluge.core.pluginmanager import PluginManager
61from deluge.core.alertmanager import AlertManager
62from deluge.core.filtermanager import FilterManager
63from deluge.core.preferencesmanager import PreferencesManager
64from deluge.core.authmanager import AuthManager
65from deluge.core.eventmanager import EventManager
66from deluge.core.rpcserver import export
67
68log = logging.getLogger(__name__)
69
70class Core(component.Component):
71 def __init__(self, listen_interface=None):
72 log.debug("Core init..")
73 component.Component.__init__(self, "Core")
74
75 # Start the libtorrent session
76 log.info("Starting libtorrent %s session..", lt.version)
77
78 # Create the client fingerprint
79 version = deluge.common.VersionSplit(deluge.common.get_version()).version
80 while len(version) < 4:
81 version.append(0)
82
83 self.session = lt.session(lt.fingerprint("DE", *version), flags=0)
84
85 # Load the session state if available
86 self.__load_session_state()
87
88 # Set the user agent
89 self.settings = lt.session_settings()
90 self.settings.user_agent = "Deluge/%(deluge_version)s Libtorrent/%(lt_version)s" % \
91 { 'deluge_version': deluge.common.get_version(),
92 'lt_version': self.get_libtorrent_version().rpartition(".")[0] }
93 # Increase the alert queue size so that alerts don't get lost
94 self.settings.alert_queue_size = 10000
95
96 # Set session settings
97 self.settings.send_redundant_have = True
98 if deluge.common.windows_check():
99 self.settings.disk_io_write_mode = \
100 lt.io_buffer_mode_t.disable_os_cache
101 self.settings.disk_io_read_mode = \
102 lt.io_buffer_mode_t.disable_os_cache
103 self.session.set_settings(self.settings)
104
105 self.session.add_extension("metadata_transfer")
106 self.session.add_extension("ut_metadata")
107 self.session.add_extension("smart_ban")
108
109 # Create the components
110 self.eventmanager = EventManager()
111 self.preferencesmanager = PreferencesManager()
112 self.alertmanager = AlertManager()
113 self.pluginmanager = PluginManager(self)
114 self.torrentmanager = TorrentManager()
115 self.filtermanager = FilterManager(self)
116 self.authmanager = AuthManager()
117
118 # New release check information
119 self.new_release = None
120
121 # Get the core config
122 self.config = deluge.configmanager.ConfigManager("core.conf")
123 self.config.save()
124
125 # If there was an interface value from the command line, use it, but
126 # store the one in the config so we can restore it on shutdown
127 self.__old_interface = None
128 if listen_interface:
129 self.__old_interface = self.config["listen_interface"]
130 self.config["listen_interface"] = listen_interface
131
132 def start(self):
133 """Starts the core"""
134 # New release check information
135 self.__new_release = None
136
137 def stop(self):
138 log.debug("Core stopping...")
139
140 # Save the DHT state if necessary
141 if self.config["dht"]:
142 self.save_dht_state()
143
144 # Save the libtorrent session state
145 self.__save_session_state()
146
147 # We stored a copy of the old interface value
148 if self.__old_interface:
149 self.config["listen_interface"] = self.__old_interface
150
151 # Make sure the config file has been saved
152 self.config.save()
153
154 def shutdown(self):
155 pass
156
157 def __save_session_state(self):
158 """Saves the libtorrent session state"""
159 try:
160 session_state = deluge.configmanager.get_config_dir("session.state")
161 open(session_state, "wb").write(lt.bencode(self.session.save_state()))
162 except Exception, e:
163 log.warning("Failed to save lt state: %s", e)
164
165 def __load_session_state(self):
166 """Loads the libtorrent session state"""
167 try:
168 session_state = deluge.configmanager.get_config_dir("session.state")
169 self.session.load_state(lt.bdecode(open(session_state, "rb").read()))
170 except Exception, e:
171 log.warning("Failed to load lt state: %s", e)
172
173 def save_dht_state(self):
174 """Saves the dht state to a file"""
175 try:
176 dht_data = open(deluge.configmanager.get_config_dir("dht.state"), "wb")
177 dht_data.write(lt.bencode(self.session.dht_state()))
178 dht_data.close()
179 except Exception, e:
180 log.warning("Failed to save dht state: %s", e)
181
182 def get_new_release(self):
183 log.debug("get_new_release")
184 from urllib2 import urlopen
185 try:
186 self.new_release = urlopen(
187 "http://download.deluge-torrent.org/version-1.0").read().strip()
188 except Exception, e:
189 log.debug("Unable to get release info from website: %s", e)
190 return
191 self.check_new_release()
192
193 def check_new_release(self):
194 if self.new_release:
195 log.debug("new_release: %s", self.new_release)
196 if deluge.common.VersionSplit(self.new_release) > deluge.common.VersionSplit(deluge.common.get_version()):
197 component.get("EventManager").emit(NewVersionAvailableEvent(self.new_release))
198 return self.new_release
199 return False
200
201 # Exported Methods
202 @export
203 def add_torrent_file(self, filename, filedump, options):
204 """
205 Adds a torrent file to the session.
206
207 :param filename: the filename of the torrent
208 :type filename: string
209 :param filedump: a base64 encoded string of the torrent file contents
210 :type filedump: string
211 :param options: the options to apply to the torrent on add
212 :type options: dict
213
214 :returns: the torrent_id as a str or None
215 :rtype: string
216
217 """
218 try:
219 filedump = base64.decodestring(filedump)
220 except Exception, e:
221 log.error("There was an error decoding the filedump string!")
222 log.exception(e)
223
224 try:
225 torrent_id = self.torrentmanager.add(
226 filedump=filedump, options=options, filename=filename
227 )
228 except Exception, e:
229 log.error("There was an error adding the torrent file %s", filename)
230 log.exception(e)
231 torrent_id = None
232
233 return torrent_id
234
235 @export
236 def add_torrent_url(self, url, options, headers=None):
237 """
238 Adds a torrent from a url. Deluge will attempt to fetch the torrent
239 from url prior to adding it to the session.
240
241 :param url: the url pointing to the torrent file
242 :type url: string
243 :param options: the options to apply to the torrent on add
244 :type options: dict
245 :param headers: any optional headers to send
246 :type headers: dict
247
248 :returns: a Deferred which returns the torrent_id as a str or None
249 """
250 log.info("Attempting to add url %s", url)
251 def on_download_success(filename):
252 # We got the file, so add it to the session
253 f = open(filename, "rb")
254 data = f.read()
255 f.close()
256 try:
257 os.remove(filename)
258 except Exception, e:
259 log.warning("Couldn't remove temp file: %s", e)
260 return self.add_torrent_file(
261 filename, base64.encodestring(data), options
262 )
263
264 def on_download_fail(failure):
265 if failure.check(twisted.web.error.PageRedirect):
266 new_url = urljoin(url, failure.getErrorMessage().split(" to ")[1])
267 result = download_file(
268 new_url, tempfile.mkstemp()[1], headers=headers,
269 force_filename=True
270 )
271 result.addCallbacks(on_download_success, on_download_fail)
272 elif failure.check(twisted.web.client.PartialDownloadError):
273 result = download_file(
274 url, tempfile.mkstemp()[1], headers=headers,
275 force_filename=True, allow_compression=False
276 )
277 result.addCallbacks(on_download_success, on_download_fail)
278 else:
279 # Log the error and pass the failure onto the client
280 log.error("Error occured downloading torrent from %s", url)
281 log.error("Reason: %s", failure.getErrorMessage())
282 result = failure
283 return result
284
285 d = download_file(
286 url, tempfile.mkstemp()[1], headers=headers, force_filename=True
287 )
288 d.addCallbacks(on_download_success, on_download_fail)
289 return d
290
291 @export
292 def add_torrent_magnet(self, uri, options):
293 """
294 Adds a torrent from a magnet link.
295
296 :param uri: the magnet link
297 :type uri: string
298 :param options: the options to apply to the torrent on add
299 :type options: dict
300
301 :returns: the torrent_id
302 :rtype: string
303
304 """
305 log.debug("Attempting to add by magnet uri: %s", uri)
306
307 return self.torrentmanager.add(magnet=uri, options=options)
308
309 @export
310 def remove_torrent(self, torrent_id, remove_data):
311 """
312 Removes a torrent from the session.
313
314 :param torrent_id: the torrent_id of the torrent to remove
315 :type torrent_id: string
316 :param remove_data: if True, remove the data associated with this torrent
317 :type remove_data: boolean
318 :returns: True if removed successfully
319 :rtype: bool
320
321 :raises InvalidTorrentError: if the torrent_id does not exist in the session
322
323 """
324 log.debug("Removing torrent %s from the core.", torrent_id)
325 return self.torrentmanager.remove(torrent_id, remove_data)
326
327 @export
328 def get_session_status(self, keys):
329 """
330 Gets the session status values for 'keys', these keys are taking
331 from libtorrent's session status.
332
333 See: http://www.rasterbar.com/products/libtorrent/manual.html#status
334
335 :param keys: the keys for which we want values
336 :type keys: list
337 :returns: a dictionary of {key: value, ...}
338 :rtype: dict
339
340 """
341 status = {}
342 session_status = self.session.status()
343 for key in keys:
344 status[key] = getattr(session_status, key)
345
346 return status
347
348 @export
349 def get_cache_status(self):
350 """
351 Returns a dictionary of the session's cache status.
352
353 :returns: the cache status
354 :rtype: dict
355
356 """
357
358 status = self.session.get_cache_status()
359 cache = {}
360 for attr in dir(status):
361 if attr.startswith("_"):
362 continue
363 cache[attr] = getattr(status, attr)
364
365 # Add in a couple ratios
366 try:
367 cache["write_hit_ratio"] = float((cache["blocks_written"] - cache["writes"])) / float(cache["blocks_written"])
368 except ZeroDivisionError:
369 cache["write_hit_ratio"] = 0.0
370
371 try:
372 cache["read_hit_ratio"] = float(cache["blocks_read_hit"]) / float(cache["blocks_read"])
373 except ZeroDivisionError:
374 cache["read_hit_ratio"] = 0.0
375
376 return cache
377
378 @export
379 def force_reannounce(self, torrent_ids):
380 log.debug("Forcing reannouncment to: %s", torrent_ids)
381 for torrent_id in torrent_ids:
382 self.torrentmanager[torrent_id].force_reannounce()
383
384 @export
385 def pause_torrent(self, torrent_ids):
386 log.debug("Pausing: %s", torrent_ids)
387 for torrent_id in torrent_ids:
388 if not self.torrentmanager[torrent_id].pause():
389 log.warning("Error pausing torrent %s", torrent_id)
390
391 @export
392 def connect_peer(self, torrent_id, ip, port):
393 log.debug("adding peer %s to %s", ip, torrent_id)
394 if not self.torrentmanager[torrent_id].connect_peer(ip, port):
395 log.warning("Error adding peer %s:%s to %s", ip, port, torrent_id)
396
397 @export
398 def move_storage(self, torrent_ids, dest):
399 log.debug("Moving storage %s to %s", torrent_ids, dest)
400 for torrent_id in torrent_ids:
401 if not self.torrentmanager[torrent_id].move_storage(dest):
402 log.warning("Error moving torrent %s to %s", torrent_id, dest)
403
404 @export
405 def pause_all_torrents(self):
406 """Pause all torrents in the session"""
407 for torrent in self.torrentmanager.torrents.values():
408 torrent.pause()
409
410 @export
411 def resume_all_torrents(self):
412 """Resume all torrents in the session"""
413 for torrent in self.torrentmanager.torrents.values():
414 torrent.resume()
415 component.get("EventManager").emit(SessionResumedEvent())
416
417 @export
418 def resume_torrent(self, torrent_ids):
419 log.debug("Resuming: %s", torrent_ids)
420 for torrent_id in torrent_ids:
421 self.torrentmanager[torrent_id].resume()
422
423 def create_torrent_status(self, torrent_id, torrent_keys, plugin_keys, diff=False, update=False, all_keys=False):
424 try:
425 status = self.torrentmanager[torrent_id].get_status(torrent_keys, diff, update=update, all_keys=all_keys)
426 except KeyError:
427 import traceback
428 traceback.print_exc()
429 # Torrent was probaly removed meanwhile
430 return {}
431
432 # Ask the plugin manager to fill in the plugin keys
433 if len(plugin_keys) > 0:
434 status.update(self.pluginmanager.get_status(torrent_id, plugin_keys))
435 return status
436
437 @export
438 def get_torrent_status(self, torrent_id, keys, diff=False):
439 torrent_keys, plugin_keys = self.torrentmanager.separate_keys(keys, [torrent_id])
440 return self.create_torrent_status(torrent_id, torrent_keys, plugin_keys, diff=diff, update=True, all_keys=not keys)
441
442 @export
443 def get_torrents_status(self, filter_dict, keys, diff=False):
444 """
445 returns all torrents , optionally filtered by filter_dict.
446 """
447 torrent_ids = self.filtermanager.filter_torrent_ids(filter_dict)
448 status_dict = {}.fromkeys(torrent_ids)
449 d = self.torrentmanager.torrents_status_update(torrent_ids, keys, diff=diff)
450
451 def add_plugin_fields(args):
452 status_dict, plugin_keys = args
453 # Ask the plugin manager to fill in the plugin keys
454 if len(plugin_keys) > 0:
455 for key in status_dict.keys():
456 status_dict[key].update(self.pluginmanager.get_status(key, plugin_keys))
457 return status_dict
458 d.addCallback(add_plugin_fields)
459 return d
460
461 @export
462 def get_filter_tree(self , show_zero_hits=True, hide_cat=None):
463 """
464 returns {field: [(value,count)] }
465 for use in sidebar(s)
466 """
467 return self.filtermanager.get_filter_tree(show_zero_hits, hide_cat)
468
469 @export
470 def get_session_state(self):
471 """Returns a list of torrent_ids in the session."""
472 # Get the torrent list from the TorrentManager
473 return self.torrentmanager.get_torrent_list()
474
475 @export
476 def get_config(self):
477 """Get all the preferences as a dictionary"""
478 return self.config.config
479
480 @export
481 def get_config_value(self, key):
482 """Get the config value for key"""
483 try:
484 value = self.config[key]
485 except KeyError:
486 return None
487
488 return value
489
490 @export
491 def get_config_values(self, keys):
492 """Get the config values for the entered keys"""
493 config = {}
494 for key in keys:
495 try:
496 config[key] = self.config[key]
497 except KeyError:
498 pass
499 return config
500
501 @export
502 def set_config(self, config):
503 """Set the config with values from dictionary"""
504 # Load all the values into the configuration
505 for key in config.keys():
506 if isinstance(config[key], basestring):
507 config[key] = config[key].encode("utf8")
508 self.config[key] = config[key]
509
510 @export
511 def get_listen_port(self):
512 """Returns the active listen port"""
513 return self.session.listen_port()
514
515 @export
516 def get_num_connections(self):
517 """Returns the current number of connections"""
518 return self.session.num_connections()
519
520 @export
521 def get_available_plugins(self):
522 """Returns a list of plugins available in the core"""
523 return self.pluginmanager.get_available_plugins()
524
525 @export
526 def get_enabled_plugins(self):
527 """Returns a list of enabled plugins in the core"""
528 return self.pluginmanager.get_enabled_plugins()
529
530 @export
531 def enable_plugin(self, plugin):
532 self.pluginmanager.enable_plugin(plugin)
533 return None
534
535 @export
536 def disable_plugin(self, plugin):
537 self.pluginmanager.disable_plugin(plugin)
538 return None
539
540 @export
541 def force_recheck(self, torrent_ids):
542 """Forces a data recheck on torrent_ids"""
543 for torrent_id in torrent_ids:
544 self.torrentmanager[torrent_id].force_recheck()
545
546 @export
547 def set_torrent_options(self, torrent_ids, options):
548 """Sets the torrent options for torrent_ids"""
549 for torrent_id in torrent_ids:
550 self.torrentmanager[torrent_id].set_options(options)
551
552 @export
553 def set_torrent_trackers(self, torrent_id, trackers):
554 """Sets a torrents tracker list. trackers will be [{"url", "tier"}]"""
555 return self.torrentmanager[torrent_id].set_trackers(trackers)
556
557 @export
558 def set_torrent_max_connections(self, torrent_id, value):
559 """Sets a torrents max number of connections"""
560 return self.torrentmanager[torrent_id].set_max_connections(value)
561
562 @export
563 def set_torrent_max_upload_slots(self, torrent_id, value):
564 """Sets a torrents max number of upload slots"""
565 return self.torrentmanager[torrent_id].set_max_upload_slots(value)
566
567 @export
568 def set_torrent_max_upload_speed(self, torrent_id, value):
569 """Sets a torrents max upload speed"""
570 return self.torrentmanager[torrent_id].set_max_upload_speed(value)
571
572 @export
573 def set_torrent_max_download_speed(self, torrent_id, value):
574 """Sets a torrents max download speed"""
575 return self.torrentmanager[torrent_id].set_max_download_speed(value)
576
577 @export
578 def set_torrent_file_priorities(self, torrent_id, priorities):
579 """Sets a torrents file priorities"""
580 return self.torrentmanager[torrent_id].set_file_priorities(priorities)
581
582 @export
583 def set_torrent_prioritize_first_last(self, torrent_id, value):
584 """Sets a higher priority to the first and last pieces"""
585 return self.torrentmanager[torrent_id].set_prioritize_first_last(value)
586
587 @export
588 def set_torrent_sequential_download(self, torrent_id, value):
589 """Toggle sequencial pieces download"""
590 return self.torrentmanager[torrent_id].set_sequential_download(value)
591
592 @export
593 def set_torrent_auto_managed(self, torrent_id, value):
594 """Sets the auto managed flag for queueing purposes"""
595 return self.torrentmanager[torrent_id].set_auto_managed(value)
596
597 @export
598 def set_torrent_stop_at_ratio(self, torrent_id, value):
599 """Sets the torrent to stop at 'stop_ratio'"""
600 return self.torrentmanager[torrent_id].set_stop_at_ratio(value)
601
602 @export
603 def set_torrent_stop_ratio(self, torrent_id, value):
604 """Sets the ratio when to stop a torrent if 'stop_at_ratio' is set"""
605 return self.torrentmanager[torrent_id].set_stop_ratio(value)
606
607 @export
608 def set_torrent_remove_at_ratio(self, torrent_id, value):
609 """Sets the torrent to be removed at 'stop_ratio'"""
610 return self.torrentmanager[torrent_id].set_remove_at_ratio(value)
611
612 @export
613 def set_torrent_move_completed(self, torrent_id, value):
614 """Sets the torrent to be moved when completed"""
615 return self.torrentmanager[torrent_id].set_move_completed(value)
616
617 @export
618 def set_torrent_move_completed_path(self, torrent_id, value):
619 """Sets the path for the torrent to be moved when completed"""
620 return self.torrentmanager[torrent_id].set_move_completed_path(value)
621
622 @export(AUTH_LEVEL_ADMIN)
623 def set_torrents_owner(self, torrent_ids, username):
624 """Set's the torrent owner.
625
626 :param torrent_id: the torrent_id of the torrent to remove
627 :type torrent_id: string
628 :param username: the new owner username
629 :type username: string
630
631 :raises DelugeError: if the username is not known
632 """
633 if not self.authmanager.has_account(username):
634 raise DelugeError("Username \"%s\" is not known." % username)
635 if isinstance(torrent_ids, basestring):
636 torrent_ids = [torrent_ids]
637 for torrent_id in torrent_ids:
638 self.torrentmanager[torrent_id].set_owner(username)
639 return None
640
641 @export
642 def set_torrents_shared(self, torrent_ids, shared):
643 if isinstance(torrent_ids, basestring):
644 torrent_ids = [torrent_ids]
645 for torrent_id in torrent_ids:
646 self.torrentmanager[torrent_id].set_options({"shared": shared})
647
648 @export
649 def get_path_size(self, path):
650 """Returns the size of the file or folder 'path' and -1 if the path is
651 unaccessible (non-existent or insufficient privs)"""
652 return deluge.common.get_path_size(path)
653
654 @export
655 def create_torrent(self, path, tracker, piece_length, comment, target,
656 webseeds, private, created_by, trackers, add_to_session):
657
658 log.debug("creating torrent..")
659 threading.Thread(target=self._create_torrent_thread,
660 args=(
661 path,
662 tracker,
663 piece_length,
664 comment,
665 target,
666 webseeds,
667 private,
668 created_by,
669 trackers,
670 add_to_session)).start()
671
672 def _create_torrent_thread(self, path, tracker, piece_length, comment, target,
673 webseeds, private, created_by, trackers, add_to_session):
674 import deluge.metafile
675 deluge.metafile.make_meta_file(
676 path,
677 tracker,
678 piece_length,
679 comment=comment,
680 target=target,
681 webseeds=webseeds,
682 private=private,
683 created_by=created_by,
684 trackers=trackers)
685 log.debug("torrent created!")
686 if add_to_session:
687 options = {}
688 options["download_location"] = os.path.split(path)[0]
689 self.add_torrent_file(os.path.split(target)[1], open(target, "rb").read(), options)
690
691 @export
692 def upload_plugin(self, filename, filedump):
693 """This method is used to upload new plugins to the daemon. It is used
694 when connecting to the daemon remotely and installing a new plugin on
695 the client side. 'plugin_data' is a xmlrpc.Binary object of the file data,
696 ie, plugin_file.read()"""
697
698 try:
699 filedump = base64.decodestring(filedump)
700 except Exception, e:
701 log.error("There was an error decoding the filedump string!")
702 log.exception(e)
703 return
704
705 f = open(os.path.join(deluge.configmanager.get_config_dir(), "plugins", filename), "wb")
706 f.write(filedump)
707 f.close()
708 component.get("CorePluginManager").scan_for_plugins()
709
710 @export
711 def rescan_plugins(self):
712 """
713 Rescans the plugin folders for new plugins
714 """
715 component.get("CorePluginManager").scan_for_plugins()
716
717 @export
718 def rename_files(self, torrent_id, filenames):
719 """
720 Rename files in torrent_id. Since this is an asynchronous operation by
721 libtorrent, watch for the TorrentFileRenamedEvent to know when the
722 files have been renamed.
723
724 :param torrent_id: the torrent_id to rename files
725 :type torrent_id: string
726 :param filenames: a list of index, filename pairs
727 :type filenames: ((index, filename), ...)
728
729 :raises InvalidTorrentError: if torrent_id is invalid
730
731 """
732 if torrent_id not in self.torrentmanager.torrents:
733 raise InvalidTorrentError("torrent_id is not in session")
734
735 self.torrentmanager[torrent_id].rename_files(filenames)
736
737 @export
738 def rename_folder(self, torrent_id, folder, new_folder):
739 """
740 Renames the 'folder' to 'new_folder' in 'torrent_id'. Watch for the
741 TorrentFolderRenamedEvent which is emitted when the folder has been
742 renamed successfully.
743
744 :param torrent_id: the torrent to rename folder in
745 :type torrent_id: string
746 :param folder: the folder to rename
747 :type folder: string
748 :param new_folder: the new folder name
749 :type new_folder: string
750
751 :raises InvalidTorrentError: if the torrent_id is invalid
752
753 """
754 if torrent_id not in self.torrentmanager.torrents:
755 raise InvalidTorrentError("torrent_id is not in session")
756
757 self.torrentmanager[torrent_id].rename_folder(folder, new_folder)
758
759 @export
760 def queue_top(self, torrent_ids):
761 log.debug("Attempting to queue %s to top", torrent_ids)
762 # torrent_ids must be sorted in reverse before moving to preserve order
763 for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position, reverse=True):
764 try:
765 # If the queue method returns True, then we should emit a signal
766 if self.torrentmanager.queue_top(torrent_id):
767 component.get("EventManager").emit(TorrentQueueChangedEvent())
768 except KeyError:
769 log.warning("torrent_id: %s does not exist in the queue", torrent_id)
770
771 @export
772 def queue_up(self, torrent_ids):
773 log.debug("Attempting to queue %s to up", torrent_ids)
774 torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids)
775 torrent_moved = True
776 prev_queue_position = None
777 #torrent_ids must be sorted before moving.
778 for queue_position, torrent_id in sorted(torrents):
779 # Move the torrent if and only if there is space (by not moving it we preserve the order)
780 if torrent_moved or queue_position - prev_queue_position > 1:
781 try:
782 torrent_moved = self.torrentmanager.queue_up(torrent_id)
783 except KeyError:
784 log.warning("torrent_id: %s does not exist in the queue", torrent_id)
785 # If the torrent moved, then we should emit a signal
786 if torrent_moved:
787 component.get("EventManager").emit(TorrentQueueChangedEvent())
788 else:
789 prev_queue_position = queue_position
790
791 @export
792 def queue_down(self, torrent_ids):
793 log.debug("Attempting to queue %s to down", torrent_ids)
794 torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids)
795 torrent_moved = True
796 prev_queue_position = None
797 #torrent_ids must be sorted before moving.
798 for queue_position, torrent_id in sorted(torrents, reverse=True):
799 # Move the torrent if and only if there is space (by not moving it we preserve the order)
800 if torrent_moved or prev_queue_position - queue_position > 1:
801 try:
802 torrent_moved = self.torrentmanager.queue_down(torrent_id)
803 except KeyError:
804 log.warning("torrent_id: %s does not exist in the queue", torrent_id)
805 # If the torrent moved, then we should emit a signal
806 if torrent_moved:
807 component.get("EventManager").emit(TorrentQueueChangedEvent())
808 else:
809 prev_queue_position = queue_position
810
811 @export
812 def queue_bottom(self, torrent_ids):
813 log.debug("Attempting to queue %s to bottom", torrent_ids)
814 # torrent_ids must be sorted before moving to preserve order
815 for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position):
816 try:
817 # If the queue method returns True, then we should emit a signal
818 if self.torrentmanager.queue_bottom(torrent_id):
819 component.get("EventManager").emit(TorrentQueueChangedEvent())
820 except KeyError:
821 log.warning("torrent_id: %s does not exist in the queue", torrent_id)
822
823 @export
824 def glob(self, path):
825 return glob.glob(path)
826
827 @export
828 def test_listen_port(self):
829 """
830 Checks if the active port is open
831
832 :returns: True if the port is open, False if not
833 :rtype: bool
834
835 """
836 from twisted.web.client import getPage
837
838 d = getPage("http://deluge-torrent.org/test_port.php?port=%s" %
839 self.get_listen_port(), timeout=30)
840
841 def on_get_page(result):
842 return bool(int(result))
843
844 def logError(failure):
845 log.warning("Error testing listen port: %s", failure)
846
847 d.addCallback(on_get_page)
848 d.addErrback(logError)
849
850 return d
851
852 @export
853 def get_free_space(self, path=None):
854 """
855 Returns the number of free bytes at path
856
857 :param path: the path to check free space at, if None, use the default
858 download location
859 :type path: string
860
861 :returns: the number of free bytes at path
862 :rtype: int
863
864 :raises InvalidPathError: if the path is invalid
865
866 """
867 if not path:
868 path = self.config["download_location"]
869 try:
870 return deluge.common.free_space(path)
871 except InvalidPathError:
872 return 0
873
874 @export
875 def get_libtorrent_version(self):
876 """
877 Returns the libtorrent version.
878
879 :returns: the version
880 :rtype: string
881
882 """
883 return lt.version
884
885 @export(AUTH_LEVEL_ADMIN)
886 def get_known_accounts(self):
887 return self.authmanager.get_known_accounts()
888
889 @export(AUTH_LEVEL_NONE)
890 def get_auth_levels_mappings(self):
891 return (AUTH_LEVELS_MAPPING, AUTH_LEVELS_MAPPING_REVERSE)
892
893 @export(AUTH_LEVEL_ADMIN)
894 def create_account(self, username, password, authlevel):
895 return self.authmanager.create_account(username, password, authlevel)
896
897 @export(AUTH_LEVEL_ADMIN)
898 def update_account(self, username, password, authlevel):
899 return self.authmanager.update_account(username, password, authlevel)
900
901 @export(AUTH_LEVEL_ADMIN)
902 def remove_account(self, username):
903 return self.authmanager.remove_account(username)
Note: See TracBrowser for help on using the repository browser.