docs: def mainloop(self):
          """ The main loop.
          """
          if not self.args:
              self.parser.error("No metafiles given, nothing to do!")
  
          if 1 < sum(bool(i) for i in (self.options.no_ssl, self.options.reannounce, self.options.reannounce_all)):
              self.parser.error("Conflicting options --no-ssl, --reannounce and --reannounce-all!")
  
          # Set filter criteria for metafiles
          filter_url_prefix = None
          if self.options.reannounce:
              # <scheme>://<netloc>/<path>?<query>
              filter_url_prefix = urlparse.urlsplit(self.options.reannounce, allow_fragments=False)
              filter_url_prefix = urlparse.urlunsplit((
                  filter_url_prefix.scheme, filter_url_prefix.netloc, '/', '', '' # bogus pylint: disable=E1103
              ))
              self.LOG.info("Filtering for metafiles with announce URL prefix %r..." % filter_url_prefix)
  
          if self.options.reannounce_all:
              self.options.reannounce = self.options.reannounce_all
          else:
              # When changing the announce URL w/o changing the domain, don't change the info hash!
              self.options.no_cross_seed = True
  
          # Resolve tracker alias, if URL doesn't look like an URL
          if self.options.reannounce and not urlparse.urlparse(self.options.reannounce).scheme:
              tracker_alias, idx = self.options.reannounce, "0"
              if '.' in tracker_alias:
                  tracker_alias, idx = tracker_alias.split('.', 1)
              try:
                  idx = int(idx, 10)
                  _, tracker_url = config.lookup_announce_alias(tracker_alias)
                  self.options.reannounce = tracker_url[idx]
              except (KeyError, IndexError, TypeError, ValueError) as exc:
                  raise error.UserError("Unknown tracker alias or bogus URL %r (%s)!" % (
                      self.options.reannounce, exc))
  
          # go through given files
          bad = 0
          changed = 0
          for filename in self.args:
              try:
                  # Read and remember current content
                  metainfo = bencode.bread(filename)
                  old_metainfo = bencode.bencode(metainfo)
              except (EnvironmentError, KeyError, bencode.BencodeError) as exc:
                  self.LOG.warning("Skipping bad metafile %r (%s: %s)" % (filename, type(exc).__name__, exc))
                  bad += 1
              else:
                  # Check metafile integrity
                  try:
                      metafile.check_meta(metainfo)
                  except ValueError as exc:
                      self.LOG.warn("Metafile %r failed integrity check: %s" % (filename, exc,))
                      if not self.options.no_skip:
                          continue
  
                  # Skip any metafiles that don't meet the pre-conditions
                  if filter_url_prefix and not metainfo['announce'].startswith(filter_url_prefix):
                      self.LOG.warn("Skipping metafile %r no tracked by %r!" % (filename, filter_url_prefix,))
                      continue
  
                  # Keep resume info safe
                  libtorrent_resume = {}
                  if "libtorrent_resume" in metainfo:
                      try:
                          libtorrent_resume["bitfield"] = metainfo["libtorrent_resume"]["bitfield"]
                      except KeyError:
                          pass # nothing to remember
  
                      libtorrent_resume["files"] = copy.deepcopy(metainfo["libtorrent_resume"]["files"])
  
                  # Change private flag?
                  if self.options.make_private and not metainfo["info"].get("private", 0):
                      self.LOG.info("Setting private flag...")
                      metainfo["info"]["private"] = 1
                  if self.options.make_public and metainfo["info"].get("private", 0):
                      self.LOG.info("Clearing private flag...")
                      del metainfo["info"]["private"]
  
                  # Remove non-standard keys?
                  if self.options.clean or self.options.clean_all or self.options.clean_xseed:
                      metafile.clean_meta(metainfo, including_info=not self.options.clean, logger=self.LOG.info)
  
                  # Restore resume info?
                  if self.options.clean_xseed:
                      if libtorrent_resume:
                          self.LOG.info("Restoring key 'libtorrent_resume'...")
                          metainfo.setdefault("libtorrent_resume", {})
                          metainfo["libtorrent_resume"].update(libtorrent_resume)
                      else:
                          self.LOG.warn("No resume information found!")
  
                  # Clean rTorrent data?
                  if self.options.clean_rtorrent:
                      for key in self.RT_RESUMT_KEYS:
                          if key in metainfo:
                              self.LOG.info("Removing key %r..." % (key,))
                              del metainfo[key]
  
                  # Change announce URL?
                  if self.options.reannounce:
                      metainfo['announce'] = self.options.reannounce
                      if "announce-list" in metainfo:
                          del metainfo["announce-list"]
  
                      if not self.options.no_cross_seed:
                          # Enforce unique hash per tracker
                          metainfo["info"]["x_cross_seed"] = hashlib.md5(self.options.reannounce).hexdigest()
                  if self.options.no_ssl:
                      # We're assuming here the same (default) port is used
                      metainfo['announce'] = (metainfo['announce']
                          .replace("https://", "http://").replace(":443/", ":80/"))
  
                  # Change comment or creation date?
                  if self.options.comment is not None:
                      if self.options.comment:
                          metainfo["comment"] = self.options.comment
                      elif "comment" in metainfo:
                          del metainfo["comment"]
                  if self.options.bump_date:
                      metainfo["creation date"] = int(time.time())
                  if self.options.no_date and "creation date" in metainfo:
                      del metainfo["creation date"]
  
                  # Add fast-resume data?
                  if self.options.hashed:
                      try:
                          metafile.add_fast_resume(metainfo, self.options.hashed.replace("{}", metainfo["info"]["name"]))
                      except EnvironmentError as exc:
                          self.fatal("Error making fast-resume data (%s)" % (exc,))
                          raise
  
                  # Set specific keys?
                  metafile.assign_fields(metainfo, self.options.set)
                  replace_fields(metainfo, self.options.regex)
  
                  # Write new metafile, if changed
                  new_metainfo = bencode.bencode(metainfo)
                  if new_metainfo != old_metainfo:
                      if self.options.output_directory:
                          filename = os.path.join(self.options.output_directory, os.path.basename(filename))
                          self.LOG.info("Writing %r..." % filename)
  
                          if not self.options.dry_run:
                              bencode.bwrite(filename, metainfo)
                              if "libtorrent_resume" in metainfo:
                                  # Also write clean version
                                  filename = filename.replace(".torrent", "-no-resume.torrent")
                                  del metainfo["libtorrent_resume"]
                                  self.LOG.info("Writing %r..." % filename)
                                  bencode.bwrite(filename, metainfo)
                      else:
                          self.LOG.info("Changing %r..." % filename)
  
                          if not self.options.dry_run:
                              # Write to temporary file
                              tempname = os.path.join(
                                  os.path.dirname(filename),
                                  '.' + os.path.basename(filename),
                              )
                              self.LOG.debug("Writing %r..." % tempname)
                              bencode.bwrite(tempname, metainfo)
  
                              # Replace existing file
                              if os.name != "posix":
                                  # cannot rename to existing target on WIN32
                                  os.remove(filename)
  
                              try:
                                  os.rename(tempname, filename)
                              except EnvironmentError as exc:
                                  # TODO: Try to write directly, keeping a backup!
                                  raise error.LoggableError("Can't rename tempfile %r to %r (%s)" % (
                                      tempname, filename, exc
                                  ))
  
                      changed += 1
  
          # Print summary
          if changed:
              self.LOG.info("%s %d metafile(s)." % (
                  "Would've changed" if self.options.dry_run else "Changed", changed
              ))
          if bad:
              self.LOG.warn("Skipped %d bad metafile(s)!" % (bad))