def on_button_edithost_clicked(self, widget=None): log.debug('on_button_edithost_clicked') model, row = self.treeview.get_selection().get_selected() status = model[row][HOSTLIST_COL_STATUS] host_id = model[row][HOSTLIST_COL_ID] if status == 'Connected': def on_disconnect(reason): self._update_host_status() client.disconnect().addCallback(on_disconnect) return host_info = [ self.liststore[row][HOSTLIST_COL_HOST], self.liststore[row][HOSTLIST_COL_PORT], self.liststore[row][HOSTLIST_COL_USER], self.liststore[row][HOSTLIST_COL_PASS]] new_host_info = self._run_addhost_dialog(edit_host_info=host_info) if new_host_info: hostname, port, username, password = new_host_info try: self.hostlist.update_host(host_id, hostname, port, username, password) except ValueError as ex: ErrorDialog(_('Error Updating Host'), ex).run() else: self.liststore[row] = host_id, hostname, port, username, password, '', '' self._update_host_status()
def handle(self, host="127.0.0.1:58846", username="", password="", **options): self.console = component.get("ConsoleUI") try: host, port = host.split(":") except ValueError: port = 58846 else: port = int(port) def do_connect(): d = client.connect(host, port, username, password) def on_connect(result): self.console.write("{!success!}Connected to %s:%s!" % (host, port)) component.start() def on_connect_fail(result): self.console.write("{!error!}Failed to connect to %s:%s with reason: %s" % (host, port, result.value.args[0])) d.addCallback(on_connect) d.addErrback(on_connect_fail) return d if client.connected(): def on_disconnect(result): do_connect() client.disconnect().addCallback(on_disconnect) else: do_connect()
def on_get_torrents_status(torrents): config_path = os.path.expanduser(config.get('config_path', '')) for hash, torrent_dict in torrents.items(): # Make sure it has a url so no plugins crash entry = Entry(deluge_id=hash, url='') if config_path: torrent_path = os.path.join(config_path, 'state', hash + '.torrent') if os.path.isfile(torrent_path): entry['location'] = torrent_path if not torrent_path.startswith('/'): torrent_path = '/' + torrent_path entry['url'] = 'file://' + torrent_path else: log.warning('Did not find torrent file at %s' % torrent_path) for key, value in torrent_dict.items(): if key in self.settings_map: flexget_key = self.settings_map[key] else: flexget_key = self.extra_settings_map[key] if isinstance(flexget_key, tuple): flexget_key, format_func = flexget_key value = format_func(value) entry[flexget_key] = value self.entries.append(entry) client.disconnect()
def on_torrents_status(result): """ Callback for the torrent_status() method. This method contains the actual ratio checking and is_finished. Once the list has been compiled the method defined in `cb_method` is called. """ torrent_filelist = [] for torrent_id, status in result.items(): # Meh, float should be fine for this. Not mission critical. # We're going to ignore anything that hasn't either met our # ratio or is not yet finished. if float(ratio) > float(status['ratio']) \ or status['is_finished'] is False: for f in status['files']: torrent_filelist.append(os.path.join(status['save_path'], f['path'])) client.disconnect() reactor.stop() # Catch system exits and ignore them. try: cb_method(path, ignore_filelist=torrent_filelist) except exceptions.SystemExit: pass
def on_button_connect_clicked(self, widget=None): model, row = self.hostlist.get_selection().get_selected() if not row: return status = model[row][HOSTLIST_COL_STATUS] if status == _("Connected"): def on_disconnect(reason): self.__update_list() client.disconnect().addCallback(on_disconnect) return host_id = model[row][HOSTLIST_COL_ID] host = model[row][HOSTLIST_COL_HOST] port = model[row][HOSTLIST_COL_PORT] user = model[row][HOSTLIST_COL_USER] password = model[row][HOSTLIST_COL_PASS] if status == _("Offline") and \ self.builder.get_object("chk_autostart").get_active() and \ host in ("127.0.0.1", "localhost"): if not self.start_daemon(port, deluge.configmanager.get_config_dir()): log.debug("Failed to auto-start daemon") return return self.__connect( host_id, host, port, user, password, try_counter=6 ) return self.__connect(host_id, host, port, user, password)
def quit(self, shutdown=False): """ Quits the GtkUI :param shutdown: whether or not to shutdown the daemon as well :type shutdown: boolean """ if shutdown: def on_daemon_shutdown(result): try: reactor.stop() except ReactorNotRunning: log.debug("Attempted to stop the reactor but it is not running...") client.daemon.shutdown().addCallback(on_daemon_shutdown) return if client.is_classicmode(): reactor.stop() return if not client.connected(): reactor.stop() return def on_client_disconnected(result): reactor.stop() client.disconnect().addCallback(on_client_disconnected)
def endSession(esresult): if esresult: log.info(esresult) reactor.stop() else: client.disconnect() printSuccess(None, False, "Client disconnected.") reactor.stop()
def on_done(value, message): global finished_count finished_count += 1 print "finished_count %d out of %d" % (finished_count, method_count) stderr_print(message) if finished_count == method_count: client.disconnect() reactor.stop()
def disable(self): client.deregister_event_handler('PluginEnabledEvent', self._json.get_remote_methods) client.deregister_event_handler('PluginDisabledEvent', self._json.get_remote_methods) if client.is_standalone(): component.get('Web.PluginManager').stop() else: client.disconnect() client.set_disconnect_callback(None)
def on_connect_fail(result): """ Callback method for an unsuccessful connection to Deluge. """ print "Failed to connect to the Deluge daemon, sure it's running?" print 'Exiting...' client.disconnect() reactor.stop() sys.exit()
def on_get_torrents_status(self, torrents_status): self.torrents_status = torrents_status #for torrentid in torrents_status: #print torrentid #torrent_status = torrents_status[torrentid] # Disconnect from the daemon once we successfully connect client.disconnect() # Stop the twisted main loop and exit reactor.stop()
def on_add_success(result): if not result: log.info("add torrent successful, was already enqueued") client.disconnect() reactor.stop() else: new_id = result c = client.core.set_torrent_move_completed_path(result, completed_dir) c.addCallback(lambda a: on_set_1(result, a)) c.addErrback(on_add_fail) log.info("added new torrent: " + repr(result)) new_id=None
def _doRead(self): c = self.stdscr.getch() if c > 31 and c < 256: if chr(c) == 'Q': from twisted.internet import reactor if client.connected(): def on_disconnect(result): reactor.stop() client.disconnect().addCallback(on_disconnect) else: reactor.stop() return elif chr(c) == 'q': self.back_to_overview() return if c == 27: self.back_to_overview() return # TODO: Scroll event list jumplen = self.rows - 3 num_events = len( component.get("ConsoleUI").events ) if c == curses.KEY_UP: self.offset -= 1 elif c == curses.KEY_PPAGE: self.offset -= jumplen elif c == curses.KEY_HOME: self.offset = 0 elif c == curses.KEY_DOWN: self.offset += 1 elif c == curses.KEY_NPAGE: self.offset += jumplen elif c == curses.KEY_END: self.offset += num_events elif c == ord('j'): self.offset -= 1 elif c == ord('k'): self.offset += 1 if self.offset <= 0: self.offset = 0 elif num_events > self.rows - 3: if self.offset > num_events - self.rows + 3: self.offset = num_events - self.rows + 3 else: self.offset = 0 self.refresh()
def on_button_connect_clicked(self, widget=None): model, row = self.hostlist.get_selection().get_selected() if not row: return status = model[row][HOSTLIST_COL_STATUS] if status == "Connected": def on_disconnect(reason): self.__update_list() client.disconnect().addCallback(on_disconnect) return host_id = model[row][HOSTLIST_COL_ID] host = model[row][HOSTLIST_COL_HOST] port = model[row][HOSTLIST_COL_PORT] user = model[row][HOSTLIST_COL_USER] password = model[row][HOSTLIST_COL_PASS] if status == "Offline" and self.glade.get_widget("chk_autostart").get_active() and\ host in ("127.0.0.1", "localhost"): # We need to start this localhost self.start_daemon(port, deluge.configmanager.get_config_dir()) def on_connect_fail(result, try_counter): log.error("Connection to host failed..") # We failed connecting to the daemon, but lets try again if try_counter: log.info("Retrying connection.. Retries left: %s", try_counter) try_counter -= 1 import time time.sleep(0.5) do_retry_connect(try_counter) return result def do_retry_connect(try_counter): log.debug("user: %s pass: %s", user, password) d = client.connect(host, port, user, password) d.addCallback(self.__on_connected, host_id) d.addErrback(on_connect_fail, try_counter) do_retry_connect(6) def do_connect(*args): client.connect(host, port, user, password).addCallback(self.__on_connected, host_id) if client.connected(): client.disconnect().addCallback(do_connect) else: do_connect() self.connection_manager.response(gtk.RESPONSE_OK)
def quit_gtkui(): def stop_gtk_reactor(result=None): self.restart = restart try: reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close') except ReactorNotRunning: log.debug('Attempted to stop the reactor but it is not running...') if shutdown: client.daemon.shutdown().addCallback(stop_gtk_reactor) elif not client.is_standalone() and client.connected(): client.disconnect().addCallback(stop_gtk_reactor) else: stop_gtk_reactor()
def on_get_torrent_value(value): apagar=1 for torrent in value: if value[torrent]["progress"] <>100 : apagar=0 print value[torrent]["name"] break if apagar==1: #print "apague" bus = dbus.SystemBus() shut = bus.get_object('org.freedesktop.Hal','/org/freedesktop/Hal/devices/computer') shutr = dbus.Interface(shut , 'org.freedesktop.Hal.Device.SystemPowerManagement') shutr.Shutdown() client.disconnect() reactor.stop()
def handle(self, host="127.0.0.1:58846", username="", password="", **options): self.console = component.get("ConsoleUI") try: host, port = host.split(":") except ValueError: port = 58846 else: port = int(port) def do_connect(): d = client.connect(host, port, username, password) def on_connect(result): if self.console.interactive: self.console.write("{!success!}Connected to %s:%s" % (host, port)) return component.start() def on_connect_fail(result): try: msg = result.value.exception_msg except: msg = result.value.args[0] self.console.write("{!error!}Failed to connect to %s:%s with reason: %s" % (host, port, msg)) return result d.addCallback(on_connect) d.addErrback(on_connect_fail) return d if client.connected(): def on_disconnect(result): self.console.statusbars.update_statusbars() return do_connect() return client.disconnect().addCallback(on_disconnect) else: return do_connect()
def handle(self, *args, **options): if client.connected(): def on_disconnect(result): reactor.stop() return client.disconnect().addCallback(on_disconnect) else: reactor.stop()
def on_button_edithost_clicked(self, widget=None): log.debug("on_button_edithost_clicked") model, row = self.hostlist.get_selection().get_selected() status = model[row][HOSTLIST_COL_STATUS] if status == _("Connected"): def on_disconnect(reason): self.__update_list() client.disconnect().addCallback(on_disconnect) return dialog = self.builder.get_object("addhost_dialog") dialog.set_transient_for(self.connection_manager) dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) hostname_entry = self.builder.get_object("entry_hostname") port_spinbutton = self.builder.get_object("spinbutton_port") username_entry = self.builder.get_object("entry_username") password_entry = self.builder.get_object("entry_password") button_addhost_save = self.builder.get_object("button_addhost_save") button_addhost_save.show() button_addhost_add = self.builder.get_object("button_addhost_add") button_addhost_add.hide() username_entry.set_text(self.liststore[row][HOSTLIST_COL_USER]) password_entry.set_text(self.liststore[row][HOSTLIST_COL_PASS]) hostname_entry.set_text(self.liststore[row][HOSTLIST_COL_HOST]) port_spinbutton.set_value(self.liststore[row][HOSTLIST_COL_PORT]) response = dialog.run() if response == 2: self.liststore[row][HOSTLIST_COL_HOST] = hostname_entry.get_text() self.liststore[row][HOSTLIST_COL_PORT] = port_spinbutton.get_value_as_int() self.liststore[row][HOSTLIST_COL_USER] = username_entry.get_text() self.liststore[row][HOSTLIST_COL_PASS] = password_entry.get_text() self.liststore[row][HOSTLIST_COL_STATUS] = _("Offline") # Save the host list to file self.__save_hostlist() # Update the status of the hosts self.__update_list() username_entry.set_text("") password_entry.set_text("") hostname_entry.set_text("") port_spinbutton.set_value(58846) dialog.hide()
def test_connect_with_password(self): username, password = get_localhost_auth() yield client.connect('localhost', self.listen_port, username=username, password=password) yield client.core.create_account('testuser', 'testpw', 'DEFAULT') yield client.disconnect() ret = yield client.connect('localhost', self.listen_port, username='******', password='******') self.assertEqual(ret, AUTH_LEVEL_NORMAL) yield
def _doRead(self): c = self.stdscr.getch() if self.popup: if self.popup.handle_read(c): self.popup = None self.refresh() return if c > 31 and c < 256: if chr(c) == 'Q': from twisted.internet import reactor if client.connected(): def on_disconnect(result): reactor.stop() client.disconnect().addCallback(on_disconnect) else: reactor.stop() return elif chr(c) == 'h': self.popup = Popup(self,"Preferences Help") for l in HELP_LINES: self.popup.add_line(l) if c == 9: self.active_zone += 1 if self.active_zone > ZONE.ACTIONS: self.active_zone = ZONE.CATEGORIES elif c == curses.KEY_BTAB: self.active_zone -= 1 if self.active_zone < ZONE.CATEGORIES: self.active_zone = ZONE.ACTIONS elif c == 114 and isinstance(self.panes[self.cur_cat],CachePane): client.core.get_cache_status().addCallback(self.panes[self.cur_cat].update_cache_status) else: if self.active_zone == ZONE.CATEGORIES: self.__category_read(c) elif self.active_zone == ZONE.PREFRENCES: self.__prefs_read(c) elif self.active_zone == ZONE.ACTIONS: self.__actions_read(c) self.refresh()
def on_button_connect_clicked(self, checked=False): host = self.selectedItem() # NB: get it before accept closes and deletes the dialog self.accept() if client.connected(): yield client.disconnect() component.get("ConnectionManager").connect(host.config_tuple(), autostart=not host.is_alive())
def disconnect(self): """ Disconnect the web interface from the connected daemon. """ d = client.disconnect() def on_disconnect(reason): return str(reason) d.addCallback(on_disconnect) return d
def quit(self): if client.connected(): def on_disconnect(result): reactor.stop() return client.disconnect().addCallback(on_disconnect) else: try: reactor.stop() except error.ReactorNotRunning: pass
def quit(self, shutdown=False): """ Quits the GtkUI :param shutdown: whether or not to shutdown the daemon as well :type shutdown: boolean """ if shutdown: def on_daemon_shutdown(result): reactor.stop() client.daemon.shutdown().addCallback(on_daemon_shutdown) return if client.is_classicmode(): reactor.stop() return if not client.connected(): reactor.stop() return def on_client_disconnected(result): reactor.stop() client.disconnect().addCallback(on_client_disconnected)
def __connect(self, host_id, host, port, username, password, skip_authentication=False, try_counter=0): def do_connect(*args): d = client.connect(host, port, username, password, skip_authentication) d.addCallback(self.__on_connected, host_id) d.addErrback(self.__on_connected_failed, host_id, host, port, username, password, try_counter) return d if client.connected(): return client.disconnect().addCallback(do_connect) else: return do_connect()
def process_torrents(): client_connected = False try: yield client.connect(host=deluge_host, username=deluge_username, password=deluge_password) client_connected = True log.info("Connected to deluge") torrents = yield client.core.get_torrents_status({}, ['name','label','progress','save_path','state','files']) downloads = [{ 'id' : id, 'location' : torrent['save_path'] + '/' + torrent['name'], 'label' : torrent['label'] } for id, torrent in torrents.iteritems() if torrent['progress'] == 100 and torrent['label'].startswith('download')] log.info('List of torrents to download: %s', downloads) for torrent in downloads: log.info('Downloading torrent: %s', torrent) remote_location = torrent['location'].replace(' ', '\ ').replace('(', '\(').replace(')', '\)').replace('&', '\&').replace('[', '\[').replace(']', '\]').replace('\'', '\\\'') save_location = complete_dir + '/' + torrent['label'] log.info('Remote location: %s', remote_location) log.info('Save location: %s', save_location) source = rsync_username + "@" + deluge_host + ":" + remote_location result = sshpass("-p", rsync_password, "rsync", "-hre", "ssh -o StrictHostKeyChecking=no", "-T", partial_dir, "--partial", "--progress", source, save_location) log.info('Got rsync result: %s', result) if (result.exit_code == 0): log.info('Remove label from torrent: %s', torrent) yield client.label.set_torrent(torrent['id'], 'No Label') except Exception as err: log.exception("Error downloading torrent") finally: if client_connected: log.info('Disconnecting deluge client') yield client.disconnect() log.info('Stopping reactor') reactor.stop()
def _connect(self, host_id, username=None, password=None, try_counter=0): def do_connect(result, username=None, password=None, *args): log.debug('Attempting to connect to daemon...') for host_entry in self.hostlist.config['hosts']: if host_entry[0] == host_id: __, host, port, host_user, host_pass = host_entry username = username if username else host_user password = password if password else host_pass d = client.connect(host, port, username, password) d.addCallback(self._on_connect, host_id) d.addErrback(self._on_connect_fail, host_id, try_counter) return d if client.connected(): return client.disconnect().addCallback(do_connect, username, password) else: return do_connect(None, username, password)
def handle(self, options): self.console = component.get('ConsoleUI') host = options.host try: host, port = host.split(':') port = int(port) except ValueError: port = 58846 def do_connect(): d = client.connect(host, port, options.username, options.password) def on_connect(result): if self.console.interactive: self.console.write('{!success!}Connected to %s:%s!' % (host, port)) return component.start() def on_connect_fail(result): try: msg = result.value.exception_msg except AttributeError: msg = result.value.message self.console.write('{!error!}Failed to connect to %s:%s with reason: %s' % (host, port, msg)) return result d.addCallbacks(on_connect, on_connect_fail) return d if client.connected(): def on_disconnect(result): if self.console.statusbars: self.console.statusbars.update_statusbars() return do_connect() return client.disconnect().addCallback(on_disconnect) else: return do_connect()
def on_button_connect_clicked(self, widget=None): """Button handler for connect to or disconnect from daemon.""" model, row = self.treeview.get_selection().get_selected() if not row: return host_id, host, port, __, __, status, __ = model[row] # If status is connected then connect button disconnects instead. if status == 'Connected': def on_disconnect(reason): self._update_host_status() return client.disconnect().addCallback(on_disconnect) try_counter = 0 auto_start = self.builder.get_object('chk_autostart').get_active() if auto_start and host in LOCALHOST and status == 'Offline': # Start the local daemon and then connect with retries set. if self.start_daemon(port, get_config_dir()): try_counter = 6 else: # Don't attempt to connect to offline daemon. return self._connect(host_id, try_counter=try_counter)
def disconnect_client(result): return client.disconnect()
def get_torrent_data(torrent_id): print torrent_id client.disconnect() reactor.stop()
def on_set_2(new_id, result): client.disconnect() reactor.stop()
def on_add_fail(result): log.info("add torrent failed: " + repr(result) + str(result)) client.disconnect() reactor.stop()
def on_connect_success(self, result, task, config): """Gets called when successfully connected to a daemon.""" from deluge.ui.client import client from twisted.internet import reactor, defer if not result: log.debug('on_connect_success returned a failed result. BUG?') if task.manager.options.test: log.debug('Test connection to deluge daemon successful.') client.disconnect() return def format_label(label): """Makes a string compliant with deluge label naming rules""" return re.sub('[^\w-]+', '_', label.lower()) def set_torrent_options(torrent_id, entry, opts): """Gets called when a torrent was added to the daemon.""" dlist = [] if not torrent_id: log.error('There was an error adding %s to deluge.' % entry['title']) # TODO: Fail entry? How can this happen still now? return log.info('%s successfully added to deluge.' % entry['title']) entry['deluge_id'] = torrent_id def create_path(result, path): """Creates the specified path if deluge is older than 1.3""" from deluge.common import VersionSplit # Before 1.3, deluge would not create a non-existent move directory, so we need to. if VersionSplit('1.3.0') > VersionSplit(self.deluge_version): if client.is_localhost(): if not os.path.isdir(path): log.debug('path %s doesn\'t exist, creating' % path) os.makedirs(path) else: log.warning( 'If path does not exist on the machine running the daemon, move will fail.' ) if opts.get('movedone'): dlist.append( version_deferred.addCallback(create_path, opts['movedone'])) dlist.append( client.core.set_torrent_move_completed(torrent_id, True)) dlist.append( client.core.set_torrent_move_completed_path( torrent_id, opts['movedone'])) log.debug('%s move on complete set to %s' % (entry['title'], opts['movedone'])) if opts.get('label'): def apply_label(result, torrent_id, label): """Gets called after labels and torrent were added to deluge.""" return client.label.set_torrent(torrent_id, label) dlist.append( label_deferred.addCallback(apply_label, torrent_id, opts['label'])) if opts.get('queuetotop') is not None: if opts['queuetotop']: dlist.append(client.core.queue_top([torrent_id])) log.debug('%s moved to top of queue' % entry['title']) else: dlist.append(client.core.queue_bottom([torrent_id])) log.debug('%s moved to bottom of queue' % entry['title']) def on_get_torrent_status(status): """Gets called with torrent status, including file info. Sets the torrent options which require knowledge of the current status of the torrent.""" main_file_dlist = [] # Determine where the file should be move_now_path = None if opts.get('movedone'): if status['progress'] == 100: move_now_path = opts['movedone'] else: # Deluge will unset the move completed option if we move the storage, forgo setting proper # path, in favor of leaving proper final location. log.debug( 'Not moving storage for %s, as this will prevent movedone.' % entry['title']) elif opts.get('path'): move_now_path = opts['path'] if move_now_path and os.path.normpath( move_now_path) != os.path.normpath( status['save_path']): main_file_dlist.append( version_deferred.addCallback(create_path, move_now_path)) log.debug('Moving storage for %s to %s' % (entry['title'], move_now_path)) main_file_dlist.append( client.core.move_storage([torrent_id], move_now_path)) if opts.get('content_filename') or opts.get('main_file_only'): def file_exists(): # Checks the download path as well as the move completed path for existence of the file if os.path.exists( os.path.join(status['save_path'], filename)): return True elif status.get('move_on_completed') and status.get( 'move_on_completed_path'): if os.path.exists( os.path.join( status['move_on_completed_path'], filename)): return True else: return False for file in status['files']: # Only rename file if it is > 90% of the content if file['size'] > (status['total_size'] * 0.9): if opts.get('content_filename'): filename = opts[ 'content_filename'] + os.path.splitext( file['path'])[1] counter = 1 if client.is_localhost(): while file_exists(): # Try appending a (#) suffix till a unique filename is found filename = ''.join([ opts['content_filename'], '(', str(counter), ')', os.path.splitext(file['path'])[1] ]) counter += 1 else: log.debug( 'Cannot ensure content_filename is unique ' 'when adding to a remote deluge daemon.' ) log.debug( 'File %s in %s renamed to %s' % (file['path'], entry['title'], filename)) main_file_dlist.append( client.core.rename_files( torrent_id, [(file['index'], filename)])) if opts.get('main_file_only'): file_priorities = [ 1 if f['index'] == file['index'] else 0 for f in status['files'] ] main_file_dlist.append( client.core.set_torrent_file_priorities( torrent_id, file_priorities)) break else: log.warning( 'No files in %s are > 90%% of content size, no files renamed.' % entry['title']) return defer.DeferredList(main_file_dlist) status_keys = [ 'files', 'total_size', 'save_path', 'move_on_completed_path', 'move_on_completed', 'progress' ] dlist.append( client.core.get_torrent_status( torrent_id, status_keys).addCallback(on_get_torrent_status)) return defer.DeferredList(dlist) def on_fail(result, task, entry): """Gets called when daemon reports a failure adding the torrent.""" log.info('%s was not added to deluge! %s' % (entry['title'], result)) entry.fail('Could not be added to deluge') # dlist is a list of deferreds that must complete before we exit dlist = [] # loop through entries to get a list of labels to add labels = set([ format_label(entry['label']) for entry in task.accepted if entry.get('label') ]) if config.get('label'): labels.add(format_label(config['label'])) label_deferred = defer.succeed(True) if labels: # Make sure the label plugin is available and enabled, then add appropriate labels def on_get_enabled_plugins(plugins): """Gets called with the list of enabled deluge plugins.""" def on_label_enabled(result): """ This runs when we verify the label plugin is enabled. """ def on_get_labels(d_labels): """Gets available labels from deluge, and adds any new labels we need.""" dlist = [] for label in labels: if not label in d_labels: log.debug('Adding the label %s to deluge' % label) dlist.append(client.label.add(label)) return defer.DeferredList(dlist) return client.label.get_labels().addCallback(on_get_labels) if 'Label' in plugins: return on_label_enabled(True) else: # Label plugin isn't enabled, so we check if it's available and enable it. def on_get_available_plugins(plugins): """Gets plugins available to deluge, enables Label plugin if available.""" if 'Label' in plugins: log.debug('Enabling label plugin in deluge') return client.core.enable_plugin( 'Label').addCallback(on_label_enabled) else: log.error( 'Label plugin is not installed in deluge') return client.core.get_available_plugins().addCallback( on_get_available_plugins) label_deferred = client.core.get_enabled_plugins().addCallback( on_get_enabled_plugins) dlist.append(label_deferred) def on_get_daemon_info(ver): """Gets called with the daemon version info, stores it in self.""" log.debug('deluge version %s' % ver) self.deluge_version = ver version_deferred = client.daemon.info().addCallback(on_get_daemon_info) dlist.append(version_deferred) def on_get_session_state(torrent_ids): """Gets called with a list of torrent_ids loaded in the deluge session. Adds new torrents and modifies the settings for ones already in the session.""" dlist = [] # add the torrents for entry in task.accepted: def add_entry(entry, opts): """Adds an entry to the deluge session""" magnet, filedump = None, None if entry.get('url', '').startswith('magnet:'): magnet = entry['url'] else: if not os.path.exists(entry['file']): entry.fail( 'Downloaded temp file \'%s\' doesn\'t exist!' % entry['file']) del (entry['file']) return with open(entry['file'], 'rb') as f: filedump = base64.encodestring(f.read()) log.verbose('Adding %s to deluge.' % entry['title']) if magnet: return client.core.add_torrent_magnet(magnet, opts) else: return client.core.add_torrent_file( entry['title'], filedump, opts) # Generate deluge options dict for torrent add add_opts = {} try: path = entry.render(entry.get('path', config['path'])) if path: add_opts['download_location'] = pathscrub( os.path.expanduser(path)) except RenderError as e: log.error('Could not set path for %s: %s' % (entry['title'], e)) for fopt, dopt in self.options.iteritems(): value = entry.get(fopt, config.get(fopt)) if value is not None: add_opts[dopt] = value if fopt == 'ratio': add_opts['stop_at_ratio'] = True # Make another set of options, that get set after the torrent has been added modify_opts = { 'label': format_label(entry.get('label', config['label'])), 'queuetotop': entry.get('queuetotop', config.get('queuetotop')), 'main_file_only': entry.get('main_file_only', config.get('main_file_only', False)) } try: movedone = entry.render( entry.get('movedone', config['movedone'])) modify_opts['movedone'] = pathscrub( os.path.expanduser(movedone)) except RenderError as e: log.error('Error setting movedone for %s: %s' % (entry['title'], e)) try: content_filename = entry.get( 'content_filename', config.get('content_filename', '')) modify_opts['content_filename'] = pathscrub( entry.render(content_filename)) except RenderError as e: log.error('Error setting content_filename for %s: %s' % (entry['title'], e)) torrent_id = entry.get('deluge_id') or entry.get( 'torrent_info_hash') torrent_id = torrent_id and torrent_id.lower() if torrent_id in torrent_ids: log.info( '%s is already loaded in deluge, setting options' % entry['title']) # Entry has a deluge id, verify the torrent is still in the deluge session and apply options # Since this is already loaded in deluge, we may also need to change the path modify_opts['path'] = add_opts.pop('download_location', None) dlist.extend([ set_torrent_options(torrent_id, entry, modify_opts), client.core.set_torrent_options([torrent_id], add_opts) ]) else: dlist.append( add_entry(entry, add_opts).addCallbacks( set_torrent_options, on_fail, callbackArgs=(entry, modify_opts), errbackArgs=(task, entry))) return defer.DeferredList(dlist) dlist.append( client.core.get_session_state().addCallback(on_get_session_state)) def on_complete(result): """Gets called when all of our tasks for deluge daemon are complete.""" client.disconnect() tasks = defer.DeferredList(dlist).addBoth(on_complete) def on_timeout(result): """Gets called if tasks have not completed in 30 seconds. Should only happen when something goes wrong.""" log.error('Timed out while adding torrents to deluge.') log.debug('dlist: %s' % result.resultList) client.disconnect() # Schedule a disconnect to happen if FlexGet hangs while connected to Deluge # Leave the timeout long, to give time for possible lookups to occur reactor.callLater(300, lambda: tasks.called or on_timeout(tasks))
def _doRead(self): c = self.stdscr.getch() if self.popup: if self.popup.handle_read(c): self.popup = None self.refresh() return if c > 31 and c < 256: if chr(c) == 'Q': from twisted.internet import reactor if client.connected(): def on_disconnect(result): reactor.stop() client.disconnect().addCallback(on_disconnect) else: reactor.stop() return elif chr(c) == 'q': self.back_to_overview() return # Navigate the torrent list if c == curses.KEY_UP: self.scroll_list_up(1) elif c == curses.KEY_PPAGE: #self.scroll_list_up(self._listing_space-2) self.scroll_list_up(self.rows // 2) elif c == curses.KEY_HOME: self.scroll_list_up(len(self.formatted_rows)) elif c == curses.KEY_DOWN: self.scroll_list_down(1) elif c == curses.KEY_NPAGE: #self.scroll_list_down(self._listing_space-2) self.scroll_list_down(self.rows // 2) elif c == curses.KEY_END: self.scroll_list_down(len(self.formatted_rows)) elif c == curses.KEY_RIGHT: if self.cursel < len(self.listing_dirs): self._enter_dir() elif c == curses.KEY_LEFT: self._go_up() # Enter Key elif c == curses.KEY_ENTER or c == 10: self._perform_action() #Escape elif c == 27: self.back_to_overview() else: if c > 31 and c < 256: if chr(c) == 'h': self.popup = MessagePopup(self, "Help", HELP_STR, width_req=0.75) elif chr(c) == '>': if self.sort_column == "date": self.reverse_sort = not self.reverse_sort else: self.sort_column = "date" self.reverse_sort = True self.__sort_rows() elif chr(c) == '<': if self.sort_column == "name": self.reverse_sort = not self.reverse_sort else: self.sort_column = "name" self.reverse_sort = False self.__sort_rows() elif chr(c) == 'm': s = self.raw_rows[self.cursel][0] if s in self.marked: self.marked.remove(s) else: self.marked.add(s) self.last_mark = self.cursel elif chr(c) == 'j': self.scroll_list_up(1) elif chr(c) == 'k': self.scroll_list_down(1) elif chr(c) == 'M': if self.last_mark != -1: if self.last_mark > self.cursel: m = range(self.cursel, self.last_mark) else: m = range(self.last_mark, self.cursel + 1) for i in m: s = self.raw_rows[i][0] self.marked.add(s) elif chr(c) == 'c': self.marked.clear() self.refresh()
def on_complete(result): """Gets called when all of our tasks for deluge daemon are complete.""" client.disconnect()
def on_timeout(result): """Gets called if tasks have not completed in 30 seconds. Should only happen when something goes wrong.""" log.error('Timed out while adding torrents to deluge.') log.debug('dlist: %s' % result.resultList) client.disconnect()
def disconnect_client(self, *args): return client.disconnect()
def stop_reactor(): client.disconnect().addCallback(lambda ignore: reactor.stop()) LOGGER.info('Disconnecting from client') LOGGER.info('Stopping reactor')
def on_get_torrent_status(torrent): print torrent["label"] client.disconnect() reactor.stop()
def dl_finish(result): print "All deferred calls have fired, exiting program..." client.disconnect() # Stop the twisted main loop and exit reactor.stop()
def on_connect_success(self, result, task, config): """Gets called when successfully connected to a daemon.""" from deluge.ui.client import client from twisted.internet import reactor, defer if not result: log.debug('on_connect_success returned a failed result. BUG?') if task.options.test: log.debug('Test connection to deluge daemon successful.') client.disconnect() return def format_label(label): """Makes a string compliant with deluge label naming rules""" return re.sub('[^\w-]+', '_', label.lower()) def set_torrent_options(torrent_id, entry, opts): """Gets called when a torrent was added to the daemon.""" dlist = [] if not torrent_id: log.error('There was an error adding %s to deluge.' % entry['title']) # TODO: Fail entry? How can this happen still now? return log.info('%s successfully added to deluge.' % entry['title']) entry['deluge_id'] = torrent_id def create_path(result, path): """Creates the specified path if deluge is older than 1.3""" from deluge.common import VersionSplit # Before 1.3, deluge would not create a non-existent move directory, so we need to. if VersionSplit('1.3.0') > VersionSplit(self.deluge_version): if client.is_localhost(): if not os.path.isdir(path): log.debug('path %s doesn\'t exist, creating' % path) os.makedirs(path) else: log.warning( 'If path does not exist on the machine running the daemon, move will fail.' ) if opts.get('movedone'): dlist.append( version_deferred.addCallback(create_path, opts['movedone'])) dlist.append( client.core.set_torrent_move_completed(torrent_id, True)) dlist.append( client.core.set_torrent_move_completed_path( torrent_id, opts['movedone'])) log.debug('%s move on complete set to %s' % (entry['title'], opts['movedone'])) if opts.get('label'): def apply_label(result, torrent_id, label): """Gets called after labels and torrent were added to deluge.""" return client.label.set_torrent(torrent_id, label) dlist.append( label_deferred.addCallback(apply_label, torrent_id, opts['label'])) if opts.get('queuetotop') is not None: if opts['queuetotop']: dlist.append(client.core.queue_top([torrent_id])) log.debug('%s moved to top of queue' % entry['title']) else: dlist.append(client.core.queue_bottom([torrent_id])) log.debug('%s moved to bottom of queue' % entry['title']) def on_get_torrent_status(status): """Gets called with torrent status, including file info. Sets the torrent options which require knowledge of the current status of the torrent.""" main_file_dlist = [] # Determine where the file should be move_now_path = None if opts.get('movedone'): if status['progress'] == 100: move_now_path = opts['movedone'] else: # Deluge will unset the move completed option if we move the storage, forgo setting proper # path, in favor of leaving proper final location. log.debug( 'Not moving storage for %s, as this will prevent movedone.' % entry['title']) elif opts.get('path'): move_now_path = opts['path'] if move_now_path and os.path.normpath( move_now_path) != os.path.normpath( status['save_path']): main_file_dlist.append( version_deferred.addCallback(create_path, move_now_path)) log.debug('Moving storage for %s to %s' % (entry['title'], move_now_path)) main_file_dlist.append( client.core.move_storage([torrent_id], move_now_path)) if opts.get('content_filename') or opts.get('main_file_only'): def file_exists(filename): # Checks the download path as well as the move completed path for existence of the file if os.path.exists( os.path.join(status['save_path'], filename)): return True elif status.get('move_on_completed') and status.get( 'move_on_completed_path'): if os.path.exists( os.path.join( status['move_on_completed_path'], filename)): return True else: return False def unused_name(name): # If on local computer, tries appending a (#) suffix until a unique filename is found if client.is_localhost(): counter = 2 while file_exists(name): name = ''.join([ os.path.splitext(name)[0], " (", str(counter), ')', os.path.splitext(name)[1] ]) counter += 1 else: log.debug( 'Cannot ensure content_filename is unique ' 'when adding to a remote deluge daemon.') return name def rename(file, new_name): # Renames a file in torrent main_file_dlist.append( client.core.rename_files( torrent_id, [(file['index'], new_name)])) log.debug('File %s in %s renamed to %s' % (file['path'], entry['title'], new_name)) # find a file that makes up more than main_file_ratio (default: 90%) of the total size main_file = None for file in status['files']: if file['size'] > (status['total_size'] * opts.get('main_file_ratio')): main_file = file break if main_file is not None: # proceed with renaming only if such a big file is found # find the subtitle file keep_subs = opts.get('keep_subs') sub_file = None if keep_subs: sub_exts = [".srt", ".sub"] for file in status['files']: ext = os.path.splitext(file['path'])[1] if ext in sub_exts: sub_file = file break # check for single file torrents so we dont add unnecessary folders if (os.path.dirname(main_file['path']) is not ("" or "/")): # check for top folder in user config if (opts.get('content_filename') and os.path.dirname( opts['content_filename']) is not ""): top_files_dir = os.path.dirname( opts['content_filename']) + "/" else: top_files_dir = os.path.dirname( main_file['path']) + "/" else: top_files_dir = "/" if opts.get('content_filename'): # rename the main file big_file_name = ( top_files_dir + os.path.basename(opts['content_filename']) + os.path.splitext(main_file['path'])[1]) big_file_name = unused_name(big_file_name) rename(main_file, big_file_name) # rename subs along with the main file if sub_file is not None and keep_subs: sub_file_name = ( os.path.splitext(big_file_name)[0] + os.path.splitext(sub_file['path'])[1]) rename(sub_file, sub_file_name) if opts.get('main_file_only'): # download only the main file (and subs) file_priorities = [ 1 if f == main_file or (f == sub_file and keep_subs) else 0 for f in status['files'] ] main_file_dlist.append( client.core.set_torrent_file_priorities( torrent_id, file_priorities)) if opts.get('hide_sparse_files'): # hide the other sparse files that are not supposed to download but are created anyway # http://dev.deluge-torrent.org/ticket/1827 # Made sparse files behave better with deluge http://flexget.com/ticket/2881 sparse_files = [ f for f in status['files'] if f != main_file and ( f != sub_file or (not keep_subs)) ] rename_pairs = [ (f['index'], top_files_dir + ".sparse_files/" + os.path.basename(f['path'])) for f in sparse_files ] main_file_dlist.append( client.core.rename_files( torrent_id, rename_pairs)) else: log.warning( 'No files in "%s" are > %d%% of content size, no files renamed.' % (entry['title'], opts.get('main_file_ratio') * 100)) return defer.DeferredList(main_file_dlist) status_keys = [ 'files', 'total_size', 'save_path', 'move_on_completed_path', 'move_on_completed', 'progress' ] dlist.append( client.core.get_torrent_status( torrent_id, status_keys).addCallback(on_get_torrent_status)) return defer.DeferredList(dlist) def on_fail(result, task, entry): """Gets called when daemon reports a failure adding the torrent.""" log.info('%s was not added to deluge! %s' % (entry['title'], result)) entry.fail('Could not be added to deluge') # dlist is a list of deferreds that must complete before we exit dlist = [] # loop through entries to get a list of labels to add labels = set([ format_label(entry['label']) for entry in task.accepted if entry.get('label') ]) if config.get('label'): labels.add(format_label(config['label'])) label_deferred = defer.succeed(True) if labels: # Make sure the label plugin is available and enabled, then add appropriate labels def on_get_enabled_plugins(plugins): """Gets called with the list of enabled deluge plugins.""" def on_label_enabled(result): """ This runs when we verify the label plugin is enabled. """ def on_get_labels(d_labels): """Gets available labels from deluge, and adds any new labels we need.""" dlist = [] for label in labels: if label not in d_labels: log.debug('Adding the label %s to deluge' % label) dlist.append(client.label.add(label)) return defer.DeferredList(dlist) return client.label.get_labels().addCallback(on_get_labels) if 'Label' in plugins: return on_label_enabled(True) else: # Label plugin isn't enabled, so we check if it's available and enable it. def on_get_available_plugins(plugins): """Gets plugins available to deluge, enables Label plugin if available.""" if 'Label' in plugins: log.debug('Enabling label plugin in deluge') return client.core.enable_plugin( 'Label').addCallback(on_label_enabled) else: log.error( 'Label plugin is not installed in deluge') return client.core.get_available_plugins().addCallback( on_get_available_plugins) label_deferred = client.core.get_enabled_plugins().addCallback( on_get_enabled_plugins) dlist.append(label_deferred) def on_get_daemon_info(ver): """Gets called with the daemon version info, stores it in self.""" log.debug('deluge version %s' % ver) self.deluge_version = ver version_deferred = client.daemon.info().addCallback(on_get_daemon_info) dlist.append(version_deferred) def on_get_session_state(torrent_ids): """Gets called with a list of torrent_ids loaded in the deluge session. Adds new torrents and modifies the settings for ones already in the session.""" dlist = [] # add the torrents for entry in task.accepted: @defer.inlineCallbacks def _wait_for_metadata(torrent_id, timeout): log.verbose('Waiting %d seconds for "%s" to magnetize' % (timeout, entry['title'])) for _ in range(timeout): time.sleep(1) try: status = yield client.core.get_torrent_status( torrent_id, ['files']) except Exception as err: log.error('wait_for_metadata Error: %s' % err) break if len(status['files']) > 0: log.info('"%s" magnetization successful' % (entry['title'])) break else: log.warning( '"%s" did not magnetize before the timeout elapsed, ' 'file list unavailable for processing.' % entry['title']) defer.returnValue(torrent_id) def add_entry(entry, opts): """Adds an entry to the deluge session""" magnet, filedump = None, None if entry.get('url', '').startswith('magnet:'): magnet = entry['url'] else: if not os.path.exists(entry['file']): entry.fail( 'Downloaded temp file \'%s\' doesn\'t exist!' % entry['file']) del (entry['file']) return with open(entry['file'], 'rb') as f: filedump = base64.encodestring(f.read()) log.verbose('Adding %s to deluge.' % entry['title']) if magnet: d = client.core.add_torrent_magnet(magnet, opts) if config.get('magnetization_timeout'): d.addCallback(_wait_for_metadata, config['magnetization_timeout']) return d else: return client.core.add_torrent_file( entry['title'], filedump, opts) # Generate deluge options dict for torrent add add_opts = {} try: path = entry.render(entry.get('path', config['path'])) if path: add_opts['download_location'] = pathscrub( os.path.expanduser(path)) except RenderError as e: log.error('Could not set path for %s: %s' % (entry['title'], e)) for fopt, dopt in self.options.items(): value = entry.get(fopt, config.get(fopt)) if value is not None: add_opts[dopt] = value if fopt == 'ratio': add_opts['stop_at_ratio'] = True # Make another set of options, that get set after the torrent has been added modify_opts = { 'label': format_label(entry.get('label', config['label'])), 'queuetotop': entry.get('queuetotop', config.get('queuetotop')), 'main_file_only': entry.get('main_file_only', config.get('main_file_only', False)), 'main_file_ratio': entry.get('main_file_ratio', config.get('main_file_ratio')), 'hide_sparse_files': entry.get('hide_sparse_files', config.get('hide_sparse_files', True)), 'keep_subs': entry.get('keep_subs', config.get('keep_subs', True)) } try: movedone = entry.render( entry.get('movedone', config['movedone'])) modify_opts['movedone'] = pathscrub( os.path.expanduser(movedone)) except RenderError as e: log.error('Error setting movedone for %s: %s' % (entry['title'], e)) try: content_filename = entry.get( 'content_filename', config.get('content_filename', '')) modify_opts['content_filename'] = pathscrub( entry.render(content_filename)) except RenderError as e: log.error('Error setting content_filename for %s: %s' % (entry['title'], e)) torrent_id = entry.get('deluge_id') or entry.get( 'torrent_info_hash') torrent_id = torrent_id and torrent_id.lower() if torrent_id in torrent_ids: log.info( '%s is already loaded in deluge, setting options' % entry['title']) # Entry has a deluge id, verify the torrent is still in the deluge session and apply options # Since this is already loaded in deluge, we may also need to change the path modify_opts['path'] = add_opts.pop('download_location', None) dlist.extend([ set_torrent_options(torrent_id, entry, modify_opts), client.core.set_torrent_options([torrent_id], add_opts) ]) else: dlist.append( add_entry(entry, add_opts).addCallbacks( set_torrent_options, on_fail, callbackArgs=(entry, modify_opts), errbackArgs=(task, entry))) return defer.DeferredList(dlist) dlist.append( client.core.get_session_state().addCallback(on_get_session_state)) def on_complete(result): """Gets called when all of our tasks for deluge daemon are complete.""" client.disconnect() tasks = defer.DeferredList(dlist).addBoth(on_complete) def on_timeout(result): """Gets called if tasks have not completed in 30 seconds. Should only happen when something goes wrong.""" log.error('Timed out while adding torrents to deluge.') log.debug('dlist: %s' % result.resultList) client.disconnect() # Schedule a disconnect to happen if FlexGet hangs while connected to Deluge # Leave the timeout long, to give time for possible lookups to occur reactor.callLater(600, lambda: tasks.called or on_timeout(tasks))