def start_download(self, torrentfilename=None, infohash=None, tdef=None, dconfig=None): self._logger.debug(u"starting download: filename: %s, torrent def: %s", torrentfilename, tdef) if infohash is not None: assert isinstance(infohash, str), "infohash type: %s" % type(infohash) assert len(infohash) == 20, "infohash length is not 20: %s, %s" % ( len(infohash), infohash) # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file. # so if we have tdef, infohash and torrent_file will be ignored, and so on. if tdef is None: if infohash is not None: # try to get the torrent from torrent_store if the infohash is provided torrent_data = self.trsession.get_collected_torrent(infohash) if torrent_data is not None: # use this torrent data for downloading tdef = TorrentDef.load_from_memory(torrent_data) if tdef is None: assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given" # try to get the torrent from the given torrent file torrent_data = fix_torrent(torrentfilename) if torrent_data is None: raise TorrentFileException( "error while decoding torrent file") tdef = TorrentDef.load_from_memory(torrent_data) assert tdef is not None, "tdef MUST not be None after loading torrent" d = self.trsession.get_download(tdef.get_infohash()) if d: new_trackers = list( set(tdef.get_trackers_as_single_tuple()) - set(d.get_def().get_trackers_as_single_tuple())) if not new_trackers: raise DuplicateDownloadException( "This download already exists.") else: self.trsession.update_trackers(tdef.get_infohash(), new_trackers) return default_dl_config = DefaultDownloadStartupConfig.getInstance() dscfg = default_dl_config.copy() if dconfig is not None: dscfg = dconfig self._logger.info('start_download: Starting in VOD mode') result = self.trsession.start_download_from_tdef(tdef, dscfg) return result
def check_watch_folder(self): if not os.path.isdir(self.session.config.get_watch_folder_path()): return for root, _, files in os.walk( self.session.config.get_watch_folder_path()): for name in files: if not name.endswith(u".torrent"): continue try: tdef = TorrentDef.load_from_memory( fix_torrent(os.path.join(root, name))) except: # torrent appears to be corrupt self.cleanup_torrent_file(root, name) continue infohash = tdef.get_infohash() if not self.session.has_download(infohash): self._logger.info("Starting download from torrent file %s", name) dl_config = DefaultDownloadStartupConfig.getInstance( ).copy() anon_enabled = self.session.config.get_default_anonymity_enabled( ) default_num_hops = self.session.config.get_default_number_hops( ) dl_config.set_hops(default_num_hops if anon_enabled else 0) dl_config.set_safe_seeding( self.session.config.get_default_safeseeding_enabled()) self.session.lm.ltmgr.start_download(tdef=tdef, dconfig=dl_config)
def check_watch_folder(self): if not os.path.isdir(self.session.config.get_watch_folder_path()): return for root, _, files in os.walk(self.session.config.get_watch_folder_path()): for name in files: if not name.endswith(u".torrent"): continue try: tdef = TorrentDef.load_from_memory(fix_torrent(os.path.join(root, name))) except: # torrent appears to be corrupt self.cleanup_torrent_file(root, name) continue infohash = tdef.get_infohash() if not self.session.has_download(infohash): self._logger.info("Starting download from torrent file %s", name) dl_config = DefaultDownloadStartupConfig.getInstance().copy() anon_enabled = self.session.config.get_default_anonymity_enabled() default_num_hops = self.session.config.get_default_number_hops() dl_config.set_hops(default_num_hops if anon_enabled else 0) dl_config.set_safe_seeding(self.session.config.get_default_safeseeding_enabled()) dl_config.set_dest_dir(self.session.config.get_default_destination_dir()) self.session.lm.ltmgr.start_download(tdef=tdef, dconfig=dl_config)
def check_watch_folder(self): if not os.path.isdir(self.session.get_watch_folder_path()): return for root, _, files in os.walk(self.session.get_watch_folder_path()): for name in files: if not name.endswith(u".torrent"): continue torrent_data = fix_torrent(os.path.join(root, name)) if not torrent_data: # torrent appears to be corrupt os.rename(os.path.join(root, name), os.path.join(root, name + ".corrupt")) self._logger.warning( "Watch folder - corrupt torrent file %s", name) self.session.notifier.notify( NTFY_WATCH_FOLDER_CORRUPT_TORRENT, NTFY_INSERT, None, name) continue tdef = TorrentDef.load_from_memory(torrent_data) infohash = tdef.get_infohash() if not self.session.has_download(infohash): self._logger.info("Starting download from torrent file %s", name) self.session.lm.ltmgr.start_download(tdef=tdef)
def on_file(): try: filename = url2pathname(uri[5:].encode('utf-8') if isinstance(uri, text_type) else uri[5:]) if filename.endswith(BLOB_EXTENSION): return on_mdblob(filename) metainfo_deferred.callback(bdecode(fix_torrent(filename))) return NOT_DONE_YET except TypeError: request.setResponseCode(http.INTERNAL_SERVER_ERROR) return json.dumps({"error": "error while decoding torrent file"})
def start_download(self, torrentfilename=None, infohash=None, tdef=None, dconfig=None): self._logger.debug(u"starting download: filename: %s, torrent def: %s", torrentfilename, tdef) if infohash is not None: assert isinstance(infohash, str), "infohash type: %s" % type(infohash) assert len(infohash) == 20, "infohash length is not 20: %s, %s" % (len(infohash), infohash) # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file. # so if we have tdef, infohash and torrent_file will be ignored, and so on. if tdef is None: if infohash is not None: # try to get the torrent from torrent_store if the infohash is provided torrent_data = self.tribler_session.get_collected_torrent(infohash) if torrent_data is not None: # use this torrent data for downloading tdef = TorrentDef.load_from_memory(torrent_data) if tdef is None: assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given" # try to get the torrent from the given torrent file torrent_data = fix_torrent(torrentfilename) if torrent_data is None: raise TorrentFileException("error while decoding torrent file") tdef = TorrentDef.load_from_memory(torrent_data) assert tdef is not None, "tdef MUST not be None after loading torrent" default_dl_config = DefaultDownloadStartupConfig.getInstance() dscfg = default_dl_config.copy() if dconfig is not None: dscfg = dconfig d = self.tribler_session.get_download(tdef.get_infohash()) if d: # If there is an existing credit mining download with the same infohash # then move to the user download directory and checkpoint the download immediately. if d.get_credit_mining(): self.tribler_session.lm.credit_mining_manager.torrents.pop(hexlify(tdef.get_infohash()), None) d.set_credit_mining(False) d.move_storage(dscfg.get_dest_dir()) d.checkpoint() new_trackers = list(set(tdef.get_trackers_as_single_tuple()) - set( d.get_def().get_trackers_as_single_tuple())) if new_trackers: self.tribler_session.update_trackers(tdef.get_infohash(), new_trackers) self._logger.info('start_download: Starting in VOD mode') result = self.tribler_session.start_download_from_tdef(tdef, dscfg) return result
def start_download(self, torrentfilename=None, infohash=None, tdef=None, dconfig=None): self._logger.debug(u"starting download: filename: %s, torrent def: %s", torrentfilename, tdef) if infohash is not None: assert isinstance(infohash, str), "infohash type: %s" % type(infohash) assert len(infohash) == 20, "infohash length is not 20: %s, %s" % (len(infohash), infohash) # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file. # so if we have tdef, infohash and torrent_file will be ignored, and so on. if tdef is None: if infohash is not None: # try to get the torrent from torrent_store if the infohash is provided torrent_data = self.tribler_session.get_collected_torrent(infohash) if torrent_data is not None: # use this torrent data for downloading tdef = TorrentDef.load_from_memory(torrent_data) if tdef is None: assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given" # try to get the torrent from the given torrent file torrent_data = fix_torrent(torrentfilename) if torrent_data is None: raise TorrentFileException("error while decoding torrent file") tdef = TorrentDef.load_from_memory(torrent_data) assert tdef is not None, "tdef MUST not be None after loading torrent" d = self.tribler_session.get_download(tdef.get_infohash()) if d: # If there is an existing credit mining download with the same infohash, remove it and restart if d.get_credit_mining(): self.tribler_session.lm.credit_mining_manager.torrents.pop(hexlify(tdef.get_infohash()), None) self.tribler_session.remove_download(d).addCallback( lambda _, tf=torrentfilename, ih=infohash, td=tdef, dc=dconfig: self.start_download(tf, ih, td, dc) ) return new_trackers = list(set(tdef.get_trackers_as_single_tuple()) - set( d.get_def().get_trackers_as_single_tuple())) if new_trackers: self.tribler_session.update_trackers(tdef.get_infohash(), new_trackers) default_dl_config = DefaultDownloadStartupConfig.getInstance() dscfg = default_dl_config.copy() if dconfig is not None: dscfg = dconfig self._logger.info('start_download: Starting in VOD mode') result = self.tribler_session.start_download_from_tdef(tdef, dscfg) return result
def on_file(): try: filename = url2pathname(uri[5:].encode('utf-8') if isinstance( uri, text_type) else uri[5:]) if filename.endswith(BLOB_EXTENSION): return on_mdblob(filename) metainfo_deferred.callback(bdecode(fix_torrent(filename))) return NOT_DONE_YET except TypeError: request.setResponseCode(http.INTERNAL_SERVER_ERROR) return json.dumps( {"error": "error while decoding torrent file"})
def test_reimport_torrents(self): self.copy_and_initialize_upgrade_database('tribler_v17.sdb') self.torrent_store = LevelDbStore(self.session.config.get_torrent_store_dir()) db_migrator = DBUpgrader(self.session, self.sqlitedb, torrent_store=self.torrent_store) db_migrator.start_migrate() # Import a torrent self.torrent_store[TORRENT_UBUNTU_FILE_INFOHASH] = fix_torrent(TORRENT_UBUNTU_FILE) self.torrent_store.flush() db_migrator.reimport_torrents() torrent_db_handler = TorrentDBHandler(self.session) self.assertEqual(torrent_db_handler.getTorrentID(TORRENT_UBUNTU_FILE_INFOHASH), 3)
def test_reimport_torrents(self): self.copy_and_initialize_upgrade_database('tribler_v17.sdb') self.torrent_store = LevelDbStore(self.session.get_torrent_store_dir()) db_migrator = DBUpgrader(self.session, self.sqlitedb, torrent_store=self.torrent_store) db_migrator.start_migrate() # Import a torrent self.torrent_store[TORRENT_FILE_INFOHASH] = fix_torrent(TORRENT_FILE) self.torrent_store.flush() db_migrator.reimport_torrents() torrent_db_handler = TorrentDBHandler(self.session) self.assertEqual(torrent_db_handler.getTorrentID(TORRENT_FILE_INFOHASH), 3)
def render_GET(self, request): """ .. http:get:: /torrentinfo A GET request to this endpoint will return information from a torrent found at a provided URI. This URI can either represent a file location, a magnet link or a HTTP(S) url. - torrent: the URI of the torrent file that should be downloaded. This parameter is required. **Example request**: .. sourcecode:: none curl -X PUT http://localhost:8085/torrentinfo?torrent=file:/home/me/test.torrent **Example response**: .. sourcecode:: javascript {"metainfo": <torrent metainfo dictionary>} """ metainfo_deferred = Deferred() def on_got_metainfo(metainfo): if not isinstance(metainfo, dict) or 'info' not in metainfo: self._logger.warning( "Received metainfo is not a valid dictionary") request.setResponseCode(http.INTERNAL_SERVER_ERROR) request.write(json.dumps({"error": 'invalid response'})) self.finish_request(request) return infohash = hashlib.sha1(bencode(metainfo['info'])).digest() # Save the torrent to our store try: self.session.save_collected_torrent(infohash, bencode(metainfo)) except TypeError: # Note: in libtorrent 1.1.1, bencode throws a TypeError which is a known bug pass request.write( json.dumps({"metainfo": metainfo}, ensure_ascii=False)) self.finish_request(request) def on_metainfo_timeout(_): if not request.finished: request.setResponseCode(http.REQUEST_TIMEOUT) request.write(json.dumps({"error": "timeout"})) # If the above request.write failed, the request will have already been finished if not request.finished: self.finish_request(request) def on_lookup_error(failure): failure.trap(ConnectError, DNSLookupError, HttpError) request.setResponseCode(http.INTERNAL_SERVER_ERROR) request.write(json.dumps({"error": failure.getErrorMessage()})) self.finish_request(request) if 'uri' not in request.args or len(request.args['uri']) == 0: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "uri parameter missing"}) uri = unicode(request.args['uri'][0], 'utf-8') if uri.startswith('file:'): try: filename = url2pathname(uri[5:].replace("+", " ")) metainfo_deferred.callback(bdecode(fix_torrent(filename))) except TypeError: request.setResponseCode(http.INTERNAL_SERVER_ERROR) return json.dumps( {"error": "error while decoding torrent file"}) elif uri.startswith('http'): def _on_loaded(metadata): metainfo_deferred.callback(bdecode(metadata)) http_get(uri.encode('utf-8')).addCallback(_on_loaded).addErrback( on_lookup_error) elif uri.startswith('magnet'): infohash = parse_magnetlink(uri)[1] if infohash is None: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "missing infohash"}) if self.session.has_collected_torrent(infohash): try: tdef = TorrentDef.load_from_memory( self.session.get_collected_torrent(infohash)) except ValueError as exc: request.setResponseCode(http.INTERNAL_SERVER_ERROR) return json.dumps( {"error": "invalid torrent file: %s" % str(exc)}) on_got_metainfo(tdef.get_metainfo()) return NOT_DONE_YET self.session.lm.ltmgr.get_metainfo( uri, callback=metainfo_deferred.callback, timeout=20, timeout_callback=on_metainfo_timeout, notify=True) else: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "invalid uri"}) metainfo_deferred.addCallback(on_got_metainfo) return NOT_DONE_YET
def startDownload(self, torrentfilename=None, destdir=None, infohash=None, tdef=None, cmdline=False, vodmode=False, hops=0, selectedFiles=None, hidden=False): self._logger.debug(u"startDownload: %s %s %s %s %s", torrentfilename, destdir, tdef, vodmode, selectedFiles) # TODO(lipu): remove the assertions after it becomes stable if infohash is not None: assert isinstance(infohash, str), "infohash type: %s" % type(infohash) assert len(infohash) == 20, "infohash length is not 20: %s, %s" % ( len(infohash), infohash) # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file. # so if we have tdef, infohash and torrent_file will be ignored, and so on. if tdef is None: if infohash is not None: # try to get the torrent from torrent_store if the infohash is provided torrent_data = self.utility.session.get_collected_torrent( infohash) if torrent_data is not None: # use this torrent data for downloading tdef = TorrentDef.load_from_memory(torrent_data) if tdef is None: assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given" # try to get the torrent from the given torrent file torrent_data = fix_torrent(torrentfilename) if torrent_data is None: # show error message: could not open torrent file dlg = wx.MessageBox( self, "Could not open torrent file %s" % torrentfilename, "Error", wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return tdef = TorrentDef.load_from_memory(torrent_data) assert tdef is not None, "tdef MUST not be None after loading torrent" try: d = self.utility.session.get_download(tdef.get_infohash()) if d: new_trackers = list( set(tdef.get_trackers_as_single_tuple()) - set(d.get_def().get_trackers_as_single_tuple())) if not new_trackers: raise DuplicateDownloadException() else: @forceWxThread def do_gui(): # Show update tracker dialog dialog = wx.MessageDialog( None, 'This torrent is already being downloaded. Do you wish to load the trackers from it?', 'Tribler', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) if dialog.ShowModal() == wx.ID_YES: # Update trackers self.utility.session.update_trackers( tdef.get_infohash(), new_trackers) dialog.Destroy() do_gui() return defaultDLConfig = DefaultDownloadStartupConfig.getInstance() dscfg = defaultDLConfig.copy() cancelDownload = False useDefault = not self.utility.read_config('showsaveas') safe_seeding = self.utility.read_config( 'default_safeseeding_enabled') if not useDefault and not destdir: defaultname = tdef.get_name_as_unicode( ) if tdef.is_multifile_torrent() else None if wx.Thread_IsMain(): dlg = SaveAs(None, tdef, dscfg.get_dest_dir(), defaultname, selectedFiles) dlg.CenterOnParent() if isinstance(tdef, TorrentDefNoMetainfo): # Correct for the smaller size of the dialog if there is no metainfo center_pos = dlg.GetPosition() center_pos[1] -= 150 dlg.SetPosition(center_pos) if dlg.ShowModal() == wx.ID_OK: # If the dialog has collected a torrent, use the new tdef tdef = dlg.GetCollected() or tdef if tdef and tdef.is_multifile_torrent(): selectedFiles = dlg.GetSelectedFiles() destdir = dlg.GetPath() # Anonymity over exit nodes or hidden services safe_seeding = dlg.UseSafeSeeding() if dlg.UseTunnels(): hops = self.utility.read_config( 'default_number_hops') else: cancelDownload = True dlg.Destroy() else: raise Exception("cannot create dialog, not on wx thread") # use default setup else: if useDefault: if self.utility.read_config('default_anonymity_enabled'): # only load default anonymous level if we use default settings hops = self.utility.read_config('default_number_hops') else: hops = 0 if hops > 0: if not tdef: raise Exception( 'Currently only torrents can be downloaded in anonymous mode' ) dscfg.set_hops(hops) dscfg.set_safe_seeding(safe_seeding) if not cancelDownload: if destdir is not None: dscfg.set_dest_dir(destdir) if selectedFiles and len(selectedFiles) == 1: # we should filter files to see if they are all playable videofiles = selectedFiles elif tdef and not selectedFiles: videofiles = tdef.get_files(exts=videoextdefaults) else: videofiles = [] # disable vodmode if no videofiles, unless we still need to collect the torrent if vodmode and len(videofiles) == 0 and ( not tdef or not isinstance(tdef, TorrentDefNoMetainfo)): vodmode = False if vodmode: self._logger.info( 'MainFrame: startDownload: Starting in VOD mode') result = self.utility.session.start_download_from_tdef( tdef, dscfg) self.guiUtility.library_manager.playTorrent( tdef.get_infohash(), videofiles[0] if len(videofiles) == 1 else None) else: if selectedFiles: dscfg.set_selected_files(selectedFiles) self._logger.debug( 'MainFrame: startDownload: Starting in DL mode') result = self.utility.session.start_download_from_tdef( tdef, dscfg, hidden=hidden) if result and not hidden: self.show_saved(tdef) return result except DuplicateDownloadException as e: # If there is something on the cmdline, all other torrents start # in STOPPED state. Restart if cmdline: dlist = self.utility.session.get_downloads() for d in dlist: if d.get_def().get_infohash() == tdef.get_infohash(): d.restart() break if wx.Thread_IsMain(): # show nice warning dialog dlg = wx.MessageDialog( None, "You are already downloading this torrent, see the Downloads section.", "Duplicate download", wx.OK | wx.ICON_ERROR) result = dlg.ShowModal() dlg.Destroy() else: print_exc() self.onWarning(e) except Exception as e: print_exc() self.onWarning(e) return None
def startDownload(self, torrentfilename=None, destdir=None, infohash=None, tdef=None, cmdline=False, vodmode=False, hops=0, selectedFiles=None, hidden=False): self._logger.debug(u"startDownload: %s %s %s %s %s", torrentfilename, destdir, tdef, vodmode, selectedFiles) # TODO(lipu): remove the assertions after it becomes stable if infohash is not None: assert isinstance(infohash, str), "infohash type: %s" % type(infohash) assert len(infohash) == 20, "infohash length is not 20: %s, %s" % (len(infohash), infohash) # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file. # so if we have tdef, infohash and torrent_file will be ignored, and so on. if tdef is None: if infohash is not None: # try to get the torrent from torrent_store if the infohash is provided torrent_data = self.utility.session.get_collected_torrent(infohash) if torrent_data is not None: # use this torrent data for downloading tdef = TorrentDef.load_from_memory(torrent_data) if tdef is None: assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given" # try to get the torrent from the given torrent file torrent_data = fix_torrent(torrentfilename) if torrent_data is None: # show error message: could not open torrent file dlg = wx.MessageBox(self, "Could not open torrent file %s" % torrentfilename, "Error", wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return tdef = TorrentDef.load_from_memory(torrent_data) assert tdef is not None, "tdef MUST not be None after loading torrent" try: d = self.utility.session.get_download(tdef.get_infohash()) if d: new_trackers = list(set(tdef.get_trackers_as_single_tuple()) - set( d.get_def().get_trackers_as_single_tuple())) if not new_trackers: raise DuplicateDownloadException() else: @forceWxThread def do_gui(): # Show update tracker dialog dialog = wx.MessageDialog( None, 'This torrent is already being downloaded. Do you wish to load the trackers from it?', 'Tribler', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) if dialog.ShowModal() == wx.ID_YES: # Update trackers self.utility.session.update_trackers(tdef.get_infohash(), new_trackers) dialog.Destroy() do_gui() return defaultDLConfig = DefaultDownloadStartupConfig.getInstance() dscfg = defaultDLConfig.copy() cancelDownload = False useDefault = not self.utility.read_config('showsaveas') safe_seeding = self.utility.read_config('default_safeseeding_enabled') if not useDefault and not destdir: defaultname = tdef.get_name_as_unicode() if tdef.is_multifile_torrent() else None if wx.Thread_IsMain(): dlg = SaveAs(None, tdef, dscfg.get_dest_dir(), defaultname, selectedFiles) dlg.CenterOnParent() if isinstance(tdef, TorrentDefNoMetainfo): # Correct for the smaller size of the dialog if there is no metainfo center_pos = dlg.GetPosition() center_pos[1] -= 150 dlg.SetPosition(center_pos) if dlg.ShowModal() == wx.ID_OK: # If the dialog has collected a torrent, use the new tdef tdef = dlg.GetCollected() or tdef if tdef and tdef.is_multifile_torrent(): selectedFiles = dlg.GetSelectedFiles() destdir = dlg.GetPath() # Anonymity over exit nodes or hidden services safe_seeding = dlg.UseSafeSeeding() if dlg.UseTunnels(): hops = self.utility.read_config('default_number_hops') else: cancelDownload = True dlg.Destroy() else: raise Exception("cannot create dialog, not on wx thread") # use default setup else: if useDefault: if self.utility.read_config('default_anonymity_enabled'): # only load default anonymous level if we use default settings hops = self.utility.read_config('default_number_hops') else: hops = 0 if hops > 0: if not tdef: raise Exception('Currently only torrents can be downloaded in anonymous mode') dscfg.set_hops(hops) dscfg.set_safe_seeding(safe_seeding) if not cancelDownload: if destdir is not None: dscfg.set_dest_dir(destdir) if selectedFiles and len(selectedFiles) == 1: # we should filter files to see if they are all playable videofiles = selectedFiles elif tdef and not selectedFiles: videofiles = tdef.get_files(exts=videoextdefaults) else: videofiles = [] # disable vodmode if no videofiles, unless we still need to collect the torrent if vodmode and len(videofiles) == 0 and (not tdef or not isinstance(tdef, TorrentDefNoMetainfo)): vodmode = False if vodmode: self._logger.info('MainFrame: startDownload: Starting in VOD mode') result = self.utility.session.start_download(tdef, dscfg) self.guiUtility.library_manager.playTorrent( tdef.get_infohash(), videofiles[0] if len(videofiles) == 1 else None) else: if selectedFiles: dscfg.set_selected_files(selectedFiles) self._logger.debug('MainFrame: startDownload: Starting in DL mode') result = self.utility.session.start_download(tdef, dscfg, hidden=hidden) if result and not hidden: self.show_saved(tdef) return result except DuplicateDownloadException as e: # If there is something on the cmdline, all other torrents start # in STOPPED state. Restart if cmdline: dlist = self.utility.session.get_downloads() for d in dlist: if d.get_def().get_infohash() == tdef.get_infohash(): d.restart() break if wx.Thread_IsMain(): # show nice warning dialog dlg = wx.MessageDialog(None, "You are already downloading this torrent, see the Downloads section.", "Duplicate download", wx.OK | wx.ICON_ERROR) result = dlg.ShowModal() dlg.Destroy() else: print_exc() self.onWarning(e) except Exception as e: print_exc() self.onWarning(e) return None