def check_import(self, force=False): """Imports latest blocklist specified by blocklist url. Args: force (bool, optional): Force the download/import, default is False. Returns: Deferred: A Deferred which fires when the blocklist has been imported. """ if not self.config['url']: return # Reset variables self.filename = None self.force_download = force self.failed_attempts = 0 self.auto_detected = False self.up_to_date = False if force: self.reader = None self.is_url = is_url(self.config['url']) # Start callback chain if self.is_url: d = self.download_list() d.addCallbacks(self.on_download_complete, self.on_download_error) d.addCallback(self.import_list) else: d = self.import_list(self.config['url']) d.addCallbacks(self.on_import_complete, self.on_import_error) if self.need_to_resume_session: d.addBoth(self.resume_session) return d
def _on_get_torrent_status(self, status): # Check to see if we got valid data from the core if status is None: return # Update all the label widgets for widget in self.label_widgets: if widget[1] != None: args = [] try: for key in widget[2]: args.append(status[key]) except Exception, e: log.debug("Unable to get status value: %s", e) continue txt = widget[1](*args) else: txt = status[widget[2][0]] if widget[0].get_text() != txt: if widget[2][0] == 'comment' and is_url(txt): widget[0].set_markup('<a href="%s">%s</a>' % (txt, txt.replace('&', '&'))) else: widget[0].set_markup(txt.replace('&', '&'))
def trackers_tiers_from_text(text_str=''): """Create a list of trackers from text. Any duplicate trackers are removed. Args: text_input (str): A block of text with tracker separated by newlines. Returns: list: The list of trackers. Notes: Trackers should be separated by newlines and empty line denotes start of new tier. """ trackers = {} tier = 0 lines = text_str.strip().split('\n') for line in lines: if not line: tier += 1 continue line = line.replace('\\', '/') # Fix any mistyped urls. if is_url(line) and line not in trackers: trackers[line] = tier return trackers
def check_import(self, force=False): """ Imports latest blocklist specified by blocklist url Only downloads/imports if necessary or forced :param force: optional argument to force download/import :type force: boolean :returns: a Deferred which fires when the blocklist has been imported :rtype: Deferred """ # Reset variables self.filename = None self.force_download = force self.failed_attempts = 0 self.auto_detected = False self.up_to_date = False if force: self.reader = None self.is_url = is_url(self.config["url"]) # Start callback chain if self.is_url: d = self.download_list() d.addCallbacks(self.on_download_complete, self.on_download_error) d.addCallback(self.import_list) else: d = self.import_list(self.config["url"]) d.addCallbacks(self.on_import_complete, self.on_import_error) if self.need_to_resume_session: d.addBoth(self.resume_session) return d
def process_args(args): """Process arguments sent to already running Deluge""" # Make sure args is a list args = list(args) log.debug('Processing args from other process: %s', args) if not client.connected(): # We're not connected so add these to the queue log.debug('Not connected to host.. Adding to queue.') component.get('QueuedTorrents').add_to_queue(args) return config = ConfigManager('gtkui.conf') for arg in args: if not arg.strip(): continue log.debug('arg: %s', arg) if is_url(arg): log.debug('Attempting to add url (%s) from external source...', arg) if config['interactive_add']: component.get('AddTorrentDialog').add_from_url(arg) component.get('AddTorrentDialog').show( config['focus_add_dialog']) else: client.core.add_torrent_url(arg, None) elif is_magnet(arg): log.debug('Attempting to add magnet (%s) from external source...', arg) if config['interactive_add']: component.get('AddTorrentDialog').add_from_magnets([arg]) component.get('AddTorrentDialog').show( config['focus_add_dialog']) else: client.core.add_torrent_magnet(arg, {}) else: log.debug('Attempting to add file (%s) from external source...', arg) if urlparse(arg).scheme == 'file': arg = url2pathname(urlparse(arg).path) path = os.path.abspath(decode_bytes(arg)) if not os.path.exists(path): log.error('No such file: %s', path) continue if config['interactive_add']: component.get('AddTorrentDialog').add_from_files([path]) component.get('AddTorrentDialog').show( config['focus_add_dialog']) else: with open(path, 'rb') as _file: filedump = b64encode(_file.read()) client.core.add_torrent_file( os.path.split(path)[-1], filedump, None)
def on_focus(self, window, param): if window.props.is_active and not self.first_run and self.config[ 'detect_urls']: text = get_clipboard_text() if text == self.previous_clipboard_text: return self.previous_clipboard_text = text if text and ((is_url(text) and text.endswith('.torrent')) or is_magnet(text)): component.get('AddTorrentDialog').show() component.get('AddTorrentDialog').on_button_url_clicked(window) self.first_run = False
def _on_get_torrent_status(self, status): # Check to see if we got valid data from the core if status is None: return # Update all the label widgets for widget in self.tab_widgets.values(): txt = xml_escape(self.widget_status_as_fstr(widget, status)) if widget.obj.get_text() != txt: if 'comment' in widget.status_keys and is_url(txt): widget.obj.set_markup('<a href="%s">%s</a>' % (txt, txt)) else: widget.obj.set_markup(txt)
def on_button_url_clicked(self, widget): log.debug('on_button_url_clicked') dialog = self.builder.get_object('url_dialog') entry = self.builder.get_object('entry_url') dialog.set_default_response(Gtk.ResponseType.OK) dialog.set_transient_for(self.dialog) entry.grab_focus() text = get_clipboard_text() if text and is_url(text) or is_magnet(text): entry.set_text(text) dialog.show_all() response = dialog.run() if response == Gtk.ResponseType.OK: url = decode_bytes(entry.get_text()) else: url = None entry.set_text('') dialog.hide() # This is where we need to fetch the .torrent file from the URL and # add it to the list. log.debug('url: %s', url) if url: if is_url(url): self.add_from_url(url) elif is_magnet(url): self.add_from_magnets([url]) else: ErrorDialog( _('Invalid URL'), '%s %s' % (url, _('is not a valid URL.')), self.dialog, ).run()
def add_url(self, bot, update): if str(update.message.chat.id) in self.whitelist: try: user = update.message.chat.id log.debug("addurl of %s: %s" % (str(user), update.message.text)) if is_url(update.message.text): try: # Download file request = urllib2.Request(update.message.text.strip(), headers=HEADERS) status_code = urllib2.urlopen(request).getcode() if status_code == 200: file_contents = urllib2.urlopen(request).read() # Base64 encode file data metainfo = b64encode(file_contents) if self.opts is None: self.opts = {} log.info( prelog() + 'Adding torrent from base64 string' + 'using options `%s` ...', self.opts) tid = self.core.add_torrent_file( None, metainfo, self.opts) self.apply_label(tid) else: update.message.reply_text( STRINGS['download_fail'], reply_markup=ReplyKeyboardRemove()) except Exception as e: update.message.reply_text( STRINGS['download_fail'], reply_markup=ReplyKeyboardRemove()) log.error(prelog() + str(e) + '\n' + traceback.format_exc()) else: update.message.reply_text( STRINGS['not_url'], reply_markup=ReplyKeyboardRemove()) return ConversationHandler.END except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def update_trackerlist_from_url(self): if self.config["dynamic_trackerlist_url"]: now = datetime.datetime.utcnow() last_update = datetime.datetime.utcfromtimestamp( self.config["last_dynamic_trackers_update"]) if now - last_update > datetime.timedelta( days=self.config["dynamic_trackers_update_interval"]): try: headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'Accept-Encoding': 'none', 'Accept-Language': 'en-US,en;q=0.8', } req = urllib.request.Request( self.config["dynamic_trackerlist_url"], headers=headers) try: page = urllib.request.urlopen( req, context=ssl._create_unverified_context()).read() except: # maybe an older Python version without a "context" argument page = urllib.request.urlopen(req).read() new_trackers = [ decode_bytes(url) for url in re.findall(b'\w+://[\w\-.:/]+', page) if is_url(decode_bytes(url)) ] if new_trackers: # replace all existing trackers self.config["trackers"] = [] for new_tracker in new_trackers: self.config["trackers"].append( {"url": new_tracker}) self.config["last_dynamic_trackers_update"] = time.mktime( now.timetuple()) except: traceback.print_exc() return self.config.config
def add_url(self, bot, update): if str(update.message.chat.id) in self.whitelist: try: user = update.message.chat.id log.debug("addurl of %s: %s" % (str(user), update.message.text)) if is_url(update.message.text): try: # Download file request = urllib2.Request(update.message.text.strip(), headers=HEADERS) status_code = urllib2.urlopen(request).getcode() if status_code == 200: file_contents = urllib2.urlopen(request).read() # Base64 encode file data metainfo = b64encode(file_contents) if self.opts is None: self.opts = {} log.info(prelog() + 'Adding torrent from base64 string' + 'using options `%s` ...', self.opts) tid = self.core.add_torrent_file(None, metainfo, self.opts) self.apply_label(tid) else: update.message.reply_text(STRINGS['download_fail'], reply_markup=ReplyKeyboardRemove()) except Exception as e: update.message.reply_text(STRINGS['download_fail'], reply_markup=ReplyKeyboardRemove()) log.error(prelog() + str(e) + '\n' + traceback.format_exc()) else: update.message.reply_text(STRINGS['not_url'], reply_markup=ReplyKeyboardRemove()) return ConversationHandler.END except Exception as e: log.error(prelog() + str(e) + '\n' + traceback.format_exc())
def update_trackerlist_from_url(self): if self.config["dynamic_trackerlist_url"]: now = datetime.datetime.utcnow() last_update = datetime.datetime.utcfromtimestamp(self.config["last_dynamic_trackers_update"]) if now - last_update > datetime.timedelta(days=self.config["dynamic_trackers_update_interval"]): try: headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'Accept-Encoding': 'none', 'Accept-Language': 'en-US,en;q=0.8', } req = urllib2.Request(self.config["dynamic_trackerlist_url"], headers=headers) try: page = urllib2.urlopen(req, context=ssl._create_unverified_context()).read() except: # maybe an older Python version without a "context" argument page = urllib2.urlopen(req).read() new_trackers = [url for url in re.findall(r'\w+://[\w\-.:/]+', page) if is_url(url)] if new_trackers: # replace all existing trackers self.config["trackers"] = [] for new_tracker in new_trackers: self.config["trackers"].append({"url": new_tracker}) self.config["last_dynamic_trackers_update"] = time.mktime(now.timetuple()) except: traceback.print_exc() return self.config.config
def test_is_url(self): self.assertTrue(is_url('http://deluge-torrent.org')) self.assertFalse(is_url('file://test.torrent'))
def walk(self, force=False): """Implemets automatic torrent updates process. Automatic update is available for torrents selected by user and having tracker's page URL in torrent's `comment` field. Besides that torrent a tracker handler class should be associated with domain from the URL mentioned above. If `force` set to a list of torrent IDs, only those torrents will be checked for updates. If `force` is False every torrent scheduled to updates by used will be checked. """ # To prevent possible concurent runs. self.walking = True try: log.info('Updatorr walking...') component.get('EventManager').emit( UpdatorrUpdatesCheckStartedEvent()) allow_last_walk_update = False if isinstance(force, list): torrents_list = force else: torrents_list = self.torrents_to_update for torrent_id in torrents_list: try: torrent_data = self.core.get_torrent_status(torrent_id, []) log.info('Updatorr Processing %s ...' % torrent_data['name']) except KeyError: log.debug( 'Updatorr \tSKIPPED No torrent with id %s listed [yet]' % torrent_id) continue # Remove not url data from comment torrent_data['comment'] = RE_LINK.search( torrent_data['comment']).group('url') if not is_url(torrent_data['comment']): log.info( 'Updatorr \tSKIPPED No URL found in torrent comment') continue # From now on we consider that update took its place. # If only this update is not forced. if not force: allow_last_walk_update = True tracker_handler = get_tracker_handler(torrent_data, log) if tracker_handler is None: self.dump_error( torrent_id, 'Unable to find tracker handler for %s' % torrent_data['comment']) continue tracker_handler.set_settings( self.trackers_settings.get(tracker_handler.tracker_host)) new_torrent_filepath = tracker_handler.get_torrent_file() if new_torrent_filepath is None: self.dump_error( torrent_id, 'Error in tracker handling: %s' % tracker_handler.get_error_text()) continue # Let's store cookies form that tracker to enter without logins in future sessions. self.trackers_settings[tracker_handler.tracker_host][ 'cookies'] = tracker_handler.get_cookies(as_dict=True) new_torrent_contents = read_torrent_file(new_torrent_filepath) new_torrent_info = read_torrent_info(new_torrent_contents) if torrent_data['hash'] == new_torrent_info['hash']: log.info('Updatorr \tSKIPPED Torrent is up-to-date') continue log.info('Updatorr \tTorrent update is available') new_torrent_prefs = get_new_prefs(torrent_data, new_torrent_info) added_torrent_id = self.core.add_torrent_file( None, base64.encodestring(new_torrent_contents), new_torrent_prefs) if added_torrent_id is not None: self.core.remove_torrent(torrent_id, False) log.info('Updatorr \tTorrent is updated') # Fire up update finished event. component.get('EventManager').emit( UpdatorrUpdateDoneEvent(new_torrent_info['hash'])) # Add new torrent hash to continue autoupdates. self.set_items_to_update(new_torrent_info['hash'], True) # Remove old torrent from autoupdates list. self.set_items_to_update(torrent_id, False) else: self.dump_error( torrent_id, 'Unable to replace current torrent with a new one') # No littering, remove temporary .torrent file. os.remove(new_torrent_filepath) if allow_last_walk_update: # Remember lastrun time. self.last_walk = time.time() log.info('Updatorr walk is finished') component.get('EventManager').emit( UpdatorrUpdatesCheckFinishedEvent()) except: log.error(traceback.format_exc()) finally: self.walking = False
def on_button_save_clicked(self, widget): log.debug('on_button_save_clicked') if len(self.files_treestore) == 0: return # Get the path path = self.files_treestore[0][0].rstrip('\\/') torrent_filename = '%s.torrent' % os.path.split(path)[-1] is_remote = self.files_treestore[0][1] == gtk.STOCK_NETWORK if is_remote: # This is a remote path dialog = self.builder.get_object('remote_save_dialog') dialog.set_transient_for(self.dialog) dialog_save_path = self.builder.get_object('entry_save_path') dialog_save_path.set_text(path + '.torrent') response = dialog.run() if response == gtk.RESPONSE_OK: result = dialog_save_path.get_text() else: dialog.hide() return dialog.hide() else: # Setup the filechooserdialog chooser = gtk.FileChooserDialog( _('Save .torrent file'), self.dialog, gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) chooser.set_transient_for(self.dialog) chooser.set_select_multiple(False) chooser.set_property('skip-taskbar-hint', True) # Add .torrent and * file filters file_filter = gtk.FileFilter() file_filter.set_name(_('Torrent files')) file_filter.add_pattern('*.' + 'torrent') chooser.add_filter(file_filter) file_filter = gtk.FileFilter() file_filter.set_name(_('All files')) file_filter.add_pattern('*') chooser.add_filter(file_filter) chooser.set_current_name(torrent_filename) # Run the dialog response = chooser.run() if response == gtk.RESPONSE_OK: result = chooser.get_filename() else: chooser.destroy() return chooser.destroy() # Fix up torrent filename if len(result) < 9: result += '.torrent' elif result[-8:] != '.torrent': result += '.torrent' # Get a list of trackers trackers = [] if not len(self.trackers_liststore): tracker = None else: # Create a list of lists [[tier0, ...], [tier1, ...], ...] tier_dict = {} for tier, tracker in self.trackers_liststore: tier_dict.setdefault(tier, []).append(tracker) trackers = [tier_dict[tier] for tier in sorted(tier_dict)] # Get the first tracker in the first tier tracker = trackers[0][0] # Get a list of webseeds textview_buf = self.builder.get_object( 'textview_webseeds').get_buffer() lines = textview_buf.get_text( *textview_buf.get_bounds()).strip().split('\n') webseeds = [] for line in lines: line = line.replace('\\', '/') # Fix any mistyped urls. if is_url(line): webseeds.append(line) # Get the piece length in bytes combo = self.builder.get_object('combo_piece_size') piece_length = self.parse_piece_size_text( combo.get_model()[combo.get_active()][0]) author = self.builder.get_object('entry_author').get_text() comment = self.builder.get_object('entry_comments').get_text() private = self.builder.get_object('chk_private_flag').get_active() add_to_session = self.builder.get_object( 'chk_add_to_session').get_active() if is_remote: def torrent_created(): self.builder.get_object('progress_dialog').hide_all() client.deregister_event_handler( 'CreateTorrentProgressEvent', on_create_torrent_progress_event) def on_create_torrent_progress_event(piece_count, num_pieces): self._on_create_torrent_progress(piece_count, num_pieces) if piece_count == num_pieces: from twisted.internet import reactor reactor.callLater(0.5, torrent_created) client.register_event_handler('CreateTorrentProgressEvent', on_create_torrent_progress_event) client.core.create_torrent(path, tracker, piece_length, comment, result, webseeds, private, author, trackers, add_to_session) else: def hide_progress(result): self.builder.get_object('progress_dialog').hide_all() deferToThread(self.create_torrent, path.decode('utf-8'), tracker, piece_length, self._on_create_torrent_progress, comment, result.decode('utf-8'), webseeds, private, author, trackers, add_to_session).addCallback(hide_progress) # Setup progress dialog self.builder.get_object('progress_dialog').set_transient_for( component.get('MainWindow').window) self.builder.get_object('progress_dialog').show_all() self.dialog.destroy()
def walk(self, force=False): """Implemets automatic torrent updates process. Automatic update is available for torrents selected by user and having tracker's page URL in torrent's `comment` field. Besides that torrent a tracker handler class should be associated with domain from the URL mentioned above. If `force` set to a list of torrent IDs, only those torrents will be checked for updates. If `force` is False every torrent scheduled to updates by used will be checked. """ # To prevent possible concurent runs. self.walking = True try: log.info('Updatorr walking...') component.get('EventManager').emit(UpdatorrUpdatesCheckStartedEvent()) allow_last_walk_update = False if isinstance(force, list): torrents_list = force else: torrents_list = self.torrents_to_update for torrent_id in torrents_list: try: torrent_data = self.core.get_torrent_status(torrent_id, []) log.info('Updatorr Processing %s ...' % torrent_data['name']) except KeyError: log.debug('Updatorr \tSKIPPED No torrent with id %s listed [yet]' % torrent_id) continue # Remove not url data from comment torrent_data['comment'] = RE_LINK.search(torrent_data['comment']).group('url') if not is_url(torrent_data['comment']): log.info('Updatorr \tSKIPPED No URL found in torrent comment') continue # From now on we consider that update took its place. # If only this update is not forced. if not force: allow_last_walk_update = True tracker_handler = get_tracker_handler(torrent_data, log) if tracker_handler is None: self.dump_error(torrent_id, 'Unable to find tracker handler for %s' % torrent_data['comment']) continue tracker_handler.set_settings(self.trackers_settings.get(tracker_handler.tracker_host)) new_torrent_filepath = tracker_handler.get_torrent_file() if new_torrent_filepath is None: self.dump_error(torrent_id, 'Error in tracker handling: %s' % tracker_handler.get_error_text()) continue # Let's store cookies form that tracker to enter without logins in future sessions. self.trackers_settings[tracker_handler.tracker_host]['cookies'] = tracker_handler.get_cookies(as_dict=True) new_torrent_contents = read_torrent_file(new_torrent_filepath) new_torrent_info = read_torrent_info(new_torrent_contents) if torrent_data['hash'] == new_torrent_info['hash']: log.info('Updatorr \tSKIPPED Torrent is up-to-date') continue log.info('Updatorr \tTorrent update is available') new_torrent_prefs = get_new_prefs(torrent_data, new_torrent_info) added_torrent_id = self.core.add_torrent_file(None, base64.encodestring(new_torrent_contents), new_torrent_prefs) if added_torrent_id is not None: self.core.remove_torrent(torrent_id, False) log.info('Updatorr \tTorrent is updated') # Fire up update finished event. component.get('EventManager').emit(UpdatorrUpdateDoneEvent(new_torrent_info['hash'])) # Add new torrent hash to continue autoupdates. self.set_items_to_update(new_torrent_info['hash'], True) # Remove old torrent from autoupdates list. self.set_items_to_update(torrent_id, False) else: self.dump_error(torrent_id, 'Unable to replace current torrent with a new one') # No littering, remove temporary .torrent file. os.remove(new_torrent_filepath) if allow_last_walk_update: # Remember lastrun time. self.last_walk = time.time() log.info('Updatorr walk is finished') component.get('EventManager').emit(UpdatorrUpdatesCheckFinishedEvent()) except: log.error(traceback.format_exc()) finally: self.walking = False