Example #1
0
def main():
    """
    Entry function
    """
    parser = argparse.ArgumentParser(description='Process some integers.')
    parser.add_argument(
        '-d', '--dir', type=lambda x: is_valid_directory(parser, x),
        help='the directory to hold the file structure', required=True
    )
    parser.add_argument(
        'hosts', metavar='H', type=lambda x: is_valid_host(parser, x),
        nargs='+', help='the Deluge hosts'
    )
    args = parser.parse_args()

    tracker_map = {}
    clients = []

    for host in args.hosts:
        client = DelugeRPCClient(*host)
        client.connect()

        clients.append(client)

    for entry in listdir_fullpath(args.dir):
        recursive_rm_dir(entry)

    for client in clients:
        torrents = client.call(
            'core.get_torrents_status',
            {},
            ['name', 'save_path', 'tracker_host']
        )

        for _, torrent in torrents.items():
            if torrent[b'tracker_host'] not in tracker_map:
                tracker_map[torrent[b'tracker_host'].decode('utf-8')] = []
            tracker_map[torrent[b'tracker_host'].decode('utf-8')].append(torrent)

        for tracker, torrents in tracker_map.items():
            loc = os.path.join(args.dir, tracker)
            if not os.path.exists(loc):
                os.makedirs(loc)
            for torrent in torrents:
                link_from = os.path.join(loc, torrent[b'name'].decode('utf-8'))
                link_to = os.path.join(
                    torrent[b'save_path'].decode('utf-8'),
                    torrent[b'name'].decode('utf-8')
                )
                if not os.path.exists(link_from):
                    try:
                        os.symlink(link_to, link_from)
                    except OSError as error:
                        if error.errno == errno.EEXIST:
                            os.remove(link_from)
                            os.symlink(link_to, link_from)
                        else:
                            raise error
Example #2
0
 def uploadTorrent(self, filename):
     """
     Upload a torrent to the deluge host based on the config file
     """
     print('Uploading torrent %s' % (filename))
     client = DelugeRPCClient(self.hostDeluge, self.portDeluge, self.usernameDeluge, self.passwordDeluge)
     client.connect()
     f = open(filename, 'rb')
     filedump = base64.encodestring(f.read())
     f.close()
     client.call('core.add_torrent_file', filename, filedump, {}, )
     bytes_available = client.call('core.get_free_space')
     gig_available = bytes_available/(1024.*1024*1024)
     print('There is %.1f GB available on the host \'%s\'.' % (gig_available, self.hostDeluge))
Example #3
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Deluge switch."""
    from deluge_client import DelugeRPCClient

    name = config.get(CONF_NAME)
    host = config.get(CONF_HOST)
    username = config.get(CONF_USERNAME)
    password = config.get(CONF_PASSWORD)
    port = config.get(CONF_PORT)

    deluge_api = DelugeRPCClient(host, port, username, password)
    try:
        deluge_api.connect()
    except ConnectionRefusedError:
        _LOGGER.error("Connection to Deluge Daemon failed")
        raise PlatformNotReady

    add_entities([DelugeSwitch(deluge_api, name)])
Example #4
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Deluge switch."""
    from deluge_client import DelugeRPCClient

    name = config.get(CONF_NAME)
    host = config.get(CONF_HOST)
    username = config.get(CONF_USERNAME)
    password = config.get(CONF_PASSWORD)
    port = config.get(CONF_PORT)

    deluge_api = DelugeRPCClient(host, port, username, password)
    try:
        deluge_api.connect()
    except ConnectionRefusedError:
        _LOGGER.error("Connection to Deluge Daemon failed")
        raise PlatformNotReady

    add_entities([DelugeSwitch(deluge_api, name)])
Example #5
0
    async def send_request(self, request):
        conn = DelugeClient('master.seedhost.eu', 21110,
                            os.environ['DELUGE_USER'],
                            os.environ['DELUGE_PASS'])
        conn.connect()
        torrent_id = conn.call(
            'core.add_torrent_magnet', request.magnet, {
                'download_location':
                f'/home13/fufu/downloads/Watchtower/{request.channel}/{request.name}/'
            })

        with TinyDB('db') as db:
            db.insert({
                'requester_name': request.requester_name,
                'torrent_id': torrent_id.decode(),
                'torrent_name': request.name,
                'time': int(time.time())
            })
Example #6
0
def torrents_status():
    STATUS_KEYS = [
    "state",
    "download_location",
    "tracker_host",
    "tracker_status",
    "next_announce",
    "name",
    "total_size",
    "progress",
    "num_seeds",
    "total_seeds",
    "num_peers",
    "total_peers",
    "eta",
    "download_payload_rate",
    "upload_payload_rate",
    "ratio",
    "distributed_copies",
    "num_pieces",
    "piece_length",
    "total_done",
    "files",
    "file_priorities",
    "file_progress",
    "peers",
    "is_seed",
    "is_finished",
    "active_time",
    "seeding_time"
    ]
    from deluge_client import DelugeRPCClient
    client = DelugeRPCClient('127.0.0.1', 2196, "seftembr", "TuGsFYqlNP")
    client.connect()
    print "--- ACTIVE ---"
    for (hashid, fields) in client.call('core.get_torrents_status', {"state":"Active"}, STATUS_KEYS).iteritems():
        print "%s: %s (%.2f out of %s - active for %s so far)" % (hashid, fields['name'], fields['progress'], sizeof_fmt(fields['total_size']), human_time(seconds=fields['active_time']))
    print "--- PAUSED ---"
    for (hashid, fields) in client.call('core.get_torrents_status', {"state":"Paused"}, STATUS_KEYS).iteritems():
        if fields['progress'] == 100:
            print "%s: %s (%s downloaded in %s)" % (hashid, fields['name'], sizeof_fmt(fields['total_size']), human_time(seconds=fields['active_time']))
        else:
            print "%s: %s (%.2f out of %s - was active for %s - and paused)" % (hashid, fields['name'], fields['progress'], sizeof_fmt(fields['total_size']), human_time(seconds=fields['active_time']))
Example #7
0
def node_task_del(infohash):
    client = DelugeRPCClient('127.0.0.1', 58846, u, p)
    if client.connected is False:
        client.connect()
    ret = client.call('core.get_torrents_status', {'id': [infohash]},
                      [u'name'])
    if len(ret[infohash]) == 0:
        # clean cache
        try:
            download_location = app.config.get(
                'TASK_DOWNLOAD_PATH') + '/' + infohash
            os.removedirs(download_location)
        except:
            pass
        res = True
    else:
        res = client.call('core.remove_torrent', infohash, True)

    return jsonify({'data': res, 'errCode': 0})
Example #8
0
def start(calling_dir=os.getcwd()):
    global client, deluge_password, deluge_server_ip, deluge_server_port, deluge_username, live_config, CONNECT_TO_DELUGE

    ##TODO: UPDATE VERSION ON BUILD
    print("Welcome to TraktPuller v0.7")
    print(
        "Source code available at https://github.com/TheSelectiveOppidan/trakt-downloader"
    )

    if not configuration.check(calling_dir):
        print(
            "Please fill in the configuration file I just created then rerun me."
        )
        exit()

    live_config = configuration.get_config(calling_dir)

    option = ""

    while option != 'n':
        option = input("Do you want to add a new account? (y/n)")

        if option == 'y':
            if not do_authorize_loop():
                option = ''

    deluge_server_ip = live_config['deluge_ip']
    deluge_server_port = int(live_config['deluge_port'])
    deluge_username = live_config['deluge_username']
    deluge_password = live_config['deluge_password']

    client = DelugeRPCClient(deluge_server_ip, deluge_server_port,
                             deluge_username, deluge_password)

    if CONNECT_TO_DELUGE:
        try:
            client.connect()
        except Exception as e:
            print(e)

    print("is Connected to Deluge: " + str(client.connected))

    main_loop()
Example #9
0
def deluge(torrent, CLIENT_URL, TOR_CLIENT_USER, TOR_CLIENT_PW, logger):
    TOR_CLIENT = "Deluge"
    print(f"Sending {torrent.description.decode('ascii')} to {TOR_CLIENT}")
    url = fetch_torrent_url(torrent)
    try:
        logger.debug("Connecting to torrent client...")
        # Connection
        logger.debug(f"{TOR_CLIENT} connection info: {CLIENT_URL.split(':')[0]}, {int(CLIENT_URL.split(':')[1])}, {TOR_CLIENT_USER}")
        client = DelugeRPCClient(CLIENT_URL.split(':')[0], int(CLIENT_URL.split(':')[1]), TOR_CLIENT_USER, TOR_CLIENT_PW)
        client.connect()
        logger.debug(f"Connected to {TOR_CLIENT}") 
                                       
        # Add torrent
        logger.debug(f"Adding {torrent.description.decode('ascii')} with url: {url}")
        client.call("download_torrent_from_url", url)
        print("Torrent sent!")
    except Exception as e:
        print(f"Unable to send to {TOR_CLIENT}. Check the logs for more information.")
        logger.error(f"Error sending to {TOR_CLIENT}. {str(e)}")
        exit()
Example #10
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Deluge sensors."""

    name = config[CONF_NAME]
    host = config[CONF_HOST]
    username = config[CONF_USERNAME]
    password = config[CONF_PASSWORD]
    port = config[CONF_PORT]

    deluge_api = DelugeRPCClient(host, port, username, password)
    try:
        deluge_api.connect()
    except ConnectionRefusedError as err:
        _LOGGER.error("Connection to Deluge Daemon failed")
        raise PlatformNotReady from err
    dev = []
    for variable in config[CONF_MONITORED_VARIABLES]:
        dev.append(DelugeSensor(variable, deluge_api, name))

    add_entities(dev)
Example #11
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Deluge sensors."""
    from deluge_client import DelugeRPCClient

    name = config.get(CONF_NAME)
    host = config.get(CONF_HOST)
    username = config.get(CONF_USERNAME)
    password = config.get(CONF_PASSWORD)
    port = config.get(CONF_PORT)

    deluge_api = DelugeRPCClient(host, port, username, password)
    try:
        deluge_api.connect()
    except ConnectionRefusedError:
        _LOGGER.error("Connection to Deluge Daemon failed")
        raise PlatformNotReady
    dev = []
    for variable in config[CONF_MONITORED_VARIABLES]:
        dev.append(DelugeSensor(variable, deluge_api, name))

    add_devices(dev)
Example #12
0
def setup_platform(hass, config, add_devices, discovery_info=None):
    """Set up the Deluge sensors."""
    from deluge_client import DelugeRPCClient

    name = config.get(CONF_NAME)
    host = config.get(CONF_HOST)
    username = config.get(CONF_USERNAME)
    password = config.get(CONF_PASSWORD)
    port = config.get(CONF_PORT)

    deluge_api = DelugeRPCClient(host, port, username, password)
    try:
        deluge_api.connect()
    except ConnectionRefusedError:
        _LOGGER.error("Connection to Deluge Daemon failed")
        return

    dev = []
    for variable in config[CONF_MONITORED_VARIABLES]:
        dev.append(DelugeSensor(variable, deluge_api, name))

    add_devices(dev)
Example #13
0
def setup_platform(
    hass: HomeAssistant,
    config: ConfigType,
    add_entities: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType | None = None,
) -> None:
    """Set up the Deluge switch."""

    name = config[CONF_NAME]
    host = config[CONF_HOST]
    username = config[CONF_USERNAME]
    password = config[CONF_PASSWORD]
    port = config[CONF_PORT]

    deluge_api = DelugeRPCClient(host, port, username, password)
    try:
        deluge_api.connect()
    except ConnectionRefusedError as err:
        _LOGGER.error("Connection to Deluge Daemon failed")
        raise PlatformNotReady from err

    add_entities([DelugeSwitch(deluge_api, name)])
def create_deluge_client(url, port, username, password):
    """
    Creates a minimal Deluge torrent client to the Deluge seedbox server.

    :param str url: URL of the Deluge server.
    :param int port: port used to access the Deluge server.
    :param str username: server account username.
    :param str password: server account password.

    :returns: a lightweight `Deluge RPC client`_.

    .. seealso:: 
      * :py:meth:`get_deluge_client <plexcore.plexcore_deluge.get_deluge_client>`
      * :py:meth:`get_deluge_credentials <plexcore.plexcore_deluge.get_deluge_credentials>`
      * :py:meth:`push_deluge_credentials <plexcore.plexcore_deluge.push_deluge_credentials>`

    .. _`Deluge RPC client`: https://github.com/JohnDoee/deluge-client
    """
    from deluge_client import DelugeRPCClient
    client = DelugeRPCClient(url, port, username, password)
    client.connect()
    assert (client.connected)  # make sure we can connect
    return client
Example #15
0
def main():
    parser = argparse.ArgumentParser(description="Change torrent trackers")
    parser.add_argument("-s", "--server", type=DelugeUri, required=True,
                        help="Deluge host or IP addresses to connect to in the form of user:pass@hostname:port")

    parser.add_argument("-c", "--src-substr", help="Tracker to replace", required=True)
    parser.add_argument("-t", "--tracker", help="URL of new tracker", required=True)
    parser.add_argument("-n", "--dry-run", action="store_true", help="Only print changed torrents")

    args = parser.parse_args()

    uri = urlparse('deluge://{}'.format(args.server))
    client = DelugeRPCClient(uri.hostname, uri.port if uri.port else 58846, uri.username, uri.password)
    client.connect()

    torrents = decodedict(client.call('core.get_torrents_status', {},
                                      ['name', 'trackers']))
    for torrent_id, torrent in torrents.items():
        tracker = torrent['trackers'][0]
        if args.src_substr in tracker["url"]:
            print("Updating '{}' on '{}' ({})".format(tracker["url"], torrent['name'], torrent_id))
            if not args.dry_run:
                client.call('core.set_torrent_trackers', torrent_id, [{"url": args.tracker, "tier": 0}])
Example #16
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Deluge sensors."""

    name = config[CONF_NAME]
    host = config[CONF_HOST]
    username = config[CONF_USERNAME]
    password = config[CONF_PASSWORD]
    port = config[CONF_PORT]

    deluge_api = DelugeRPCClient(host, port, username, password)
    try:
        deluge_api.connect()
    except ConnectionRefusedError as err:
        _LOGGER.error("Connection to Deluge Daemon failed")
        raise PlatformNotReady from err
    monitored_variables = config[CONF_MONITORED_VARIABLES]
    entities = [
        DelugeSensor(deluge_api, name, description)
        for description in SENSOR_TYPES
        if description.key in monitored_variables
    ]

    add_entities(entities)
Example #17
0
def deluge_connect() -> DelugeRPCClient:
    host = os.getenv('DELUGE_HOST')
    if not host:
        raise Exception('DELUGE_HOST not set')
    port = os.getenv('DELUGE_PORT')
    if port:
        try:
            port = int(port)
        except Exception as e:
            raise Exception('DELUGE_PORT is not int ' + str(e))
    else:
        port = 58846
    
    username = os.getenv('DELUGE_USERNAME')
    if not username:
        raise Exception('DELUGE_USERNAME not set')
    password = os.getenv('DELUGE_PASSWORD')
    if not password:
        raise Exception('DELUGE_PASSWORD not set')

    client = DelugeRPCClient(host, port, username, password)
    client.connect()

    return client
Example #18
0
class DelugeHelper:
    def __init__(self):
        self.login()

    def login(self):
        self.client = DelugeRPCClient(host, port, username, password)
        self.client.connect()

    def get_torrents(self):
        # list of keys? https://forum.deluge-torrent.org/viewtopic.php?t=54793
        res_torrents = self.client.call('core.get_torrents_status', {}, [
            'name', 'progress', 'ratio', 'tracker', 'seeding_time',
            'total_size'
        ])

        torrents = [
            TorrentStat(_id, torrent[b'name'], torrent[b'ratio'],
                        torrent[b'seeding_time'], torrent[b'tracker'])
            for _id, torrent in res_torrents.items()
        ]
        return torrents

    def delete_torrent(self, torrent_id):
        self.client.core.remove_torrent(torrent_id, remove_data=True)
Example #19
0
    def collect(self):
        deluge_host = os.environ.get('DELUGE_HOST', '127.0.0.1')
        client = DelugeRPCClient(deluge_host, self.rpc_port, self.rpc_user,
                                 self.rpc_password)
        client.connect()

        libtorrent_metrics = get_libtorrent_metrics_meta()
        libtorrent_metric_values = client.call('core.get_session_status', [])

        for metric, metric_type in libtorrent_metrics.items():
            encoded_name = metric.encode('ascii')
            if encoded_name in libtorrent_metric_values:
                yield metric_type('deluge_libtorrent_{}'.format(
                    metric.replace('.', '_')),
                                  'libtorrent metric {}'.format(metric),
                                  value=libtorrent_metric_values[encoded_name])

        yield new_metric_with_labels_and_value(
            GaugeMetricFamily,
            'deluge_info',
            'Deluge information',
            labels={
                'version':
                client.call('daemon.info').decode('utf-8'),
                'libtorrent_version':
                client.call('core.get_libtorrent_version').decode('utf-8'),
            },
            value=1)

        for key, value in client.call('core.get_config').items():
            if isinstance(value, (int, float, bool)):
                yield GaugeMetricFamily(
                    'deluge_config_{}'.format(key.decode('utf-8')),
                    'Value of the deluge config setting {}'.format(
                        key.decode('utf-8')),
                    value=value)

        torrents_by_state = {
            'downloading': 0,
            'seeding': 0,
            'paused': 0,
            'checking': 0,
            'queued': 0,
            'error': 0,
            'active': 0,

            # not the prometheus way, but the states above (as defined by deluge) are already overlapping, so sum() over them is already meaningless
            'total': 0,
        }
        torrents_by_label = defaultdict(int)
        for torrent in client.core.get_torrents_status({}, [
                b'label', b'state', b'download_payload_rate',
                b'upload_payload_rate'
        ]).values():
            if b'label' in torrent:
                torrents_by_label[torrent[b'label'].decode('utf-8')] += 1
            torrents_by_state[torrent[b'state'].decode('utf-8').lower()] += 1
            torrents_by_state['total'] += 1
            if torrent[b'download_payload_rate'] > 0 or torrent[
                    b'upload_payload_rate'] > 0:
                torrents_by_state['active'] += 1

        if len(torrents_by_label) > 0:
            torrents_by_label_metric = GaugeMetricFamily(
                'deluge_torrents_by_label',
                'The number of torrents for each label assigned to a torrent using the deluge label plugin',
                labels=['label'])
            for label, count in torrents_by_label.items():
                torrents_by_label_metric.add_metric([label], count)
            yield torrents_by_label_metric

        torrents_metric = GaugeMetricFamily(
            'deluge_torrents',
            'The number of torrents in a specific state (note: some states overlap)',
            labels=['state'])
        for state, torrent_count in torrents_by_state.items():
            torrents_metric.add_metric([state], torrent_count)
        yield torrents_metric

        client.disconnect()
Example #20
0
class DelugeRPC(object):
    """Deluge RPC client class."""

    def __init__(self, host='localhost', port=58846, username=None, password=None):
        """Deluge RPC Constructor.

        :param host:
        :type host: str
        :param port:
        :type port: int
        :param username:
        :type username: str
        :param password:
        :type password: str
        """
        super(DelugeRPC, self).__init__()
        self.host = host
        self.port = int(port)
        self.username = username
        self.password = password

    def connect(self):
        """Connect to the host using synchronousdeluge API."""
        try:
            self.client = DelugeRPCClient(self.host, self.port, self.username, self.password, decode_utf8=True)
            self.client.connect()
        except Exception as error:
            log.warning('Error while trying to connect to deluge daemon. Error: {error}', {'error': error})
            raise

    def disconnect(self):
        """Disconnect RPC client."""
        self.client.disconnect()

    def test(self):
        """Test connection.

        :return:
        :rtype: bool
        """
        try:
            self.connect()
        except Exception:
            return False
        else:
            return True

    def move_storage(self, torrent_id, location):
        """Move torrent to new location and return torrent id/hash.

        :param torrent_id:
        :type torrent_id: str
        :param location:
        :type location: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            self.client.core.move_storage([torrent_id], location)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def add_torrent_magnet(self, torrent, options, info_hash):
        """Add Torrent magnet and return torrent id/hash.

        :param torrent:
        :type torrent: str
        :param options:
        :type options: dict
        :param info_hash:
        :type info_hash: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            torrent_id = self.client.core.add_torrent_magnet(torrent, options)
        except Exception:
            return False
        else:
            return torrent_id
        finally:
            if self.client:
                self.disconnect()

    def add_torrent_file(self, filename, torrent, options, info_hash):
        """Add Torrent file and return torrent id/hash.

        :param filename:
        :type filename: str
        :param torrent:
        :type torrent: str
        :param options:
        :type options: dict
        :param info_hash:
        :type info_hash: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            torrent_id = self.client.core.add_torrent_file(filename, b64encode(torrent), options)
        except Exception:
            return False
        else:
            return torrent_id
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_label(self, torrent_id, label):
        """Set Torrent label.

        :param torrent_id:
        :type torrent_id: str
        :param label:
        :type label: str
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.label.set_torrent(torrent_id, label)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_path(self, torrent_id, path):
        """Set Torrent path.

        :param torrent_id:
        :type torrent_id: str
        :param path:
        :type path: str
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.core.set_torrent_move_completed_path(torrent_id, path)
            self.client.core.set_torrent_move_completed(torrent_id, 1)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_priority(self, torrent_id, priority):
        """Set Torrent priority.

        :param torrent_id:
        :type torrent_id: str
        :param priority:
        :type priority: bool
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            if priority:
                self.client.core.queue_top([torrent_id])
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_ratio(self, torrent_id, ratio):
        """Set Torrent ratio.

        :param torrent_id:
        :type torrent_id: str
        :param ratio:
        :type ratio: float
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.core.set_torrent_stop_at_ratio(torrent_id, True)
            self.client.core.set_torrent_stop_ratio(torrent_id, ratio)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def remove_torrent_data(self, torrent_id):
        """Remove torrent from client and disk using given info_hash.

        :param torrent_id:
        :type torrent_id: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            self.client.core.remove_torrent(torrent_id, True)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def remove_torrent(self, torrent_id):
        """Remove torrent from client using given info_hash.

        :param torrent_id:
        :type torrent_id: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            self.client.core.remove_torrent(torrent_id, False)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def pause_torrent(self, torrent_ids):
        """Pause torrent.

        :param torrent_ids:
        :type torrent_ids: list of str
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.core.pause_torrent(torrent_ids)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def _torrent_properties(self, info_hash):
        """Get torrent properties."""
        try:
            self.connect()
            log.debug('Checking DelugeD torrent {hash} status.', {'hash': info_hash})
            torrent_data = self.client.core.get_torrent_status(
                info_hash, ('name', 'hash', 'progress', 'state', 'ratio', 'stop_ratio',
                            'is_seed', 'is_finished', 'paused', 'files', 'download_location'))
        except RequestException as error:
            raise DownloadClientConnectionException(f'Error while fetching torrent info_hash {info_hash}. Error: {error}')
        except Exception:
            log.warning('Error while fetching torrent {hash} status.', {'hash': info_hash})
            return
        else:
            return torrent_data
        finally:
            if self.client:
                self.disconnect()
Example #21
0
class Deluge(IntervalModule):
    """
    Deluge torrent module
    Requires `deluge-client`

    .. rubric:: Formatters:

    * `{num_torrents}`       - number of torrents in deluge
    * `{free_space_bytes}`   - bytes free in path
    * `{used_space_bytes}`   - bytes used in path
    * `{upload_rate}` - bytes sent per second
    * `{download_rate}` - bytes received per second
    * `{total_uploaded}`     - bytes sent total
    * `{total_downloaded}`     - bytes received total

    """

    settings = (
        'format',
        ('rounding', 'number of decimal places to round numbers too'),
        ('host', 'address of deluge server (default: 127.0.0.1)'),
        ('port', 'port of deluge server (default: 58846)'),
        ('username', 'username to authenticate with deluge'),
        ('password', 'password to authenticate to deluge'),
        ('path',
         'override "download path" server-side when checking space used/free'),
    )
    required = ('username', 'password')

    host = '127.0.0.1'
    port = 58846
    path = None
    libtorrent_stats = False
    rounding = 2

    format = '⛆{num_torrents} ✇{free_space_bytes}'

    id = int(time.time())  # something random

    def init(self):
        self.client = DelugeRPCClient(self.host, self.port, self.username,
                                      self.password)
        self.data = {}

    def run(self):
        if not self.client.connected:
            self.client.connect()

        self.data = self.get_session_statistics()

        torrents = self.get_torrents_status()
        if torrents:
            self.data['num_torrents'] = len(torrents)

        if 'free_space_bytes' in self.format:
            self.data['free_space_bytes'] = self.get_free_space(self.path)
        if 'used_space_bytes' in self.format:
            self.data['used_space_bytes'] = self.get_path_size(self.path)

        self.parse_values(self.data)

        self.output = {'full_text': self.format.format(**self.data)}

    def parse_values(self, values):
        for k, v in values.items():
            if v:
                if k in [
                        'total_upload', 'total_download', 'download_rate',
                        'upload_rate'
                ] or k.endswith('_bytes'):
                    values[k] = '{value:.{round}f}{unit}'.format(
                        round=self.rounding, **bytes_info_dict(v))

    def get_path_size(self, path=None):
        """
        get used space of path in bytes (default: download location)
        """
        if path is None:
            path = []
        return self.client.call('core.get_path_size', path)

    def get_free_space(self, path=None):
        """
        get free space of path in bytes (default: download location)
        """
        if path is None:
            path = []
        return self.client.call('core.get_free_space', path)

    def get_torrents_status(self, torrent_id=None, keys=None):
        if torrent_id is None:
            torrent_id = []
        if keys is None:
            keys = []
        return self.client.call('core.get_torrents_status', torrent_id, keys)

    def get_session_statistics(self):
        keys = [
            'upload_rate', 'download_rate', 'total_upload', 'total_download'
        ]

        out = {
        }  # some of the values from deluge-client are bytes, the others are ints - we need to decode them
        for k, v in self.client.call('core.get_session_status', keys).items():
            k = k.decode('utf-8')  # keys aswell
            if type(v) == bytes:
                out[k] = v.decode('utf-8')
            else:
                out[k] = v

        return out
Example #22
0
class Client(GenericClient, DelugeBase):
    def __init__(self, host=None, username=None, password=None):
        super().__init__('DelugeD', host, username, password)
        self.client = None

    def setup(self):
        parsed_url = urlparse(self.host)
        if self.client and all([
                self.client.host == parsed_url.hostname, self.client.port
                == parsed_url.port, self.client.username == self.username,
                self.client.password == self.password
        ]):
            return

        self.client = DelugeRPCClient(parsed_url.hostname, parsed_url.port
                                      or 58846, self.username, self.password)

    def _get_auth(self):
        self.setup()
        if not self.client.connected:
            for attempt in range(0, 5):
                try:
                    self.client.connect()
                    break
                except FailedToReconnectException:
                    time.sleep(5)

        self.auth = self.client.connected
        return self.auth

    def _add_torrent_uri(self, result):
        remote_torrent = self.client.core.add_torrent_magnet(
            result.url, self.make_options(result))
        if not remote_torrent:
            return None

        result.hash = remote_torrent

        return remote_torrent

    def _add_torrent_file(self, result):
        if not result.content:
            result.content = {}
            return None

        remote_torrent = self.client.core.add_torrent_file(
            result.name + '.torrent',
            b64encode(result.content).decode('ascii'),
            self.make_options(result))
        if not remote_torrent:
            return None

        result.hash = remote_torrent

        return remote_torrent

    def _set_torrent_label(self, result):
        # No option for this built into the rpc, because it is a plugin
        label = settings.TORRENT_LABEL.lower()
        if result.show.is_anime:
            label = settings.TORRENT_LABEL_ANIME.lower()
        if ' ' in label:
            logger.exception(
                f'{self.name}: Invalid label. Label must not contain a space')
            return False

        if label:
            try:

                if 'label' not in [
                        x.decode().lower()
                        for x in self.client.core.get_available_plugins()
                ]:
                    logger.debug(f'{self.name}: label plugin not detected')
                    return False

                self.client.core.enable_plugin('Label')
                self.client.core.enable_plugin('label')

                labels = [x.decode() for x in self.client.label.get_labels()]
                if label not in labels:
                    logger.debug(
                        f'{self.name}: {label} label does not exist in Deluge we must add it'
                    )
                    self.client.label.add(label)
                    logger.debug(
                        f'{self.name}: [{label}] label added to deluge')

                self.client.label.set_torrent(result.hash, label)
            except Exception as error:
                logger.info(f'{self.name}: Could not add label to torrent')
                logger.debug(error)
                # logger.debug(self.client.daemon.get_method_list())
                return False

        logger.debug(f'{self.name}: [{label}] label added to torrent')
        return True

    def testAuthentication(self):
        if self._get_auth() and self.client.daemon.info():
            return True, 'Success: Connected and Authenticated'
        else:
            return False, 'Error: Unable to Authenticate!  Please check your config!'
Example #23
0
class DelugeClientKORPI():
    """
    Class for controlling deluge client.
    """

    def __init__(self, username, password, host="127.0.0.1", port=58846):
        self._username = username
        self._password = password
        self._host = host
        self._port = port

        self.__client = DelugeRPCClient(host, int(port), username, password)

    def connect(self):
        self.__client.connect()

    def list(self):
        """Returns tuple with torrent hashes"""
        return self.__client.call("core.get_session_state")

    def status(self, thash=None):
        if thash:
            return self.__client.call('core.get_torrents_status', {"hash": thash}, [])
        else:
            return self.__client.call('core.get_torrents_status', {}, [])

    def completed(self, thash):
        """Returns % of downloaded from torrent."""
        status = self.__client.call('core.get_torrents_status', {"hash": thash}, [])

        thash = thash.encode("utf-8")
        if status[thash][b"total_wanted"] == 0:
            return 0
        else:
            return status[thash][b"total_done"] / status[thash][b"total_wanted"] * 100

    def pause(self, thash=None):
        """
        If hash not provided, pause/resume all torrents.
        Returns False if torrent(s) was paused, True otherwise.
        """
        if thash:
            status = self.status(thash)[thash.encode("utf-8")][b"paused"]
            if status:
                self.__client.call('core.resume_torrent', [thash])
            else:
                self.__client.call('core.pause_torrent', [thash])

            return status
        else:
            if self.all_paused():
                self.__client.call("core.resume_torrent", self.list())
            else:
                self.__client.call("core.pause_torrent", self.list())

            return self.all_paused()

    def add(self, magnet, directory, max_speed):
        return self.__client.call('core.add_torrent_magnet', magnet, 
            {"download_location": directory, "max_download_speed": max_speed})

    def remove(self, thash, with_files):
        """Set with_files True to remove with files"""
        if with_files == "True": with_files = True
        elif with_files == "False": with_files = False

        return self.__client.call("core.remove_torrent", thash, with_files)

    def free_space(self, directory):
        """Get free space in megabytes."""
        return self.__client.call("core.get_free_space", directory) * TO_GB

    def download_speed(self, dmax=-1):
        for thash in self.list():
            self.__client.call("core.set_torrent_max_download_speed", 
                                thash, int(dmax))

    def all_paused(self):
        return all(paused[b"paused"]
                   for _, paused in self.status().items())
Example #24
0
class TorrentClient(object):
    def __init__(self):
        self.conn = None

    def connect(self, host, username, password, test=False):
        if self.conn is not None:
            return self.connect

        if not host:
            return {'status': False, 'error': 'No host specified'}

        if not username:
            return {'status': False, 'error': 'No username specified'}

        if not password:
            return {'status': False, 'error': 'No password specified'}

        # Get port from the config
        host, portnr = host.split(':')

        # logger.info('Connecting to ' + host + ':' + portnr + ' Username: '******' Password: '******'Could not create DelugeRPCClient Object %s' % e)
            return {'status': False, 'error': e}
        else:
            try:
                self.client.connect()
            except Exception as e:
                logger.error('Could not connect to Deluge: %s' % host)
                return {'status': False, 'error': e}
            else:
                if test is True:
                    daemon_version = self.client.call('daemon.info')
                    libtorrent_version = self.client.call(
                        'core.get_libtorrent_version')
                    return {
                        'status': True,
                        'daemon_version': daemon_version,
                        'libtorrent_version': libtorrent_version
                    }
                else:
                    return self.client

    def find_torrent(self, hash):
        logger.debug('Finding Torrent hash: ' + hash)
        torrent_info = self.get_torrent(hash)
        if torrent_info:
            return True
        else:
            return False

    def get_torrent(self, hash):
        logger.debug('Getting Torrent info from hash: ' + hash)
        try:
            torrent_info = self.client.call('core.get_torrent_status', hash,
                                            '')
        except Exception as e:
            logger.error('Could not get torrent info for ' + hash)
            return False
        else:
            if torrent_info is None:
                torrent_info = False
            return torrent_info

    def start_torrent(self, hash):
        try:
            self.find_torrent(hash)
        except Exception as e:
            return False
        else:
            try:
                self.client.call('core.resume_torrent', hash)
            except Exception as e:
                logger.error('Torrent failed to start ' + e)
            else:
                logger.info('Torrent ' + hash + ' was started')
                return True

    def stop_torrent(self, hash):
        try:
            self.client.find_torrent(hash)
        except Exception as e:
            logger.error('Torrent Not Found')
            return False
        else:
            try:
                self.client.call('core.pause_torrent', hash)
            except Exception as e:
                logger.error('Torrent failed to be stopped: ' + e)
                return False
            else:
                logger.info('Torrent ' + hash + ' was stopped')
                return True

    def load_torrent(self, filepath):

        options = {}

        if mylar.CONFIG.DELUGE_DOWNLOAD_DIRECTORY:
            options[
                'download_location'] = mylar.CONFIG.DELUGE_DOWNLOAD_DIRECTORY

        if mylar.CONFIG.DELUGE_DONE_DIRECTORY:
            options['move_completed'] = 1
            options['move_completed_path'] = mylar.CONFIG.DELUGE_DONE_DIRECTORY

        if mylar.CONFIG.DELUGE_PAUSE:
            options['add_paused'] = int(mylar.CONFIG.DELUGE_PAUSE)

        logger.info('filepath to torrent file set to : ' + filepath)
        torrent_id = False

        if self.client.connected is True:
            logger.info('Checking if Torrent Exists!')

            if not filepath.startswith('magnet'):
                torrentcontent = open(filepath, 'rb').read()
                hash = str.lower(self.get_the_hash(
                    filepath))  # Deluge expects a lower case hash

                logger.debug('Torrent Hash (load_torrent): "' + hash + '"')
                logger.debug('FileName (load_torrent): ' +
                             str(os.path.basename(filepath)))

                #Check if torrent already added
                if self.find_torrent(str.lower(hash)):
                    logger.info('load_torrent: Torrent already exists!')
                    #should set something here to denote that it's already loaded, and then the failed download checker not run so it doesn't download
                    #multiple copies of the same issues that's already downloaded
                else:
                    logger.info('Torrent not added yet, trying to add it now!')
                    try:
                        torrent_id = self.client.call(
                            'core.add_torrent_file',
                            str(os.path.basename(filepath)),
                            base64.encodestring(torrentcontent), options)
                    except Exception as e:
                        logger.debug('Torrent not added')
                        return False
            else:
                try:
                    torrent_id = self.client.call('core.add_torrent_magnet',
                                                  str(filepath), options)
                except Exception as e:
                    logger.debug('Torrent not added')
                    return False

            # If label enabled put label on torrent in Deluge
            if torrent_id and mylar.CONFIG.DELUGE_LABEL:
                logger.info('Setting label to ' + mylar.CONFIG.DELUGE_LABEL)
                try:
                    self.client.call('label.set_torrent', torrent_id,
                                     mylar.CONFIG.DELUGE_LABEL)
                except:
                    #if label isn't set, let's try and create one.
                    try:
                        self.client.call('label.add',
                                         mylar.CONFIG.DELUGE_LABEL)
                        self.client.call('label.set_torrent', torrent_id,
                                         mylar.CONFIG.DELUGE_LABEL)
                    except:
                        logger.warn(
                            'Unable to set label - Either try to create it manually within Deluge, and/or ensure there are no spaces, capitalization or special characters in label'
                        )
                    else:
                        logger.info('Succesfully set label to ' +
                                    mylar.CONFIG.DELUGE_LABEL)

        try:
            torrent_info = self.get_torrent(torrent_id)
            logger.info('Double checking that the torrent was added.')
        except Exception as e:
            logger.warn('Torrent was not added! Please check logs')
            return False
        else:
            logger.info('Torrent successfully added!')
            return {
                'hash': torrent_info['hash'],
                'label': mylar.CONFIG.DELUGE_LABEL,
                'folder': torrent_info['save_path'],
                'move path': torrent_info['move_completed_path'],
                'total_filesize': torrent_info['total_size'],
                'name': torrent_info['name'],
                'files': torrent_info['files'],
                'time_started': torrent_info['active_time'],
                'pause': torrent_info['paused'],
                'completed': torrent_info['is_finished']
            }

    def delete_torrent(self, hash, removeData=False):
        try:
            self.client.find_torrent(hash)
        except Exception as e:
            logger.error('Torrent ' + hash + ' does not exist')
            return False
        else:
            try:
                self.client.call('core.remote_torrent', hash, removeData)
            except Exception as e:
                logger.error('Unable to delete torrent ' + hash)
                return False
            else:
                logger.info('Torrent deleted ' + hash)
                return True

    def get_the_hash(self, filepath):
        import hashlib, StringIO
        import bencode

        # Open torrent file
        torrent_file = open(filepath, "rb")
        metainfo = bencode.decode(torrent_file.read())
        info = metainfo['info']
        thehash = hashlib.sha1(bencode.encode(info)).hexdigest().upper()
        logger.debug('Hash: ' + thehash)
        return thehash
Example #25
0
class Deluge:
    def _mkdtemp(self):
        cache_path = cherrypy.config['opmuse'].get('cache.path')
        dir = os.path.join(cache_path, 'deluge')

        if not os.path.exists(dir):
            os.mkdir(dir)

        return tempfile.mkdtemp(dir=dir)

    def connect(self, timeout=20):
        config = cherrypy.tree.apps[''].config['opmuse']

        if 'deluge.host' not in config:
            log('Deluge not configured, skipping')
            return False

        host = config['deluge.host']
        port = config['deluge.port']
        user = config['deluge.user']
        password = config['deluge.password']

        DelugeRPCClient.timeout = timeout
        self.client = DelugeRPCClient(host, port, user, password)

        try:
            self.client.connect()
        except OSError as e:
            if e.errno == 113: # "No route to host"
                log('No route to host: %s' % host)
                return False
            else:
                raise e

        return self.client.connected

    def update_torrents(self):
        torrents = self.client.call('core.get_torrents_status', {},
                                    ['name', 'files', 'save_path', 'time_added',
                                     'total_size', 'paused', 'is_finished', 'progress'])

        all_torrents = set()

        for torrent_id, in get_database().query(Torrent.torrent_id).all():
            all_torrents.add(torrent_id)

        for torrent_id, data in torrents.items():
            torrent_id = torrent_id.decode('utf-8')

            if torrent_id in all_torrents:
                all_torrents.remove(torrent_id)
                torrent = get_database().query(Torrent).filter(Torrent.torrent_id == torrent_id).one()
            else:
                torrent = Torrent()

            for file in data[b'files']:
                if Library.is_supported(file[b'path']):
                    has_supported_files = True
                    break
            else:
                has_supported_files = False

            torrent.torrent_id = torrent_id
            torrent.name = data[b'name'].decode('utf-8')
            torrent.has_supported_files = has_supported_files
            torrent.added = datetime.datetime.fromtimestamp(data[b'time_added'])
            torrent.size = data[b'total_size']
            torrent.paused = data[b'paused']
            torrent.finished = data[b'is_finished']
            torrent.progress = data[b'progress']

            get_database().add(torrent)
            get_database().commit()

        if len(all_torrents) > 0:
            (get_database().query(Torrent).filter(Torrent.torrent_id.in_(all_torrents))
                .delete(synchronize_session='fetch'))

        get_database().commit()

    def import_torrent(self, torrent_id):
        config = cherrypy.tree.apps[''].config['opmuse']
        ssh_host = config['deluge.ssh_host']

        if ssh_host is None:
            raise Exception('You need to set deluge.ssh_host')

        debug('fetching torrent %s info' % torrent_id)
        torrent = self.client.call('core.get_torrent_status', torrent_id, [])

        filelist_fd, filelist_path = tempfile.mkstemp()

        files = []

        tempdir = self._mkdtemp().encode()

        with os.fdopen(filelist_fd, 'bw') as f:
            for file in torrent[b'files']:
                path = os.path.join(torrent[b'save_path'], file[b'path'])
                f.write(path + b"\n")
                files.append(os.path.join(tempdir, path[1:]))

        try:
            debug('rsync torrent %s from %s' % (torrent_id, ssh_host))
            output = subprocess.check_output([
                'rsync',
                '-a',
                '-e', 'ssh -oBatchMode=yes -oVisualHostKey=no',
                '--files-from=%s' % filelist_path,
                '%s:/' % ssh_host,
                tempdir
            ], stderr=subprocess.STDOUT)
        except CalledProcessError as error:
            log('Failed to rsync', traceback=True)
            shutil.rmtree(tempdir)
            raise Exception(error.output.decode())
        except Exception:
            log('Failed to rsync', traceback=True)
            shutil.rmtree(tempdir)
            raise
        finally:
            os.remove(filelist_path)

        debug('done rsyncing torrent %s' % torrent_id)

        return files
Example #26
0
    async def on_message(self, message):

        if message.author == self.user:
            return

        text = message.content.strip()

        if message.channel.id == authentication_channel and message.author.id == authentication_user:
            if text == "!stop":
                await sys.exit(1)
            if text == "!clear":
                global queued_requests
                queued_requests = {}
            if text in queued_requests:
                request = queued_requests[text]
                await self.send_request(request)
                await message.channel.send(f"Request approved: {text}")
                await request.requester_channel.send(
                    f"The request for '{request.name}' has been approved!")
                del queued_requests[text]
            else:
                await message.channel.send("That uuid doesn't exist...")

        if not message.guild.name in active_servers:
            return

        if not message.channel.name in active_channels:
            return

        if text.lower().startswith("!add"):
            add_regex = "!add\nmagnet: *(magnet:\?[^ ]*)\nchannel: *([\w\d ]*)\nname: *([\w\d ]*)"
            regex = re.compile(add_regex, re.I | re.M)
            groups = regex.match(text)

            if groups is None:
                await message.channel.send(
                    "Not a valid '!add' command! Use '!help' if you are confused."
                )
                return
            magnet = groups.group(1).strip()
            channel = groups.group(2).strip()
            name = groups.group(3).strip()
            requester_name = message.author.name + message.author.discriminator

            if channel.lower() in plex_channels:
                channel = plex_channels[channel.lower()]
            else:
                await message.channel.send(
                    f"That's not a valid channel on plex! Please choose one of {plex_channels.values()}"
                )
                return

            request = Request(magnet, channel, name, requester_name,
                              message.channel)
            request_uuid = str(uuid.uuid4())
            queued_requests[request_uuid] = request

            auth_channel = self.get_channel(authentication_channel)
            await auth_channel.send(
                f"Request submitted:  {request}\n\n ID: {request_uuid}")
            await message.channel.send(
                f"Your request has been submitted, and is pending approval")

        elif text.lower().startswith("!status"):
            requester_name = message.author.name + message.author.discriminator
            now = time.time()
            then = now - 24 * 60 * 60

            with TinyDB('db') as db:
                request = Query()
                torrents = db.search((request.requester_name == requester_name)
                                     & (request.time > then))

            status_string = f"Here's the status for all the approved torrents requested by {requester_name} in the last 24 hours:\n"
            conn = DelugeClient('master.seedhost.eu', 21110,
                                os.environ['DELUGE_USER'],
                                os.environ['DELUGE_PASS'])
            conn.connect()

            for torrent in torrents:
                torrent_name = torrent['torrent_name']
                torrent_id = torrent['torrent_id']

                status = conn.call('core.get_torrent_status', torrent_id,
                                   ['state', 'total_done', 'total_wanted'])
                if not b'state' in status:
                    continue
                state = status[b'state'].decode()
                total_done = status[b'total_done']
                total_wanted = status[b'total_wanted']
                status_string += "{:<35} {:>15}% completed\n".format(
                    torrent_name, int(total_done / total_wanted * 100))

            await message.channel.send(status_string)

        elif text.lower().startswith("!"):
            help_text_1 = \
            "This is a simple bot that will let you download torrents onto the Plex server, without having harass me " \
            "a ton. Right now, there are only 3 commands:\n" \
            "!add : Allows you to add torrents to the server. Usage is detailed below.\n" \
            "!status : Shows you the download status of all of the approved torrents you requested in the  " \
            "last 24 hours\n" \
            "!help : Shows this message!\n" \
            "\n" \
            "To use !add, you need to provide a information in a specific format. The three pieces of information " \
            "that you will need to provide are: 1) the magnet link to the desired torrent, 2) the plex channel that " \
            "you want the torrent to show up on (so, one of: TV, Movies, Weeb TV), and 3) the name of the media you're " \
            "downloading. This must be provided in a message the follows the given format: \n" \
            "\n" \
            "!add\n" \
            "magnet: <magnet link>\n" \
            "channel: <plex channel>\n" \
            "name: <name of thing>\n" \
            "\n" \
            "So, an example of a valid request would be:\n" \
            "\n" \
            "!add\n" \
            "magnet: magnet:?xt=urn:btih:52FD58172C296021F2E351B8A12BBC8BE7C88F8D&dn=Batman+Begins+%282005%29+1080p+BluRay+x264+-+1.6GB+-+YIFY&tr=udp%3A%2F%2Ftracker.yify-torrents.com%2Fannounce&tr=http%3A%2F%2Finferno.demonoid.me%3A3414%2Fannounce&tr=http%3A%2F%2Ftracker.yify-torrents.com%2Fannounce&tr=udp%3A%2F%2Ftracker.1337x.org%3A80%2Fannounce&tr=http%3A%2F%2Fexodus.desync.com%2Fannounce&tr=http%3A%2F%2Ft1.pow7.com%2Fannounce&tr=http%3A%2F%2Fexodus.desync.com%2Fannounce&tr=http%3A%2F%2Feztv.tracker.prq.to%2Fannounce&tr=http%3A%2F%2Fpow7.com%2Fannounce&tr=http%3A%2F%2Ftracker.torrent.to%3A2710%2Fannounce&tr=udp%3A%2F%2Ftracker.zer0day.to%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fcoppersurfer.tk%3A6969%2Fannounce\n" \
            "channel: Movies\n" \
            "name: Batman Begins\n"

            help_text_2 = \
            "\nNote that this command will not immediately download the torrent. Instead, it will send me a message, " \
            "asking me if I think it's a responsible request. If I approve it, this bot will update this channel to " \
            "let you know its been approved. Only approved torrents will show up in !status.\n" \
            "\n" \
            "Last thing-- I literally wrote this in a couple of hours, and its not meant tp be super robust (yet!). " \
            "I will be continually improving and updating this bot, and I know that there are a few potential bugs, " \
            "as well as a bunch of features I wanna add, so if you hit any issues, just lemme know."

            await message.channel.send(help_text_1)
            await message.channel.send(help_text_2)
Example #27
0
class DelugeClient(object):
    def __init__(self, host, port, username, password):
        """
        Initializes a new Deluge client.
        
        url - The url where deluge json can be reached.
        password - The password used to login
        """
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.rpcclient = DelugeRPCClient(self.host, self.port, self.username, self.password)
    
    def _login(self):
        """
        Logs into deluge
        """
        if not self.rpcclient.connected:
            self.rpcclient.connect()
    
    def test_connection(self):
        """
        Tests the Deluge RPC connection, returns message if found.
        """
        self._login()
        return 'Free space: %s' % humanize_bytes(self.rpcclient.call('core.get_free_space'))
    
    def get_torrents(self):
        """
        Returns a set of info hashes currently added to the client.
        """
        logger.info('Getting a list of torrent hashes')
        self._login()
        result = self.rpcclient.call('core.get_torrents_status', {}, ['name'])
        return set(x.lower() for x in result.keys())
    
    def add_torrent(self, torrent, destination_path, files, fast_resume=True):
        """
        Add a new torrent to Deluge.
        
        torrent is the decoded file as a python object.
        destination_path is where the links are. The complete files must be linked already.
        files is a list of files found in the torrent.
        """
        name = torrent[b'info'][b'name']
        logger.info('Trying to add a new torrent to deluge: %r' % name)
        
        destination_path = os.path.abspath(destination_path)
        
        infohash = hashlib.sha1(bencode(torrent[b'info'])).hexdigest()
        encoded_torrent = base64.b64encode(bencode(torrent))
        
        basename = os.path.basename(destination_path)
        mapped_files = {}
        for i, f in enumerate(files):
            mapped_files[i] = os.path.join(basename, *f['path'])
        
        self._login()
        result = self.rpcclient.call('core.add_torrent_file', 'torrent.torrent', encoded_torrent, {
                                                                'download_location': os.path.dirname(destination_path),
                                                                'mapped_files': mapped_files})
        
        return result and result.decode('utf-8') == infohash
def connect_to_deluge():
    client = DelugeRPCClient(config.DLGD_HOST, config.DLGD_PORT,
                             config.DLGD_USER, config.DLGD_PASS)
    client.connect()
    if client.connected: print "Connected to deluge daemon"

    from types import MethodType

    def add_torr_url(self, url):
        return self.call('core.add_torrent_url', wz.urls.url_fix(url), {})

    client.add_torr_url = MethodType(add_torr_url, client, DelugeRPCClient)

    def add_torr_file(self, file):
        f = open(file, 'rb')
        filedump = base64.encodestring(f.read())
        f.close()
        return self.call('core.add_torrent_file', file, filedump, {})

    client.add_torr_file = MethodType(add_torr_file, client, DelugeRPCClient)

    def add_label(self, label, options={}):
        label = normalize_label(label)
        self.call('label.add', label)
        if options:
            if options['move_completed_path']:
                options.update({
                    'move_completed': True,
                    'apply_move_completed': True
                })
            self.call('label.set_options', label, options)

    client.add_label = MethodType(add_label, client, DelugeRPCClient)

    def label_exist(self, label):
        label = normalize_label(label)
        if label in self.list_labels():
            return True
        else:
            return False

    client.label_exist = MethodType(label_exist, client, DelugeRPCClient)

    def list_labels(self):
        return self.call('label.get_labels')

    client.list_labels = MethodType(list_labels, client, DelugeRPCClient)

    def add_tor_label(self, tor_id, label):
        return self.call('label.set_torrent', tor_id, normalize_label(label))

    client.add_tor_label = MethodType(add_tor_label, client, DelugeRPCClient)

    def session_state(self):
        return self.call('core.get_session_state')

    client.session_state = MethodType(session_state, client, DelugeRPCClient)

    def torrent_status(self, tid, fields={}):
        return self.call('core.get_torrent_status', tid, fields)

    client.torrent_status = MethodType(torrent_status, client, DelugeRPCClient)

    def torrents_status(self, filters={}, fields=[]):
        return self.call('core.get_torrents_status', filters, fields)

    client.torrents_status = MethodType(torrents_status, client,
                                        DelugeRPCClient)

    def get_finished(self):
        torrs = torrents_status(self)
        for k, v in torrs.items():
            #print(k,v['name'])
            if v['is_finished'] == False:
                #print("Removing unfinished: " + v['name'] + " " + str(v['is_finished']))
                torrs.pop(k)
            elif v['tracker_host'] in config.REMOVE_SEEDS_EXCEPTION_TRACKERS:
                #print("Removing exception_tracker: " + v['name'])
                torrs.pop(k)
            elif not is_all_files_done(v):
                #print("Removing not_all_done: " + v['name'])
                torrs.pop(k)
        return torrs

    client.get_finished = MethodType(get_finished, client, DelugeRPCClient)

    def remove_finished(self):
        for k in get_finished(self):
            self.call('core.remove_torrent', k, False)

    client.remove_finished = MethodType(remove_finished, client,
                                        DelugeRPCClient)

    def is_all_files_done(tor):
        for i in tor['file_progress']:
            if i != 1.0:
                return False
        return True

    return client
Example #29
0
class p2p_client():
    def __init__(self, com_id, host_id):
        self.com_id = int(com_id)
        self.host_id = int(host_id)
        self.port = 62000 + (self.com_id - 1) * 100 + (self.host_id - 1)
        self.home_dir = './experiment/'
        self.account = ''
        self.password = ''

    def config(self):
        dir_type = ['Config', 'Log', 'PID', 'Host_Local_Storage', 'NewTorrent']
        ids = 'Com' + str(self.com_id) + '_Host' + str(self.host_id)
        for k in dir_type:
            path = self.home_dir + k + '/' + ids
            if not os.path.isdir(path):
                try:
                    os.makedirs(path)
                except:
                    print 'Error: error when making directories!! dir:', path
                    sys.exit()

        log_file = self.home_dir + 'Log/' + ids + '/' + ids + '.txt'
        pid_file = self.home_dir + 'PID/' + ids + '/' + ids + '.txt'
        if not os.path.isfile(log_file):
            try:
                open(log_file, 'w').close()
            except:
                print 'Error when writing log file'
                sys.exit()
        if not os.path.isfile(pid_file):
            try:
                open(pid_file, 'w').close()
            except:
                print 'Error when writing pid file'
                sys.exit()

    def get_user_info(self):
        config = self.home_dir + 'Config/Com' + str(
            self.com_id) + '_Host' + str(self.host_id) + '/auth'
        try:
            f = open(config, 'r')
            data = f.read().split(':')
            self.account = data[0]
            self.password = data[1]
            f.close()
        except:
            print 'Error: error when getting Accoung/Password'
            sys.exit()

    def start_daemon(self):
        ids = 'Com' + str(self.com_id) + '_Host' + str(self.host_id)
        config_path = self.home_dir + 'Config/' + ids
        log_file = self.home_dir + 'Log/' + ids + '/' + ids + '.txt'
        pid_file = self.home_dir + 'PID/' + ids + '/' + ids + '.txt'
        command = 'deluged -c %s -l %s -P %s -p %s' % (
            config_path, log_file, pid_file, str(self.port))
        os.system(command)
        time.sleep(5)

    def shutdown(self):
        self.client.call('daemon.shutdown')

    def login(self):
        self.client = DelugeRPCClient('127.0.0.1', self.port, self.account,
                                      self.password)
        self.client.connect()

    def get_session_state(self):
        return self.client.call('core.get_session_state')

    def clean_session(self):
        item = self.get_session_state()
        for k in item:
            self.remove_torrent(k)

    def get_method_list(self):
        method = sorted(list(self.client.call('daemon.get_method_list')))
        for k in method:
            print k

    def get_torrent_status(self, hashid):
        return self.client.call('core.get_torrent_status', hashid, '')

    def get_torrents_status(self):
        return self.client.call('core.get_torrents_status', {}, [])

    def add_torrent(self, file_name):
        torrent_file = self.home_dir + 'torrent/' + file_name
        download_path = self.home_dir + 'Host_Local_Storage/' + 'Com' + str(
            self.com_id) + '_Host' + str(self.host_id)
        if not os.path.isdir(download_path):
            try:
                os.makedirs(download_path)
            except:
                print 'Error: error when making download directories'
                sys.exit()
        self.client.call('core.add_torrent_file', torrent_file,
                         base64.encodestring(open(torrent_file, 'rb').read()),
                         {
                             'add_paused': True,
                             'download_location': download_path
                         })

    def remove_torrent(self, hashid, remove_data=True):
        self.client.call('core.remove_torrent', hashid, remove_data)

    def create_torrent(self, file_dst, comment='', create_by=''):
        source = '/home/john/p2p/file/' + file_dst
        torrent_location = self.home_dir + 'NewTorrent/' + 'Com' + str(
            self.com_id) + '_Host' + str(
                self.host_id) + '/' + file_dst + '.torrent'
        tracker = 'http://192.168.144.126:9010/'
        piece_length = 30768
        webseeds = ''
        add_to_session = True
        private = False
        trackers = ''
        self.client.call('core.create_torrent', source, tracker, piece_length,
                         comment, torrent_location, webseeds, private,
                         create_by, trackers, add_to_session)

    def resume_torrent(self, torrents):
        self.client.call('core.resume_torrent', torrents)

    def pause_torrent(self, torrents):
        self.client.call('core.pause_torrent', torrents)

    def set_torrent_max_download_speed(self, torrent, value):
        self.client.call('core.set_torrent_max_download_speed', torrent, value)

    def set_torrent_max_upload_speed(self, torrent, value):
        self.client.call('core.set_torrent_max_upload_speed', torrent, value)

    def get_session_status(self, key=''):
        return self.client.call('core.get_session_status', key)
Example #30
0
File: deluge.py Project: 2mny/mylar
class TorrentClient(object):
    def __init__(self):
        self.conn = None
		
    def connect(self, host, username, password):
        if self.conn is not None:
            return self.connect
	
        if not host:
            return False

        # Get port from the config
        host,portnr = host.split(':')


        #if username and password:
        # logger.info('Connecting to ' + host + ':' + portnr + ' Username: '******' Password: '******'Could not create DelugeRPCClient Object' + e)
            return False
        else:
            try:
                self.client.connect()
            except Exception as e:
                logger.error('Could not connect to Deluge ' + host)
            else:
                return self.client
	
    def find_torrent(self, hash):
        logger.debug('Finding Torrent hash: ' + hash)
        torrent_info = self.get_torrent(hash)
        if torrent_info:
            return True
        else:
            return False

    def get_torrent(self, hash):
        logger.debug('Getting Torrent info from hash: ' + hash)
        try:
            torrent_info = self.client.call('core.get_torrent_status', hash, '')
        except Exception as e:
            logger.error('Could not get torrent info for ' + hash)
            return False
        else:
            if torrent_info is None:
                torrent_info = False
            return torrent_info


    def start_torrent(self, hash):
        try:
            self.find_torrent(hash)
        except Exception as e:
            return False
        else:
            try:
                self.client.call('core.resume_torrent', hash)
            except Exception as e:
                logger.error('Torrent failed to start ' + e)
            else:
                logger.info('Torrent ' + hash + ' was started')
                return True

    def stop_torrent(self, hash):
        try:
            self.client.find_torrent(hash)
        except Exception as e:
            logger.error('Torrent Not Found')
            return False
        else:
            try:
                self.client.call('core.pause_torrent', hash)
            except Exception as e:
                logger.error('Torrent failed to be stopped: ' + e)
                return False
            else:
                logger.info('Torrent ' + hash + ' was stopped')
                return True
        

    def load_torrent(self, filepath):
        
        logger.info('filepath to torrent file set to : ' + filepath)
        torrent_id = False
                
        if self.client.connected is True:
            logger.info('Checking if Torrent Exists!')
            
            if not filepath.startswith('magnet'):
                torrentcontent = open(filepath, 'rb').read()
                hash = str.lower(self.get_the_hash(filepath)) # Deluge expects a lower case hash

                logger.debug('Torrent Hash (load_torrent): "' + hash + '"')
                logger.debug('FileName (load_torrent): ' + str(os.path.basename(filepath)))


                #Check if torrent already added
                if self.find_torrent(str.lower(hash)):
                    logger.info('load_torrent: Torrent already exists!')
                    #should set something here to denote that it's already loaded, and then the failed download checker not run so it doesn't download
                    #multiple copies of the same issues that's already downloaded
                else:
                    logger.info('Torrent not added yet, trying to add it now!')
                    try:
                        torrent_id = self.client.call('core.add_torrent_file', str(os.path.basename(filepath)), base64.encodestring(torrentcontent), '')
                    except Exception as e:
                        logger.debug('Torrent not added')
                        return False
            else:
                try:
                    torrent_id = self.client.call('core.add_torrent_magnet', str(filepath), {})
                except Exception as e:
                    logger.debug('Torrent not added')
                    return False

            # If label enabled put label on torrent in Deluge
            if torrent_id and mylar.CONFIG.DELUGE_LABEL:
                logger.info ('Setting label to ' + mylar.CONFIG.DELUGE_LABEL)
                try:
                    self.client.call('label.set_torrent', torrent_id, mylar.CONFIG.DELUGE_LABEL)
                except:
                 #if label isn't set, let's try and create one.
                    try:
                        self.client.call('label.add', mylar.CONFIG.DELUGE_LABEL)
                        self.client.call('label.set_torrent', torrent_id, mylar.CONFIG.DELUGE_LABEL)
                    except:
                        logger.warn('Unable to set label - Either try to create it manually within Deluge, and/or ensure there are no spaces, capitalization or special characters in label')
                    else:
                        logger.info('Succesfully set label to ' + mylar.CONFIG.DELUGE_LABEL)

        try:
            torrent_info = self.get_torrent(torrent_id)
            logger.info('Double checking that the torrent was added.')
        except Exception as e:
            logger.warn('Torrent was not added! Please check logs')
            return False
        else:
            logger.info('Torrent successfully added!')
            return {'hash':             torrent_info['hash'],
                    'label':            mylar.CONFIG.DELUGE_LABEL,
                    'folder':           torrent_info['save_path'],
                    'total_filesize':   torrent_info['total_size'],
                    'name':             torrent_info['name'],
                    'files':            torrent_info['files'],
                    'time_started':     torrent_info['active_time'],
                    'completed':        torrent_info['is_finished']}


    def delete_torrent(self, hash, removeData=False):
        try:
            self.client.find_torrent(hash)
        except Exception as e:
            logger.error('Torrent ' + hash + ' does not exist')
            return False
        else:
            try:
                self.client.call('core.remote_torrent', hash, removeData)
            except Exception as e:
                logger.error('Unable to delete torrent ' + hash)
                return False
            else:
                logger.info('Torrent deleted ' + hash)
                return True


    def get_the_hash(self, filepath):
        import hashlib, StringIO
        import bencode

        # Open torrent file
        torrent_file = open(filepath, "rb")
        metainfo = bencode.decode(torrent_file.read())
        info = metainfo['info']
        thehash = hashlib.sha1(bencode.encode(info)).hexdigest().upper()
        logger.debug('Hash: ' + thehash)
        return thehash
Example #31
0
class DelugeRPC(object):
    host = 'localhost'
    port = 58846
    username = None
    password = None
    client = None

    def __init__(self,
                 host='localhost',
                 port=58846,
                 username=None,
                 password=None):
        super(DelugeRPC, self).__init__()

        self.host = host
        self.port = port
        self.username = username
        self.password = password

    def connect(self):
        self.client = DelugeRPCClient(self.host, int(self.port), self.username,
                                      self.password)
        self.client.connect()
        return self.client.connected

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

    def test(self):
        try:
            return self.connect()
        except Exception:
            return False

    def add_torrent_magnet(self, torrent, options, torrent_hash):
        try:
            if not self.connect():
                return False

            torrent_id = self.client.core.add_torrent_magnet(torrent,
                                                             options).get()
            if not torrent_id:
                torrent_id = self._check_torrent(torrent_hash)
        except Exception:
            return False
        finally:
            if self.client:
                self.disconnect()

        return torrent_id

    def add_torrent_file(self, filename, torrent, options, torrent_hash):
        try:
            if not self.connect():
                return False

            torrent_id = self.client.core.add_torrent_file(
                filename, b64encode(torrent), options).get()
            if not torrent_id:
                torrent_id = self._check_torrent(torrent_hash)
        except Exception:
            return False
        finally:
            if self.client:
                self.disconnect()

        return torrent_id

    def set_torrent_label(self, torrent_id, label):
        try:
            if not self.connect():
                return False

            self.client.label.set_torrent(torrent_id, label).get()
        except Exception:
            return False
        finally:
            if self.client:
                self.disconnect()

        return True

    def set_torrent_path(self, torrent_id, path):
        try:
            if not self.connect():
                return False

            self.client.core.set_torrent_move_completed_path(torrent_id,
                                                             path).get()
            self.client.core.set_torrent_move_completed(torrent_id, 1).get()
        except Exception:
            return False
        finally:
            if self.client:
                self.disconnect()

        return True

    def set_torrent_priority(self, torrent_ids, priority):
        try:
            if not self.connect():
                return False

            if priority:
                self.client.core.queue_top([torrent_ids]).get()
        except Exception as err:
            return False
        finally:
            if self.client:
                self.disconnect()
        return True

    def set_torrent_ratio(self, torrent_ids, ratio):
        try:
            if not self.connect():
                return False

            self.client.core.set_torrent_stop_at_ratio(torrent_ids, True).get()
            self.client.core.set_torrent_stop_ratio(torrent_ids, ratio).get()
        except Exception as err:
            return False
        finally:
            if self.client:
                self.disconnect()

        return True

    def pause_torrent(self, torrent_ids):
        try:
            if not self.connect():
                return False

            self.client.core.pause_torrent(torrent_ids).get()
        except Exception:
            return False
        finally:
            if self.client:
                self.disconnect()

        return True

    def _check_torrent(self, torrent_hash):
        torrent_id = self.client.core.get_torrent_status(torrent_hash,
                                                         {}).get()
        if torrent_id['hash']:
            sickrage.app.log.debug('DelugeD: Torrent already exists in Deluge')
            return torrent_hash

        return False
Example #32
0
class DelugePlugin(object):
    """Base class for deluge plugins, contains settings and methods for connecting to a deluge daemon."""

    def on_task_start(self, task, config):
        """Raise a DependencyError if our dependencies aren't available"""
        try:
            from deluge_client import DelugeRPCClient
        except ImportError as e:
            log.debug('Error importing deluge-client: %s' % e)
            raise plugin.DependencyError('deluge', 'deluge-client',
                                         'deluge-client >=1.5 is required. `pip install deluge-client` to install.',
                                         log)
        config = self.prepare_config(config)

        if config['host'] in ['localhost', '127.0.0.1'] and not config.get('username'):
            # If an username is not specified, we have to do a lookup for the localclient username/password
            auth = self.get_localhost_auth()
            if auth and auth[0]:
                config['username'], config['password'] = auth
            else:
                raise plugin.PluginError('Unable to get local authentication info for Deluge. You may need to '
                                         'specify an username and password from your Deluge auth file.')

        self.client = DelugeRPCClient(config['host'], config['port'], config['username'], config['password'],
                                      decode_utf8=True)

    def on_task_abort(self, task, config):
        pass

    def prepare_config(self, config):
        config.setdefault('host', 'localhost')
        config.setdefault('port', 58846)
        return config

    def connect(self):
        """Connects to the deluge daemon and runs on_connect_success """

        self.client.connect()

        if not self.client.connected:
            raise plugin.PluginError('Deluge failed to connect.')

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

    def get_torrents_status(self, fields, filters=None):
        """Fetches all torrents and their requested fields optionally filtered"""
        if filters is None:
            filters = {}
        return self.client.call('core.get_torrents_status', filters, fields)

    @staticmethod
    def get_localhost_auth():
        if sys.platform.startswith('win'):
            auth_file = os.path.join(os.getenv('APPDATA'), 'deluge', 'auth')
        else:
            auth_file = os.path.expanduser('~/.config/deluge/auth')
        if not os.path.isfile(auth_file):
            return None

        with open(auth_file) as auth:
            for line in auth:
                line = line.strip()
                if line.startswith('#') or not line:
                    # This is a comment or blank line
                    continue

                lsplit = line.split(':')
                if lsplit[0] == 'localclient':
                    username, password = lsplit[:2]
                    return username, password
Example #33
0
def add_torrent(magnet_url):
    from deluge_client import DelugeRPCClient
    client = DelugeRPCClient('127.0.0.1', 2196, "seftembr", "TuGsFYqlNP")
    client.connect()
    result = client.call('core.add_torrent_magnet', magnet_url, {})
    print "Returned hash:", result
Example #34
0
class DefineDelugeInterface:
    def __init__(self, address, port, username, password):

        # The actual interface with the deluge daemon, via the RPCClient package
        # This object captures the interface (including address & credentials) to be
        # opened, closed, and used to pass messages to the daemon
        self.delugeinterface = DelugeDaemonInterface(address, port, username,
                                                     password)

        # The deluge keys used for gaining overall session data via the 'core.get_session_status' call
        self.delugekeysforsessioninfo = [
            "payload_download_rate", "payload_upload_rate",
            "total_payload_upload"
        ]

        # The deluge keys used for gaining detailed data about a single torrent via the 'core.get_torrent_status' call
        self.delugekeysfortorrentinfo = [
            "state", "save_path", "name", "total_size", "progress", "eta",
            "files", "tracker_status", "is_finished", "time_added",
            "num_seeds", "num_peers"
        ]

        # The full list deluge keys available for gaining detailed data about a single torrent via the
        # 'core.get_torrent_status' call
        self.alldelugekeysavailablefortorrentinfo = [
            "state", "save_path", "tracker", "tracker_status", "next_announce",
            "name", "total_size", "progress", "num_seeds", "total_seeds",
            "num_peers", "total_peers", "eta", "download_payload_rate",
            "upload_payload_rate", "ratio", "distributed_copies", "num_pieces",
            "piece_length", "total_done", "files", "file_priorities",
            "file_progress", "peers", "is_seed", "is_finished", "active_time",
            "seeding_time"
        ]

# =========================================================================================
# Opens a connection with the deluge daemon, for messages to be passed to/from it
# =========================================================================================

    def openconnection(self):

        # Logging.printout("- Connecting to Deluge Daemon&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<small>(" + reasontext + ")</small>")
        try:
            while self.delugeinterface.connected == False:
                self.delugeinterface.connect()
        # print "========================================================="
        # print self.delugeinterface.call('client.api_methods')
        # print "========================================================="
        # WORKS! print self.delugeinterface.call('core.get_free_space')
        # print "========================================================="
        # WORKS! print self.delugeinterface.call('core.get_config')
        # print "========================================================="
            outcome = self.delugeinterface.connected
        except Exception as errortype:
            outcome = None
            print(
                "DELUGE INTERFACE ERROR: Trying to connect to deluge client (",
                errortype, ")")

        return outcome

# =========================================================================================
# Closes the open connection with the deluge daemon
# =========================================================================================

    def closeconnection(self):

        try:
            while self.delugeinterface.connected == True:
                self.delugeinterface.disconnect()
            outcome = self.delugeinterface.connected
        except Exception as errortype:
            outcome = None
            print(
                "DELUGE INTERFACE ERROR: Trying to disconnect from deluge client (",
                errortype, ")")

        return outcome

# =========================================================================================
# Returns a list of strings, one per torrent, providing the GUID of each torrent
# =========================================================================================

    def retrievetorrentlist(self):

        try:
            outcome = []
            rawtorrentlist = self.delugeinterface.call(
                'core.get_session_state')

            for rawtorrentid in rawtorrentlist:
                outcome.append(rawtorrentid.decode("ascii", "ignore"))

        except Exception as errortype:
            print("DELUGE INTERFACE ERROR: Trying to retrieve torrent list (",
                  errortype, ")")
            outcome = None

        return outcome

# =========================================================================================
# Returns a structured/layered dictionary of information about a specified (by GUID) torrent
# =========================================================================================

    def retrievetorrentdata(self, torrentid):

        try:
            outcome = {}
            rawtorrentdata = self.delugeinterface.call(
                'core.get_torrent_status', torrentid,
                self.delugekeysfortorrentinfo)

            for itemkey in rawtorrentdata:
                itemdata = rawtorrentdata[itemkey]
                newkeyname = itemkey.decode("utf-8", "ignore")

                if isinstance(itemdata, bytes) == True:
                    outcome[newkeyname] = itemdata.decode("utf-8", "ignore")

                elif isinstance(itemdata, tuple) == True:
                    newlist = []
                    for subitem in itemdata:
                        newsubdictionary = {}
                        for subitemkey in subitem:
                            newsubitemkey = subitemkey.decode(
                                "utf-8", "ignore")
                            if isinstance(subitem[subitemkey], bytes) == True:
                                newsubitemdata = subitem[subitemkey].decode(
                                    "utf-8", "ignore")
                            else:
                                newsubitemdata = subitem[subitemkey]
                            newsubdictionary[newsubitemkey] = newsubitemdata
                        newlist.append(newsubdictionary)
                    outcome[newkeyname] = newlist

                else:
                    outcome[newkeyname] = itemdata

        except Exception as errortype:
            print(
                "DELUGE INTERFACE ERROR: Trying to retrieve torrent data for "
                + torrentid + " (", errortype, ")")
            outcome = None

        return outcome

# =========================================================================================
# Adds a new torrent to the daemon, using the specified link URL
# Returns the GUID of the added torrent
# =========================================================================================

    def addtorrentlink(self, linkstring):

        try:
            if linkstring[:7] == "magnet:":
                newtorrentid = self.delugeinterface.call(
                    'core.add_torrent_magnet', linkstring, {})
            else:
                newtorrentid = self.delugeinterface.call(
                    'core.add_torrent_url', linkstring, {})
            outcome = newtorrentid.decode("ascii", "ignore")

        except Exception as errortype:
            print("DELUGE INTERFACE ERROR: Trying to add new torrent (",
                  errortype, ")")
            outcome = None

        return outcome

# =========================================================================================
# Instigates a recheck of the specified (by GUID) torrent
# (Returns the RPCClient response, an unknown object)
# =========================================================================================

    def rechecktorrent(self, torrentids):

        try:
            outcome = self.delugeinterface.call('core.force_recheck',
                                                torrentids)
        except Exception as errortype:
            print(
                "DELUGE INTERFACE ERROR: Trying to force recheck of torrent " +
                torrentids + " (", errortype, ")")
            outcome = None
        return outcome

# =========================================================================================
# Pauses the specified (by GUID) torrent
# If "ALL" is specified, all torrents in the daemon are paused
# (Returns the RPCClient response, an unknown object)
# =========================================================================================

    def pausetorrent(self, torrentid):

        try:
            if torrentid == "ALL":
                outcome = self.delugeinterface.call('core.pause_all_torrents')
            else:
                outcome = self.delugeinterface.call('core.pause_torrent',
                                                    [torrentid])
        except Exception as errortype:
            print(
                "DELUGE INTERFACE ERROR: Trying to pause torrent " +
                torrentid + " (", errortype, ")")
            outcome = None

        return outcome

# =========================================================================================
# Unpauses the specified (by GUID) torrent
# If "ALL" is specified, all torrents in the daemon are unpaused
# (Returns the RPCClient response, an unknown object)
# =========================================================================================

    def resumetorrent(self, torrentid):

        try:
            if torrentid == "ALL":
                outcome = self.delugeinterface.call('core.resume_all_torrents')
            else:
                outcome = self.delugeinterface.call('core.resume_torrent',
                                                    [torrentid])

        except Exception as errortype:
            print(
                "DELUGE INTERFACE ERROR: Trying to resume torrent " +
                torrentid + " (", errortype, ")")
            outcome = None

        return outcome

# =========================================================================================
# Deletes the specified (by GUID) torrent
# (Returns the RPCClient response, an unknown object)
# =========================================================================================

    def deletetorrent(self, torrentid):

        try:
            outcome = self.delugeinterface.call('core.remove_torrent',
                                                torrentid, True)
        except Exception as errortype:
            print(
                "DELUGE INTERFACE ERROR: Trying to delete torrent " +
                torrentid + " (", errortype, ")")
            outcome = None

        return outcome

# =========================================================================================
# Returns a dictionary of information about the daemon session
# =========================================================================================

    def retrievesessiondata(self):

        try:
            rawstats1 = self.delugeinterface.call(
                'core.get_session_status', self.delugekeysforsessioninfo)
            rawstats2 = self.delugeinterface.call('core.get_free_space')

            outcome = {}
            outcome['uploadspeed'] = rawstats1[b'payload_upload_rate']
            outcome['downloadspeed'] = rawstats1[b'payload_download_rate']
            outcome['uploadedtotal'] = rawstats1[b'total_payload_upload']
            outcome['freespace'] = rawstats2 / 1000000000

        except Exception as errortype:
            print("DELUGE INTERFACE ERROR: Trying to retrieve session data (",
                  errortype, ")")
            outcome = None

        return outcome
Example #35
0
class TorrentUtils:
    client = None
    methods = []
    torrents = []

    def __init__(self, username='******', password='******', host='127.0.0.1', port=58846):
        self.checkDelugeExist()
        if username and password:
            self.client = DelugeRPCClient(host, port, username, password)
            try:
                self.client.connect()
            except ConnectionRefusedError:
                pass
            self.checkConnection()
            self.getMethods()
            self.getTorrents()

    def checkConnection(self):
        if not self.client or not self.client.connected:
            globalUtils.messageHandler('Torrent daemon not connected', tp='err')
            exit()

    @staticmethod
    def checkDelugeExist():
        if not which('deluge') or not which('deluged'):
            globalUtils.messageHandler('Deluge or Deluged daemon not installed', tp='err')
            exit()

    def getMethods(self) -> list:
        self.methods = self.client.call('daemon.get_method_list')
        return self.methods

    def getTorrents(self, fields: list = [], filters: dict = {}) -> list:
        self.torrents = self.client.call('core.get_torrents_status', filters, fields)
        return self.torrents

    def addTorrent(self, path: Union[str, Path]) -> Union[str, bool]:
        try:
            torrent = Torrent.from_file(path)
        except BencodeDecodingError:
            return False
        torrentId = torrent.info_hash
        if not self.checkTorrentExist(torrent.info_hash):
            fileEncoded = globalUtils.readFile(path)
            torrentId = self.client.call('core.add_torrent_file', '', fileEncoded, {
                'sequential_download': True,
                'prioritize_first_last': True})
            globalUtils.messageHandler(self.getTorrentName(path), '+ Download', tp='msg')
            return torrentId
        globalUtils.messageHandler(self.getTorrentName(path), 'Exist', tp='err')
        self.resumeTorrent(torrentId)
        return torrentId

    def stopTorrent(self, torrentHash: str):
        self.client.call('core.pause_torrent', [torrentHash])

    def resumeTorrent(self, torrentHash: str):
        self.client.call('core.resume_torrent', [torrentHash])

    def setTorrentOptions(self, torrentId: list, options: dict):
        self.client.call('core.set_torrent_options', [torrentId], options)

    def addPlugin(self, path: Union[str, Path]):
        fileEncoded = globalUtils.readFile(path)
        fileName = Path(path).name
        self.client.call('core.upload_plugin', fileName, fileEncoded)

    def checkTorrentExist(self, torrentHash):
        if type(torrentHash) != bytes:
            torrentHash = torrentHash.encode('UTF-8')
        return bool(torrentHash in self.torrents)

    @staticmethod
    def saveTorrentFile(torrentUrl, fileName):
        torrentData = requests.get(torrentUrl).content
        path = globalUtils.saveFile(torrentData, fileName, 'torrentFiles')
        return path

    @staticmethod
    def deleteTorrentFile(fileName):
        globalUtils.deleteFile(fileName, 'torrentFiles')

    @staticmethod
    def getTorrentName(torrent: Union[str, Path]):
        return Torrent.from_file(torrent).name

    @staticmethod
    def getSavedTorrentFiles():
        files = Path('torrentFiles').glob('*.torrent')
        filesList = []
        for f in files:
            filesList.append(str(f))
        return filesList
def main(torrent_id, torrent_name, save_path): 
    file_extensions = ['r\d+', 'rar', 'zip']
    client = DelugeRPCClient(cfg.deluge_address, cfg.deluge_port, cfg.deluge_user, cfg.deluge_pass)
    client.connect()

    print("Starting '%s' with id='%s' at %s" % (torrent_name, torrent_id, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
    
    if not client.connected:
        print("Error connecting to deluge")
        sys.exit()
    
    #pprint.pprint(client.call('core.get_torrents_status', {}, ['name']))
    #pprint.pprint(client.call('core.get_torrent_status', torrent_id, ['files']))
    #print("|".join(file_extensions))
    
    try:
        torrent_file = client.call('core.get_torrent_status', torrent_id, ['files'])['files']
    except:
        print("Error matching torrent_id in deluge")
        sys.exit()
    
    neither_radarr_sonarr = True
    search = False
    for file in torrent_file:
        search = re.search("(" + "|".join(file_extensions) + ")$", file['path'])
        search = search.group() if search else None
        if search:
            print("Torrent contained unwanted file type:")
            print("\t" + file['path'] + "\t" + str(search))
    
            sonarr_item = search_sonarr_for_torrent_name(torrent_name)

            if not sonarr_item:
                radarr_item = search_radarr_for_torrent_name(torrent_name)

                if not radarr_item:
                    print("Torrent not found in radarr or sonarr")
                    break
                else:
                    neither_radarr_sonarr = False

            # Blacklist in sonarr
            
            if radarr_item:
                id = radarr_item['id']
                sonarr_radarr_target = delete_from_radarr
                print("\tSending to radarr background thread.")

            if sonarr_item:
                id = sonarr_item['id']
                sonarr_radarr_target = delete_from_sonarr
                print("\tSending to sonarr background thread.")

            thread = Thread(target = sonarr_radarr_target, args = (id, ))
            thread.start()
            thread.join()
            break
    
    if (not search) and (neither_radarr_sonarr):
        # Torrent is okay, lets start the download.
         print("Torrent is okay, un-pausing download. Neither radar or sonarr == %s" % (neither_radarr_sonarr))
         client.call('core.resume_torrent', [torrent_id])
    else:
        if sonarr_item:
            print("Requesting sonarr searches for the eppisode again")
            url = "http://%s:%s/sonarr/api/command?apikey=%s" % (sonarr_host, sonarr_port, cfg.sonarr_apikey)
        elif radarr_item:
            print("Requesting radarr searches for the eppisode again")
            url = "http://%s:%s/radarr/api/command?apikey=%s" % (radarr_host, radarr_port, cfg.radarr_apikey)
        else:
            print("Neither sonar or radarr... exiting...")
            sys.exit(0)
    
        data={"name": "EpisodeSearch", "episodeIds": [sonarr_item['episode']['id']]}
        #pprint.pprint(data)
        time.sleep(90)
        d = requests.post(url, json=data)
        print("\t'" + url + "', response=" + str(d.status_code) + "\r\n")
    
    print("____________________________________________\r\n")
Example #37
0
class DelugePlugin(object):
    """Base class for deluge plugins, contains settings and methods for connecting to a deluge daemon."""
    def on_task_start(self, task, config):
        """Raise a DependencyError if our dependencies aren't available"""
        try:
            from deluge_client import DelugeRPCClient
        except ImportError as e:
            log.debug('Error importing deluge-client: %s' % e)
            raise plugin.DependencyError(
                'deluge', 'deluge-client',
                'deluge-client >=1.5 is required. `pip install deluge-client` to install.',
                log)
        config = self.prepare_config(config)

        if config['host'] in ['localhost', '127.0.0.1'
                              ] and not config.get('username'):
            # If an username is not specified, we have to do a lookup for the localclient username/password
            auth = self.get_localhost_auth()
            if auth and auth[0]:
                config['username'], config['password'] = auth
            else:
                raise plugin.PluginError(
                    'Unable to get local authentication info for Deluge. You may need to '
                    'specify an username and password from your Deluge auth file.'
                )

        self.client = DelugeRPCClient(config['host'],
                                      config['port'],
                                      config['username'],
                                      config['password'],
                                      decode_utf8=True)

    def on_task_abort(self, task, config):
        pass

    def prepare_config(self, config):
        config.setdefault('host', 'localhost')
        config.setdefault('port', 58846)
        return config

    def connect(self):
        """Connects to the deluge daemon and runs on_connect_success """

        self.client.connect()

        if not self.client.connected:
            raise plugin.PluginError('Deluge failed to connect.')

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

    def get_torrents_status(self, fields, filters=None):
        """Fetches all torrents and their requested fields optionally filtered"""
        if filters is None:
            filters = {}
        return self.client.call('core.get_torrents_status', filters, fields)

    @staticmethod
    def get_localhost_auth():
        if sys.platform.startswith('win'):
            auth_file = os.path.join(os.getenv('APPDATA'), 'deluge', 'auth')
        else:
            auth_file = os.path.expanduser('~/.config/deluge/auth')

        with open(auth_file) as auth:
            for line in auth:
                line = line.strip()
                if line.startswith('#') or not line:
                    # This is a comment or blank line
                    continue

                lsplit = line.split(':')
                if lsplit[0] == 'localclient':
                    username, password = lsplit[:2]
                    return username, password
Example #38
0
class DelugeClient(BaseClient):
    identifier = 'deluge'
    
    def __init__(self, host, username, password):
        """
        Initializes a new Deluge client.
        
        url - The url where deluge json can be reached.
        password - The password used to login
        """
        host, port = host.split(':')
        self.host = host
        self.port = int(port)
        self.username = username
        self.password = password
        self.rpcclient = DelugeRPCClient(self.host, self.port, self.username, self.password)
    
    def _login(self):
        """
        Logs into deluge
        """
        if not self.rpcclient.connected:
            self.rpcclient.connect()
    
    def get_config(self):
        """
        Get the current configuration that can be used in the autotorrent config file
        """
        return {
            'host': '%s:%s' % (self.host, self.port),
            'username': self.username,
            'password': self.password,
        }
    
    @classmethod
    def auto_config(cls):
        """
        Tries to auto configure deluge using the .config/deluge files
        """
        config_path = os.path.expanduser('~/.config/deluge/core.conf')
        if not os.path.isfile(config_path):
            logger.debug('deluge config file was not found')
            return
        
        if not os.access(config_path, os.R_OK):
            logger.debug('Unable to access deluge config file at %s' % config_path)
            return
        
        auth_path = os.path.expanduser('~/.config/deluge/auth')
        if not os.path.isfile(auth_path):
            logger.debug('deluge auth file was not found')
            return
        
        if not os.access(auth_path, os.R_OK):
            logger.debug('Unable to access deluge confauthig file at %s' % auth_path)
            return
        
        with open(config_path, 'r') as f:
            config_data = f.read()
        
        daemon_port = re.findall('"daemon_port":\s*(\d+)', config_data)
        if not daemon_port:
            logger.debug('No deluge port, just trying to use default')
            daemon_port = 58846
        else:
            daemon_port = int(daemon_port[0])
        
        with open(auth_path, 'r') as f:
            auth_data = f.read()
        
        auth_data = auth_data.split('\n')[0].split(':')
        if len(auth_data[0]) < 2:
            logger.debug('Invalid entry found in auth file')
            return
        
        username = auth_data[0]
        password = auth_data[1]
        
        return cls('127.0.0.1:%s' % daemon_port, username, password)
    
    def test_connection(self):
        """
        Tests the Deluge RPC connection, returns message if found.
        """
        self._login()
        return 'Free space: %s' % humanize_bytes(self.rpcclient.call('core.get_free_space'))
    
    def get_torrents(self):
        """
        Returns a set of info hashes currently added to the client.
        """
        logger.info('Getting a list of torrent hashes')
        self._login()
        result = self.rpcclient.call('core.get_torrents_status', {}, ['name'])
        return set(x.lower().decode('ascii') for x in result.keys())
    
    def add_torrent(self, torrent, destination_path, files, fast_resume=True):
        """
        Add a new torrent to Deluge.
        
        torrent is the decoded file as a python object.
        destination_path is where the links are. The complete files must be linked already.
        files is a list of files found in the torrent.
        """
        name = torrent[b'info'][b'name']
        logger.info('Trying to add a new torrent to deluge: %r' % name)
        
        destination_path = os.path.abspath(destination_path)
        
        infohash = hashlib.sha1(bencode(torrent[b'info'])).hexdigest()
        encoded_torrent = base64.b64encode(bencode(torrent))
        
        basename = os.path.basename(destination_path)
        mapped_files = {}
        for i, f in enumerate(files):
            mapped_files[i] = os.path.join(basename, *f['path'])
        
        self._login()
        result = self.rpcclient.call('core.add_torrent_file', 'torrent.torrent', encoded_torrent, {
                                                                'download_location': os.path.dirname(destination_path),
                                                                'mapped_files': mapped_files,
                                                                'seed_mode': fast_resume})
        
        return result and result.decode('utf-8') == infohash
if len(sys.argv) < 4:
    log.error("Not enough command line parameters present, are you launching this from deluge?")
    sys.exit()

path = str(sys.argv[3])
torrent_name = str(sys.argv[2])
torrent_id = str(sys.argv[1])
delete_dir = None

log.debug("Path: %s." % path)
log.debug("Torrent: %s." % torrent_name)
log.debug("Hash: %s." % torrent_id)

client = DelugeRPCClient(host=settings.deluge['host'], port=int(settings.deluge['port']), username=settings.deluge['user'], password=settings.deluge['pass'])
client.connect()

if client.connected:
    log.info("Successfully connected to Deluge")
else:
    log.error("Failed to connect to Deluge")
    sys.exit()

torrent_data = client.call('core.get_torrent_status', torrent_id, ['files', 'label'])
torrent_files = torrent_data['files']
category = torrent_data['label'].lower()

files = []
log.debug("List of files in torrent:")
for contents in torrent_files:
    files.append(contents['path'])
def connect_to_deluge():
    client = DelugeRPCClient(config.DLGD_HOST, config.DLGD_PORT, config.DLGD_USER, config.DLGD_PASS)
    client.connect()
    if client.connected: print "Connected to deluge daemon"

    from types import MethodType
    
    def add_torr_url(self, url):
        return self.call('core.add_torrent_url', wz.urls.url_fix(url), {})
    client.add_torr_url = MethodType(add_torr_url, client, DelugeRPCClient)

    def add_torr_file(self, file):
        f = open(file, 'rb')
        filedump = base64.encodestring(f.read())
        f.close()
        return self.call('core.add_torrent_file', file, filedump, {})
    client.add_torr_file = MethodType(add_torr_file, client, DelugeRPCClient)
    
    def add_label(self, label, options={}):
        label = normalize_label(label)
        self.call('label.add', label)
        if options:
            if options['move_completed_path']:
                    options.update({'move_completed': True, 'apply_move_completed': True})
            self.call('label.set_options', label, options)
    client.add_label = MethodType(add_label, client, DelugeRPCClient)
    
    def label_exist(self, label):
        label = normalize_label(label)
        if label in self.list_labels():
            return True
        else:
            return False
    client.label_exist = MethodType(label_exist, client, DelugeRPCClient)            
        
    def list_labels(self):
        return self.call('label.get_labels')
    client.list_labels = MethodType(list_labels, client, DelugeRPCClient)
    
    def add_tor_label(self, tor_id, label):
        return self.call('label.set_torrent', tor_id, normalize_label(label))
    client.add_tor_label = MethodType(add_tor_label, client, DelugeRPCClient)

    def session_state(self):
        return self.call('core.get_session_state')
    client.session_state = MethodType(session_state, client, DelugeRPCClient)
    
    def torrent_status(self, tid, fields = {}):
        return self.call('core.get_torrent_status', tid, fields)
    client.torrent_status = MethodType(torrent_status, client, DelugeRPCClient)

    def torrents_status(self, filters = {}, fields = []):
        return self.call('core.get_torrents_status', filters, fields)
    client.torrents_status = MethodType(torrents_status, client, DelugeRPCClient)
    
    def get_finished(self):
        torrs = torrents_status(self)
        for k,v in torrs.items():
            #print(k,v['name'])
            if v['is_finished'] == False:
                #print("Removing unfinished: " + v['name'] + " " + str(v['is_finished']))
                torrs.pop(k)
            elif v['tracker_host'] in config.REMOVE_SEEDS_EXCEPTION_TRACKERS:
                #print("Removing exception_tracker: " + v['name'])
                torrs.pop(k)
            elif not is_all_files_done(v):
                #print("Removing not_all_done: " + v['name'])
                torrs.pop(k)
        return torrs
    client.get_finished = MethodType(get_finished, client, DelugeRPCClient)
    
    def remove_finished(self):
        for k in get_finished(self):
            self.call('core.remove_torrent', k, False)
    client.remove_finished = MethodType(remove_finished, client, DelugeRPCClient)
    
    def is_all_files_done(tor):
        for i in tor['file_progress']:
            if i != 1.0: 
                return False
        return True

    return client
Example #41
0
class DelugeRPC(object):
    """Deluge RPC client class."""

    def __init__(self, host='localhost', port=58846, username=None, password=None):
        """Constructor.

        :param host:
        :type host: str
        :param port:
        :type port: int
        :param username:
        :type username: str
        :param password:
        :type password: str
        """
        super(DelugeRPC, self).__init__()
        self.host = host
        self.port = int(port)
        self.username = username
        self.password = password

    def connect(self):
        """Connect to the host using synchronousdeluge API."""
        self.client = DelugeRPCClient(self.host, self.port, self.username, self.password, decode_utf8=True)
        self.client.connect()

    def test(self):
        """Test connection.

        :return:
        :rtype: bool
        """
        try:
            self.connect()
        except Exception:
            return False
        else:
            return True

    def remove_torrent_data(self, torrent_id):
        """Remove torrent from client using given info_hash.

        :param torrent_id:
        :type torrent_id: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            self.client.core.remove_torrent(torrent_id, True)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def move_storage(self, torrent_id, location):
        """Move torrent to new location and return torrent id/hash.

        :param torrent_id:
        :type torrent_id: str
        :param location:
        :type location: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            self.client.core.move_storage(torrent_id, location)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def add_torrent_magnet(self, torrent, options, info_hash):
        """Add Torrent magnet and return torrent id/hash.

        :param torrent:
        :type torrent: str
        :param options:
        :type options: dict
        :param info_hash:
        :type info_hash: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            torrent_id = self.client.core.add_torrent_magnet(torrent, options)
            if not torrent_id:
                torrent_id = self._check_torrent(info_hash)
        except Exception:
            raise
            return False
        else:
            return torrent_id
        finally:
            if self.client:
                self.disconnect()

    def add_torrent_file(self, filename, torrent, options, info_hash):
        """Add Torrent file and return torrent id/hash.

        :param filename:
        :type filename: str
        :param torrent:
        :type torrent: str
        :param options:
        :type options: dict
        :param info_hash:
        :type info_hash: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            torrent_id = self.client.core.add_torrent_file(filename, b64encode(torrent), options)
            if not torrent_id:
                torrent_id = self._check_torrent(info_hash)
        except Exception:
            return False
        else:
            return torrent_id
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_label(self, torrent_id, label):
        """Set Torrent label.

        :param torrent_id:
        :type torrent_id: str
        :param label:
        :type label: str
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.label.set_torrent(torrent_id, label)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_path(self, torrent_id, path):
        """Set Torrent path.

        :param torrent_id:
        :type torrent_id: str
        :param path:
        :type path: str
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.core.set_torrent_move_completed_path(torrent_id, path)
            self.client.core.set_torrent_move_completed(torrent_id, 1)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_priority(self, torrent_id, priority):
        """Set Torrent priority.

        :param torrent_id:
        :type torrent_id: str
        :param priority:
        :type priority: bool
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            if priority:
                self.client.core.queue_top([torrent_id])
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_ratio(self, torrent_id, ratio):
        """Set Torrent ratio.

        :param torrent_id:
        :type torrent_id: str
        :param ratio:
        :type ratio: float
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.core.set_torrent_stop_at_ratio(torrent_id, True)
            self.client.core.set_torrent_stop_ratio(torrent_id, ratio)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def pause_torrent(self, torrent_ids):
        """Pause torrent.

        :param torrent_ids:
        :type torrent_ids: list of str
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.core.pause_torrent(torrent_ids)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def disconnect(self):
        """Disconnect RPC client."""
        self.client.disconnect()

    def _check_torrent(self, info_hash):
        torrent_id = self.client.core.get_torrent_status(info_hash, {})
        if torrent_id.get('hash'):
            log.debug('DelugeD: Torrent already exists in Deluge')
            return info_hash
        return False

    def get_all_torrents(self):
        """Get all torrents in client.

        :return:
        :rtype: bool
        """
        try:
            self.connect()
            torrents_data = self.client.core.get_torrents_status({}, ('name', 'hash', 'progress', 'state',
                                                                      'ratio', 'stop_ratio', 'is_seed', 'is_finished',
                                                                      'paused', 'files'))
        except Exception:
            return False
        else:
            return torrents_data
        finally:
            if self.client:
                self.disconnect()
def c_De():
    __APIURL__ = raw_input("输入API地址(站内查看):")
    __DE_URL__ = raw_input("输入客户端IP(http://IP):")
    __DE_PORT__ = raw_input("输入客户端后端端口(非WebUI端口):")
    __DE_PORT__ = int(__DE_PORT__)
    __DE_USER__ = raw_input("输入客户端用户名:")
    __DE_PW__ = raw_input("输入客户端密码:")

    count = 0

    client = DelugeRPCClient(__DE_URL__, __DE_PORT__, __DE_USER__, __DE_PW__)
    print("Connecting to Deluge...")
    client.connect()
    print("Fetching DMHY torrents from Deluge...")
    torrent_list = client.core.get_torrents_status({}, ['trackers'])
    dmhy_torrent_hash_list = [
        hash_ for hash_ in torrent_list
        if "dmhy" in str(torrent_list[hash_][b'trackers'][0][b'url'])
    ]
    dmhy_req_list = []
    for i, hash_ in enumerate(dmhy_torrent_hash_list):
        dmhy_req_list.append({
            "jsonrpc": "2.0",
            "method": "query",
            "params": [str(hash_)[2:-1]],
            "id": i + 1
        })
    print("Fetching Secure Code...")
    resp = requests.post(__APIURL__, json=dmhy_req_list)
    if resp.status_code != 200:
        raise (Exception("Error with Code {} Pls Try Again!".format(
            resp.status_code)))

    requested_secure_list = resp.json()

    error_torrent_hash_list = []
    print("Begin Updating...")
    for i, hash_ in enumerate(dmhy_torrent_hash_list):
        if "result" in requested_secure_list[i]:
            count += 1
            client.core.set_torrent_trackers(hash_, [{
                'url':
                "https://daydream.dmhy.best/announce?secure={}".format(
                    requested_secure_list[i]["result"]),
                'tier':
                0
            }])
            print("Edited Tracker for {} ({}/{})".format(
                str(hash_)[2:-1], count, len(requested_secure_list)))
        elif "error" in requested_secure_list[i]:
            print("Editing Tracker for {} failed {}. {}".format(
                str(hash_)[2:-1], requested_secure_list[i]["error"]["code"],
                requested_secure_list[i]["error"]["message"]))
            error_torrent_hash_list.append(str(hash_)[2:-1])
        else:
            print("Editing Tracker for {} failed.".format(str(hash_)[2:-1]))
            error_torrent_hash_list.append(str(hash_)[2:-1])

    print()
    print("Successfully edited {} of {} torrents with errors occurred below:".
          format(count, len(requested_secure_list)))
    for each in error_torrent_hash_list:
        print(each)

    print()
    for i in range(2):
        print("Retry Time {}".format(i + 1))

        dmhy_req_list.clear()
        dmhy_torrent_hash_list.clear()
        count = 0

        for i, hash_ in enumerate(error_torrent_hash_list):
            dmhy_torrent_hash_list.append(hash_)
            dmhy_req_list.append({
                "jsonrpc": "2.0",
                "method": "query",
                "params": [hash_],
                "id": i + 1
            })

        print("Fetching Secure Code...")
        resp = requests.post(__APIURL__, json=dmhy_req_list)

        if resp.status_code != 200:
            print("Failed to fetch secure code, retry later")
            time.sleep(20)
            continue

        requested_secure_list = resp.json()
        error_torrent_hash_list.clear()

        print("Begin Updating...")

        for i, hash_ in enumerate(dmhy_torrent_hash_list):
            if "result" in requested_secure_list[i]:
                count += 1
                client.core.set_torrent_trackers(hash_, [{
                    'url':
                    "https://daydream.dmhy.best/announce?secure={}".format(
                        requested_secure_list[i]["result"]),
                    'tier':
                    0
                }])
                print("Edited Tracker for {} ({}/{})".format(
                    str(hash_)[2:-1], count, len(requested_secure_list)))
            elif "error" in requested_secure_list[i]:
                print("Editing Tracker for {} failed {}. {}".format(
                    str(hash_)[2:-1],
                    requested_secure_list[i]["error"]["code"],
                    requested_secure_list[i]["error"]["message"]))
                error_torrent_hash_list.append(str(hash_)[2:-1])
            else:
                print("Editing Tracker for {} failed.".format(
                    str(hash_)[2:-1]))
                error_torrent_hash_list.append(str(hash_)[2:-1])

        print(
            "Successfully edited {} of {} torrents with errors occurred below:"
            .format(count, len(requested_secure_list)))
        if len(error_torrent_hash_list) == 0:
            break
    return 0
Example #43
0
class DelugeRPC(object):
    """Deluge RPC client class."""

    def __init__(self, host='localhost', port=58846, username=None, password=None):
        """Constructor.

        :param host:
        :type host: str
        :param port:
        :type port: int
        :param username:
        :type username: str
        :param password:
        :type password: str
        """
        super(DelugeRPC, self).__init__()
        self.host = host
        self.port = int(port)
        self.username = username
        self.password = password

    def connect(self):
        """Connect to the host using synchronousdeluge API."""
        self.client = DelugeRPCClient(self.host, self.port, self.username, self.password, decode_utf8=True)
        self.client.connect()

    def test(self):
        """Test connection.

        :return:
        :rtype: bool
        """
        try:
            self.connect()
        except Exception:
            return False
        else:
            return True

    def remove_torrent_data(self, torrent_id):
        """Remove torrent from client using given info_hash.

        :param torrent_id:
        :type torrent_id: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            self.client.core.remove_torrent(torrent_id, True)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def move_storage(self, torrent_id, location):
        """Move torrent to new location and return torrent id/hash.

        :param torrent_id:
        :type torrent_id: str
        :param location:
        :type location: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            self.client.core.move_storage([torrent_id], location)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def add_torrent_magnet(self, torrent, options, info_hash):
        """Add Torrent magnet and return torrent id/hash.

        :param torrent:
        :type torrent: str
        :param options:
        :type options: dict
        :param info_hash:
        :type info_hash: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            torrent_id = self.client.core.add_torrent_magnet(torrent, options)
            if not torrent_id:
                torrent_id = self._check_torrent(info_hash)
        except Exception:
            raise
            return False
        else:
            return torrent_id
        finally:
            if self.client:
                self.disconnect()

    def add_torrent_file(self, filename, torrent, options, info_hash):
        """Add Torrent file and return torrent id/hash.

        :param filename:
        :type filename: str
        :param torrent:
        :type torrent: str
        :param options:
        :type options: dict
        :param info_hash:
        :type info_hash: str
        :return:
        :rtype: str or bool
        """
        try:
            self.connect()
            torrent_id = self.client.core.add_torrent_file(filename, b64encode(torrent), options)
            if not torrent_id:
                torrent_id = self._check_torrent(info_hash)
        except Exception:
            return False
        else:
            return torrent_id
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_label(self, torrent_id, label):
        """Set Torrent label.

        :param torrent_id:
        :type torrent_id: str
        :param label:
        :type label: str
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.label.set_torrent(torrent_id, label)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_path(self, torrent_id, path):
        """Set Torrent path.

        :param torrent_id:
        :type torrent_id: str
        :param path:
        :type path: str
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.core.set_torrent_move_completed_path(torrent_id, path)
            self.client.core.set_torrent_move_completed(torrent_id, 1)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_priority(self, torrent_id, priority):
        """Set Torrent priority.

        :param torrent_id:
        :type torrent_id: str
        :param priority:
        :type priority: bool
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            if priority:
                self.client.core.queue_top([torrent_id])
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def set_torrent_ratio(self, torrent_id, ratio):
        """Set Torrent ratio.

        :param torrent_id:
        :type torrent_id: str
        :param ratio:
        :type ratio: float
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.core.set_torrent_stop_at_ratio(torrent_id, True)
            self.client.core.set_torrent_stop_ratio(torrent_id, ratio)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def pause_torrent(self, torrent_ids):
        """Pause torrent.

        :param torrent_ids:
        :type torrent_ids: list of str
        :return:
        :rtype: bool
        """
        try:
            self.connect()
            self.client.core.pause_torrent(torrent_ids)
        except Exception:
            return False
        else:
            return True
        finally:
            if self.client:
                self.disconnect()

    def disconnect(self):
        """Disconnect RPC client."""
        self.client.disconnect()

    def _check_torrent(self, info_hash):
        torrent_id = self.client.core.get_torrent_status(info_hash, {})
        if torrent_id.get('hash'):
            log.debug('DelugeD: Torrent already exists in Deluge')
            return info_hash
        return False

    def get_all_torrents(self):
        """Get all torrents in client.

        :return:
        :rtype: bool
        """
        try:
            self.connect()
            torrents_data = self.client.core.get_torrents_status({}, ('name', 'hash', 'progress', 'state',
                                                                      'ratio', 'stop_ratio', 'is_seed', 'is_finished',
                                                                      'paused', 'files'))
        except Exception:
            return False
        else:
            return torrents_data
        finally:
            if self.client:
                self.disconnect()
Example #44
0
    sys.exit()

path = str(sys.argv[3])
torrent_name = str(sys.argv[2])
torrent_id = str(sys.argv[1])
delete_dir = None

log.debug("Path: %s." % path)
log.debug("Torrent: %s." % torrent_name)
log.debug("Hash: %s." % torrent_id)

client = DelugeRPCClient(host=settings.deluge['host'],
                         port=int(settings.deluge['port']),
                         username=settings.deluge['user'],
                         password=settings.deluge['pass'])
client.connect()

if client.connected:
    log.info("Successfully connected to Deluge")
else:
    log.error("Failed to connect to Deluge")
    sys.exit()

torrent_data = client.call('core.get_torrent_status', torrent_id,
                           ['files', 'label'])
torrent_files = torrent_data['files']
category = torrent_data['label'].lower()

files = []
log.debug("List of files in torrent:")
for contents in torrent_files:
Example #45
0
class Deluge(IntervalModule):
    """
    Deluge torrent module
    Requires `deluge-client`

    .. rubric:: Formatters:

    * `{num_torrents}`       - number of torrents in deluge
    * `{free_space_bytes}`   - bytes free in path
    * `{used_space_bytes}`   - bytes used in path
    * `{upload_rate}` - bytes sent per second
    * `{download_rate}` - bytes received per second
    * `{total_uploaded}`     - bytes sent total
    * `{total_downloaded}`     - bytes received total

    """

    settings = (
        'format',
        ('rounding', 'number of decimal places to round numbers too'),
        ('host', 'address of deluge server (default: 127.0.0.1)'),
        ('port', 'port of deluge server (default: 58846)'),
        ('username', 'username to authenticate with deluge'),
        ('password', 'password to authenticate to deluge'),
        ('path', 'override "download path" server-side when checking space used/free'),
        ('offline_string', 'string to output while unable to connect to deluge daemon')
    )
    required = ('username', 'password')

    host = '127.0.0.1'
    port = 58846
    path = None
    libtorrent_stats = False
    rounding = 2
    offline_string = 'offline'

    format = '⛆{num_torrents} ✇{free_space_bytes}'

    id = int(time.time())  # something random

    def init(self):
        self.client = DelugeRPCClient(self.host, self.port, self.username, self.password)
        self.data = {}

    def run(self):
        if not self.client.connected:
            try:
                self.client.connect()
            except OSError:
                self.output = {
                    'full_text': self.offline_string
                }
                return

        try:
            self.data = self.get_session_statistics()

            torrents = self.get_torrents_status()
            if torrents:
                self.data['num_torrents'] = len(torrents)

            if 'free_space_bytes' in self.format:
                self.data['free_space_bytes'] = self.get_free_space(self.path)
            if 'used_space_bytes' in self.format:
                self.data['used_space_bytes'] = self.get_path_size(self.path)
        except FailedToReconnectException:
            return

        self.parse_values(self.data)

        self.output = {
            'full_text': self.format.format(**self.data)
        }

    def parse_values(self, values):
        for k, v in values.items():
            if v:
                if k in ['total_upload', 'total_download', 'download_rate', 'upload_rate'] or k.endswith('_bytes'):
                    values[k] = '{value:.{round}f}{unit}'.format(round=self.rounding, **bytes_info_dict(v))

    def get_path_size(self, path=None):
        """
        get used space of path in bytes (default: download location)
        """
        if path is None:
            path = []
        return self.client.call('core.get_path_size', path)

    def get_free_space(self, path=None):
        """
        get free space of path in bytes (default: download location)
        """
        if path is None:
            path = []
        return self.client.call('core.get_free_space', path)

    def get_torrents_status(self, torrent_id=None, keys=None):
        if torrent_id is None:
            torrent_id = []
        if keys is None:
            keys = []
        return self.client.call('core.get_torrents_status', torrent_id, keys)

    def get_session_statistics(self):
        keys = ['upload_rate', 'download_rate', 'total_upload', 'total_download']

        out = {}  # some of the values from deluge-client are bytes, the others are ints - we need to decode them
        for k, v in self.client.call('core.get_session_status', keys).items():
            k = k.decode('utf-8')  # keys aswell
            if type(v) == bytes:
                out[k] = v.decode('utf-8')
            else:
                out[k] = v

        return out
Example #46
0
class DelugeService:
    # list of deluge filed - https://libtorrent.org/single-page-ref.html

    def __init__(self, config):
        self._deluge_client = DelugeRPCClient(config.get('deluge', 'host'),
                                              int(config.get('deluge',
                                                             'port')),
                                              config.get('deluge', 'username'),
                                              config.get('deluge', 'password'),
                                              decode_utf8=True)
        self._deluge_client.connect()
        self._label_enable = False
        try:
            self._label_enable = bool(
                strtobool(config.get('deluge', 'LabelEnable',
                                     fallback='false')))
        except ValueError:
            pass

        self._label_id = config.get('deluge', 'LabelId', fallback=None)

        if self._is_label_enabled():
            self.create_label(self._label_id)

    def add_torrent_magnet(self, magnet_url: str) -> str:
        # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L556
        torrent_id = self._deluge_client.core.add_torrent_magnet(
            magnet_url, {})
        if self._is_label_enabled():
            self.set_torrent_label(torrent_id, self._label_id)
        return torrent_id

    def add_torrent_file(self, file_name: str, file_base64_str: str) -> str:
        # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L407
        torrent_id = self._deluge_client.core.add_torrent_file(
            file_name, file_base64_str, {})
        if self._is_label_enabled():
            self.set_torrent_label(torrent_id, self._label_id)
        return torrent_id

    def create_label(self, label_id: str):
        # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/plugins/Label/deluge_label/core.py#L178
        try:
            self._deluge_client.label.add(label_id)
        except Exception as e:
            if 'Exception: Label already exists' not in str(e):
                raise e

    def delete_label(self, label_id: str):
        # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/plugins/Label/deluge_label/core.py#L193
        try:
            self._deluge_client.label.remove(label_id)
        except Exception as e:
            if 'Exception: Unknown Label' not in str(e):
                raise e

    def get_labels(self) -> List[str]:
        # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/plugins/Label/deluge_label/core.py#L173
        return self._deluge_client.label.get_labels()

    def set_torrent_label(self, torrent_id: str, label_id: str):
        # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/plugins/Label/deluge_label/core.py#L312
        self._deluge_client.label.set_torrent(torrent_id, label_id)

    def delete_torrent(self, torrent_id: str):
        # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L574
        self._deluge_client.core.remove_torrent(torrent_id, False)

    def torrent_name_by_id(self, torrent_id: str) -> str:
        # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L758
        return self._deluge_client.core.get_torrent_status(
            torrent_id, ['name'])['name']

    def torrent_status(self, torrent_id: str) -> Dict[str, str]:
        # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L758
        return self._deluge_client.core.get_torrent_status(
            torrent_id, ['name', 'state'])

    def torrents_status(self, torrent_ids: List[str]) -> List[Dict[str, str]]:
        fields = ['name', 'state', 'progress', 'completed_time', 'time_added']
        torrents_dict = self._deluge_client.core.get_torrents_status(
            {"id": [i for i in torrent_ids]}, fields)
        return DelugeService._dict_key_to_obj(torrents_dict)

    def labeled_torrents(self) -> List[Dict[str, str]]:
        if self._is_label_enabled():
            fields = [
                'name', 'state', 'progress', 'completed_time', 'time_added'
            ]
            labeled_torrents = self._deluge_client.core.get_torrents_status(
                {'label': self._label_id}, fields)
            return DelugeService._dict_key_to_obj(labeled_torrents)
        else:
            return []

    def stop_download_torrents(self):
        self._deluge_client.core.set_config({'max_download_speed': "0"})

    def resume_download_torrents(self):
        self._deluge_client.core.set_config({'max_download_speed': "-1"})

    def _is_label_enabled(self) -> bool:
        if self._label_enable and self._label_id:
            return True
        else:
            return False

    @staticmethod
    def _dict_key_to_obj(d) -> List[Dict[str, str]]:
        if not d or not len(d):
            return []
        torrents = []
        for key, value in d.items():
            value['_id'] = key
            torrents.append(value)
        return torrents

    def disconnect(self):
        self._deluge_client.disconnect()
Example #47
0
def init_deluge():
    global deluge
    deluge = DelugeRPCClient(config.deluge_host, config.deluge_port,
                             config.deluge_user, config.deluge_pass)
    deluge.connect()
    assert deluge.connected