Example #1
0
    def add(self, data, download_dir=None):
        """ Add a torrent to the client

        :param data: Torrent data to load in
        :type data: TorrentData
        :param download_dir: Path on deluge server to store download
        :type download_dir: basestring
        :return: Status of successful load (according to deluge)
        :rtype: bool
        """
        try:
            torrent = Torrent.from_str(data.torrent_data)
            try:
                self.torrent_status(torrent.info_hash)
            except KeyError:
                pass
            else:
                self.log.warn("Tried to load duplicate info hash: {}".format(
                    torrent.info_hash))
                return True
            torrent_data = b64encode(data.torrent_data)
            res = self.client.add_torrent(torrent_data,
                                          download_dir=download_dir)
        except TransmissionError as err:
            try:
                msg = err._message
            except AttributeError:
                msg = err.message
            if "duplicate torrent" in msg:
                self.log.warning("Tried to add duplicate torrent file")
                return True
            self.log.exception(err)
            return False

        return res
Example #2
0
    def parse_entry(self, session, entry):
        """ Parse RSS entry data for qualified torrents to download

        :param session: DB Session
        :type session: sqlalchemy.orm.session.Session
        :param entry: RSS Feed entry data
        :type entry: dict
        :return: A parsed release object ready to load into backend client or None on fail
        :rtype: release.TorrentData, None
        """

        release_name = entry.get('title', "")
        if not release_name:
            self.log.warning("No title parsed from RSS feed. Malformed?")
            return False
        release_info = parser.parse_release(release_name)
        if not release_info.release_key:
            self.log.warning("No release key parsed from release name: {}".format(release_name))
            return False
        release_key = release_info.release_key
        section_name = parser.validate_section(release_info)
        if not section_name or section_name == "section_movie":
            return False
        if self.exists(session, release_key) and not self.is_replacement(release_info):
            return False
        torrent_data = net.http_request(entry['link'], json=False)
        if not torrent_data:
            self.log.error("Failed to download torrent data from server: {0}".format(entry['link']))
            return False
        data = release.TorrentData(bytes(release_name), torrent_data, section_name), release_info
        torrent = Torrent.from_str(torrent_data)
        if not parser.valid_size(torrent, section_name):
            return False
        return data
Example #3
0
    def add(self, data, download_dir=None):
        """ Add a torrent to the client

        :param data: Torrent data to load in
        :type data: TorrentData
        :param download_dir: Path on deluge server to store download
        :type download_dir: basestring
        :return: Status of successful load (according to deluge)
        :rtype: bool
        """
        try:
            torrent = Torrent.from_str(data.torrent_data)
            try:
                self.torrent_status(torrent.info_hash)
            except KeyError:
                pass
            else:
                self.log.warn("Tried to load duplicate info hash: {}".format(torrent.info_hash))
                return True
            torrent_data = b64encode(data.torrent_data)
            res = self.client.add_torrent(torrent_data, download_dir=download_dir)
        except TransmissionError as err:
            try:
                msg = err._message
            except AttributeError:
                msg = err.message
            if "duplicate torrent" in msg:
                self.log.warning("Tried to add duplicate torrent file")
                return True
            self.log.exception(err)
            return False

        return res
Example #4
0
    def add(self, data, download_dir=None):

        try:
            torrent = Torrent.from_str(data)
            try:
                self.torrent_status(torrent.info_hash)
            except KeyError:
                pass
            else:
                self.log.warn("Tried to load duplicate info hash: {}".format(torrent.info_hash))
                return True
            encoded_data = b64encode(data)
            res = self.client.add(encoded_data, download_dir=download_dir)
        except TransmissionError as err:
            try:
                msg = err._message
            except AttributeError:
                msg = err.message
            if "duplicate torrent" in msg:
                self.log.warning("Tried to add duplicate torrent file")
                return True
            self.log.exception(err)
            return False

        return res
Example #5
0
 def add(self, torrent, download_dir=None):
     payload = xmlrpclib.Binary(torrent.torrent_data)
     info_hash = Torrent.from_str(torrent.torrent_data).info_hash.upper()
     # Make sure the xml-rpc size limit doesnt overflow
     self._server.set_xmlrpc_size_limit(len(torrent.torrent_data) * 2)
     self._server.load_raw(payload)
     if download_dir:
         self._server.d.set_directory_base(info_hash, download_dir)
     self._server.d.start(info_hash)
     return True
Example #6
0
 def add(self, torrent, download_dir=None):
     payload = xmlrpc.client.Binary(torrent.torrent_data)
     info_hash = Torrent.from_str(torrent.torrent_data).info_hash.upper()
     # Make sure the xml-rpc size limit doesnt overflow
     self._server.set_xmlrpc_size_limit(len(torrent.torrent_data) * 2)
     self._server.load_raw(payload)
     if download_dir:
         self._server.d.set_directory_base(info_hash, download_dir)
     self._server.d.start(info_hash)
     return True
Example #7
0
    def test_valid_size(self):
        t = Torrent.from_file(get_fixture("linux-iso.torrent"))
        section_name = "section_movie"
        config.set(section_name, "size_min", 1)
        config.set(section_name, "size_max", 10000)
        self.assertTrue(parser.valid_size(t, section_name))

        config.set(section_name, "size_max", 400)
        self.assertFalse(parser.valid_size(t, section_name))

        config.set(section_name, "size_min", 7000)
        config.set(section_name, "size_max", 10000)
        self.assertFalse(parser.valid_size(t, section_name))
Example #8
0
    def test_valid_size(self):
        t = Torrent.from_file(get_fixture("linux-iso.torrent"))
        section_name = "section_movie"
        config.set(section_name, "size_min", 1)
        config.set(section_name, "size_max", 10000)
        self.assertTrue(parser.valid_size(t, section_name))

        config.set(section_name, "size_max", 400)
        self.assertFalse(parser.valid_size(t, section_name))

        config.set(section_name, "size_min", 7000)
        config.set(section_name, "size_max", 10000)
        self.assertFalse(parser.valid_size(t, section_name))
Example #9
0
    def fetch_releases(self, session, scene_only=True):
        """ Generator which yields torrent data to be loaded into backend daemons

        :param session:
        :type session: sqlalchemy.orm.session.Session
        :param scene_only: Only fetch scene releases
        :type scene_only: bool
        :return: Matched Downloaded torrents
        :rtype: TorrentData[]
        """
        found = []
        try:
            releases = list(self.get_torrents_browse(50)['torrents'].values())
        except (TypeError, KeyError) as err:
            self.log.debug("Failed to fetch releases")
        else:
            if scene_only:
                releases = [
                    rls for rls in releases if rls['Origin'] == "Scene"
                ]
            for entry in releases:
                release_name = entry['ReleaseName']
                release_info = parser.parse_release(
                    release_name, guess_type=constants.MEDIA_TV)
                if not release_info:
                    continue
                section_name = parser.validate_section(release_info)
                if not section_name:
                    continue
                if self.exists(session, release_info.release_key
                               ) and not self.is_replacement(release_info):
                    continue
                #dl_url = self.get_torrent_url(entry['TorrentID'])
                torrent_data = net.http_request(entry['DownloadURL'],
                                                json=False)
                if not torrent_data:
                    self.log.error(
                        "Failed to download torrent data from server: {0}".
                        format(entry['link']))
                    continue
                data = release.TorrentData(str(release_name), torrent_data,
                                           section_name)
                torrent = Torrent.from_str(torrent_data)
                if not parser.valid_size(torrent, section_name):
                    continue
                yield data, release_info
Example #10
0
    def parse_entry(self, session, entry):
        """ Parse RSS entry data for qualified torrents to download

        :param session: DB Session
        :type session: sqlalchemy.orm.session.Session
        :param entry: RSS Feed entry data
        :type entry: dict
        :return: A parsed release object ready to load into backend client or None on fail
        :rtype: release.TorrentData, None
        """

        release_name = entry.get('title', "")
        if not release_name:
            self.log.warning("No title parsed from RSS feed. Malformed?")
            return False
        release_info = parser.parse_release(release_name)
        if not release_info.release_key:
            self.log.warning(
                "No release key parsed from release name: {}".format(
                    release_name))
            return False
        release_key = release_info.release_key
        section_name = parser.validate_section(release_info)
        if not section_name or section_name == "section_movie":
            return False
        if self.exists(session,
                       release_key) and not self.is_replacement(release_info):
            return False
        torrent_data = net.http_request(entry['link'], json=False)
        if not torrent_data:
            self.log.error(
                "Failed to download torrent data from server: {0}".format(
                    entry['link']))
            return False
        data = release.TorrentData(bytes(release_name), torrent_data,
                                   section_name), release_info
        torrent = Torrent.from_str(torrent_data)
        if not parser.valid_size(torrent, section_name):
            return False
        return data
Example #11
0
def add_torrents_from_cli(args):
    """ Parse command line args and try to load torrent files found

    :param args:
    :type args:
    :return:
    :rtype:
    """
    try:
        if len(args) <= 1:
            raise ConfigError("! Not enough arguments")

        torrent_data = []
        for torrent in args[1:]:
            try:
                torrent_data.append(open(torrent, 'r').read())
            except IOError as err:
                pass
        if len(torrent_data) != len(args[1:]):
            raise ConfigError("! Failed to locate any files")
    except (ConfigError, Exception) as err:
        print(err)
        return 1
    else:
        if torrent_data:
            client = init_client()
            print("> Connected to {}".format(client))
            for raw_torrent in torrent_data:
                torrent_struct = Torrent.from_str(raw_torrent)
                print("-> {} @ {}".format(
                    torrent_struct['info']['name'].decode('utf8'),
                    torrent_struct.size(human=True)))
                if client.add(raw_torrent):
                    print("--> Upload successful")
                    return 0
                else:
                    print("--> Upload failed")
                    return 1
Example #12
0
    def fetch_releases(self, session, scene_only=True):
        """ Generator which yields torrent data to be loaded into backend daemons

        :param session:
        :type session: sqlalchemy.orm.session.Session
        :param scene_only: Only fetch scene releases
        :type scene_only: bool
        :return: Matched Downloaded torrents
        :rtype: TorrentData[]
        """
        found = []
        try:
            releases = self.get_torrents_browse(50)['torrents'].values()
        except (TypeError, KeyError) as err:
            self.log.debug("Failed to fetch releases")
        else:
            if scene_only:
                releases = [rls for rls in releases if rls['Origin'] == "Scene"]
            for entry in releases:
                release_name = entry['ReleaseName']
                release_info = parser.parse_release(release_name, guess_type=constants.MEDIA_TV)
                if not release_info:
                    continue
                section_name = parser.validate_section(release_info)
                if not section_name:
                    continue
                if self.exists(session, release_info.release_key) and not self.is_replacement(release_info):
                    continue
                #dl_url = self.get_torrent_url(entry['TorrentID'])
                torrent_data = net.http_request(entry['DownloadURL'], json=False)
                if not torrent_data:
                    self.log.error("Failed to download torrent data from server: {0}".format(entry['link']))
                    continue
                data = release.TorrentData(str(release_name), torrent_data, section_name)
                torrent = Torrent.from_str(torrent_data)
                if not parser.valid_size(torrent, section_name):
                    continue
                yield data, release_info
Example #13
0
def add_torrents_from_cli(args):
    """ Parse command line args and try to load torrent files found

    :param args:
    :type args:
    :return:
    :rtype:
    """
    try:
        if len(args) <= 1:
            raise ConfigError("! Not enough arguments")

        torrent_data = []
        for torrent in args[1:]:
            try:
                torrent_data.append(open(torrent, 'r').read())
            except IOError as err:
                pass
        if len(torrent_data) != len(args[1:]):
            raise ConfigError("! Failed to locate any files")
    except (ConfigError, Exception) as err:
        print(err)
        return 1
    else:
        if torrent_data:
            client = init_client()
            print("> Connected to {}".format(client))
            for raw_torrent in torrent_data:
                torrent_struct = Torrent.from_str(raw_torrent)
                print("-> {} @ {}".format(torrent_struct['info']['name'].decode('utf8'), torrent_struct.size(human=True)))
                if client.add(raw_torrent):
                    print("--> Upload successful")
                    return 0
                else:
                    print("--> Upload failed")
                    return 1
Example #14
0
class TorrentTests(TrannyTestCase):
    live_test = False

    test_file_1 = get_fixture('linux-iso.torrent')
    test_file_2 = get_fixture('linux-iso-2.torrent')
    test_file_3 = get_fixture('linux-iso-3.torrent')
    torrent = Torrent.from_file(test_file_1)
    torrent2 = Torrent.from_file(test_file_2)
    torrent3 = Torrent.from_file(test_file_3)

    def sleep_live(self, t):
        if self.live_test:
            time.sleep(t)

    def _wipe_all(self):
        try:
            for torrent in self.client.torrent_list():
                self.client.torrent_remove(torrent.info_hash, remove_data=True)
        except:
            pass

    def make_client(self):
        raise NotImplementedError("")

    def setUp(self):
        self.client = self.make_client()
        self.client_name = self.client.config_key.split("_")[1]
        self._wipe_all()

    def tearDown(self):
        self._wipe_all()
        time.sleep(1)

    def test_client_version(self):
        with client_env(self.track("torrent_version"), self.live_test):
            ver = self.client.client_version()
        num, rev = ver.split(" ")
        self.assertTrue(float(int(rev[1:][:-1])) > 2)
        self.assertTrue(rev > 10000)

    def test_torrent_add(self):
        with client_env(self.track("torrent_add_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_add_b"), self.live_test):
            torrent = self.client.torrent_status(self.torrent.info_hash)
            self.assertEqual(torrent.info_hash, self.torrent.info_hash)

    def test_current_speeds(self):
        with client_env(self.track("torrent_current_speeds"), self.live_test):
            speed = self.client.current_speeds()
        self.assertTrue(len(speed) == 2)
        self.assertGreaterEqual(speed[0], 0)
        self.assertGreaterEqual(speed[1], 0)

    def test_torrent_peers(self):
        with client_env(self.track("torrent_peers_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        self.sleep_live(10)
        with client_env(self.track("torrent_peers_b"), self.live_test):
            peers = self.client.torrent_peers(self.torrent.info_hash)
        self.assertTrue(len(peers) > 0)
        self.assertSetEqual({'client', 'down_speed', 'ip', 'progress', 'up_speed', 'country'}, set(peers[0].keys()))

    def test_torrent_files(self):
        with client_env(self.track("torrent_files_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_files_b"), self.live_test):
            files = self.client.torrent_files(self.torrent.info_hash)
        self.assertTrue(files)

    def test_torrent_speed(self):
        with client_env(self.track("torrent_speed_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_speed_b"), self.live_test):
            speed = self.client.torrent_speed(self.torrent.info_hash)
        self.assertTrue(speed)

    def test_torrent_status(self):
        with client_env(self.track("torrent_status_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        self.sleep_live(5)
        with client_env(self.track("torrent_status_b"), self.live_test):
            status = self.client.torrent_status(self.torrent.info_hash)
        self.assertTrue(status)

    def test_torrent_queue_up(self):
        with client_env(self.track("torrent_queue_up_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_up_b"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
        self.assertEqual(torrent_a.queue_position, 0)
        with client_env(self.track("torrent_queue_up_c"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_2, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_up_d"), self.live_test):
            torrent_b = self.client.torrent_status(self.torrent2.info_hash)
        self.assertEqual(torrent_b.queue_position, 1)

        with client_env(self.track("torrent_queue_up_e"), self.live_test):
            self.client.torrent_queue_up(self.torrent2.info_hash)
        with client_env(self.track("torrent_queue_up_f"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
        self.assertEqual(torrent_a.queue_position, 1)
        with client_env(self.track("torrent_queue_up_g"), self.live_test):
            torrent_b = self.client.torrent_status(self.torrent2.info_hash)
        self.assertEqual(torrent_b.queue_position, 0)

    def test_torrent_queue_down(self):
        with client_env(self.track("torrent_queue_down_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_down_b"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
        self.assertEqual(torrent_a.queue_position, 0)
        with client_env(self.track("torrent_queue_down_c"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_2, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_down_d"), self.live_test):
            torrent_b = self.client.torrent_status(self.torrent2.info_hash)
        self.assertEqual(torrent_b.queue_position, 1)
        with client_env(self.track("torrent_queue_down_e"), self.live_test):
            self.client.torrent_queue_down(self.torrent.info_hash)
        with client_env(self.track("torrent_queue_down_f"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
        self.assertEqual(torrent_a.queue_position, 1)

        with client_env(self.track("torrent_queue_down_g"), self.live_test):
            torrent_b = self.client.torrent_status(self.torrent2.info_hash)
        self.assertEqual(torrent_b.queue_position, 0)

    def test_torrent_queue_top(self):
        with client_env(self.track("torrent_queue_top_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_top_b"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
        self.assertEqual(torrent_a.queue_position, 0)
        with client_env(self.track("torrent_queue_top_c"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_2, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_top_d"), self.live_test):
            torrent_b = self.client.torrent_status(self.torrent2.info_hash)
        self.assertEqual(torrent_b.queue_position, 1)

        with client_env(self.track("torrent_queue_top_e"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_3, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_top_f"), self.live_test):
            torrent_c = self.client.torrent_status(self.torrent3.info_hash)
        self.assertEqual(torrent_c.queue_position, 2)

        with client_env(self.track("torrent_queue_top_g"), self.live_test):
            self.assertTrue(self.client.torrent_queue_top(self.torrent3.info_hash))

        with client_env(self.track("torrent_queue_top_h"), self.live_test):
            torrent_c = self.client.torrent_status(self.torrent3.info_hash)
            self.assertEqual(torrent_c.queue_position, 0)

        with client_env(self.track("torrent_queue_top_i"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
            self.assertEqual(torrent_a.queue_position, 1)

        with client_env(self.track("torrent_queue_top_j"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent2.info_hash)
            self.assertEqual(torrent_a.queue_position, 2)

    def test_torrent_queue_bottom(self):
        with client_env(self.track("torrent_queue_bottom_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_bottom_b"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
        self.assertEqual(torrent_a.queue_position, 0)
        with client_env(self.track("torrent_queue_bottom_c"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_2, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_bottom_d"), self.live_test):
            torrent_b = self.client.torrent_status(self.torrent2.info_hash)
        self.assertEqual(torrent_b.queue_position, 1)

        with client_env(self.track("torrent_queue_bottom_e"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_3, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_queue_bottom_f"), self.live_test):
            torrent_c = self.client.torrent_status(self.torrent3.info_hash)
        self.assertEqual(torrent_c.queue_position, 2)

        with client_env(self.track("torrent_queue_bottom_g"), self.live_test):
            self.assertTrue(self.client.torrent_queue_bottom(self.torrent.info_hash))

        with client_env(self.track("torrent_queue_bottom_h"), self.live_test):
            torrent_c = self.client.torrent_status(self.torrent3.info_hash)
            self.assertEqual(torrent_c.queue_position, 1)

        with client_env(self.track("torrent_queue_bottom_i"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
            self.assertEqual(torrent_a.queue_position, 2)

        with client_env(self.track("torrent_queue_bottom_j"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent2.info_hash)
            self.assertEqual(torrent_a.queue_position, 0)

    def test_torrent_reannounce(self):
        with client_env(self.track("torrent_reannounce_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_reannounce_b"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
            self.assertEqual(torrent_a.next_announce, 0)
        time.sleep(5)
        with client_env(self.track("torrent_reannounce_c"), self.live_test):
            self.client.torrent_reannounce(self.torrent.info_hash)
        with client_env(self.track("torrent_reannounce_d"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
            self.assertGreater(torrent_a.next_announce, 0)

    def test_disconnect(self):
        self.assertTrue(self.client.disconnect())

    def test_torrent_recheck(self):
        # Not sure best way to check this..
        with client_env(self.track("torrent_recheck_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_recheck_b"), self.live_test):
            self.assertTrue(self.client.torrent_recheck(self.torrent.info_hash))

    @unittest.skip("Not sure how to test yet")
    def test_torrent_pause(self):
        with client_env(self.track("torrent_pause_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        with client_env(self.track("torrent_pause_b"), self.live_test):
            torrent_a = self.client.torrent_status(self.torrent.info_hash)
            self.assertIn(torrent_a.state, [TorrentState.PAUSED, TorrentState.CHECKING, TorrentState.DOWNLOADING])
        with client_env(self.track("torrent_pause_c"), self.live_test):
            self.assertTrue(self.client.torrent_pause(self.torrent.info_hash))

    def test_torrent_start(self):
        with client_env(self.track("torrent_start_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))
        time.sleep(2)
        with client_env(self.track("torrent_start_b"), self.live_test):
            self.assertTrue(self.client.torrent_pause(self.torrent.info_hash))
        time.sleep(2)
        with client_env(self.track("torrent_start_c"), self.live_test):
            status = self.client.torrent_status(self.torrent.info_hash)
            self.assertEqual(status.state, TorrentState.PAUSED)
        time.sleep(2)
        with client_env(self.track("torrent_start_d"), self.live_test):
            self.assertTrue(self.client.torrent_start(self.torrent.info_hash))
        time.sleep(2)
        with client_env(self.track("torrent_start_e"), self.live_test):
            status = self.client.torrent_status(self.torrent.info_hash)
            self.assertIn(status.state, [TorrentState.STARTED, TorrentState.DOWNLOADING])

    def test_torrent_add_duplicate(self):
        with client_env(self.track("torrent_add_duplicate_a"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))

        with client_env(self.track("torrent_add_duplicate_b"), self.live_test):
            self.assertTrue(self.client.torrent_add(open(self.test_file_1, "rb").read(), tempfile.gettempdir()))