CouchPotatoServer unable to access qBittorrent webUI

Windows specific questions, problems.
Post Reply
jrochet

CouchPotatoServer unable to access qBittorrent webUI

Post by jrochet »

I've tried without SSL (1st), with SSL (2nd) - both work fine in a web browser but not from CouchPotato server (latest build as of today (ID 13396)).  I believe it stopped working when qBittorrent went to version 3.3.1.3.  The error messages in CouchPotato even when just doing the "Test qBittorrent" from Settings -> Downloaders, is:

Code: Select all

6-09 14:59:06 ERROR
[ couchpotato.core.event] Error in event "download.status", that wasn't caught: Traceback (most recent call last): File "C:\CouchPotatoServer-master\couchpotato\core\event.py", line 15, in runHandler return handler(*args, **kwargs) File "C:\CouchPotatoServer-master\couchpotato\core\_base\downloader\main.py", line 85, in _getAllDownloadStatus return self.getAllDownloadStatus(ids) File "C:\CouchPotatoServer-master\couchpotato\core\downloaders\qbittorrent_.py", line 125, in getAllDownloadStatus if not self.connect(): File "C:\CouchPotatoServer-master\couchpotato\core\downloaders\qbittorrent_.py", line 30, in connect self.qb.logout() File "C:\CouchPotatoServer-master\libs\qbittorrent\client.py", line 108, in logout response = self._get('logout') File "C:\CouchPotatoServer-master\libs\qbittorrent\client.py", line 34, in _get return self._request(endpoint, 'get', **kwargs) File "C:\CouchPotatoServer-master\libs\qbittorrent\client.py", line 62, in _request raise LoginRequired LoginRequired: Please login first. encoding=cp1252 debug=False args=[] app_dir=C:\CouchPotatoServer-master data_dir=C:\WINDOWS\system32\config\systemprofile\AppData\Roaming\CouchPotato desktop=None options=Namespace(config_file='C:\\WINDOWS\\system32\\config\\systemprofile\\AppData\\Roaming\\CouchPotato\\settings.conf', console_log=False, daemon=False, data_dir=None, debug=False, pid_file='C:\\WINDOWS\\system32\\config\\systemprofile\\AppData\\Roaming\\CouchPotato\\couchpotato.pid', quiet=False)
I'm hoping somebody can have a look at this CouchPotatoServer source file (qbittorrent_.py) and spot what wouldn't work:

Code: Select all

from base64 import b16encode, b32decode
from hashlib import sha1
from datetime import timedelta
import os
import re

from bencode import bencode, bdecode
from couchpotato.core._base.downloader.main import DownloaderBase, ReleaseDownloadList
from couchpotato.core.helpers.encoding import sp
from couchpotato.core.helpers.variable import cleanHost
from couchpotato.core.logger import CPLog
from qbittorrent.client import QBittorrentClient


log = CPLog(__name__)

autoload = 'qBittorrent'


class qBittorrent(DownloaderBase):

    protocol = ['torrent', 'torrent_magnet']
    qb = None

    def __init__(self):
        super(qBittorrent, self).__init__()

    def connect(self):
        if self.qb is not None:
            self.qb.logout()

        url = cleanHost(self.conf('host'), protocol = True, ssl = False)

        if self.conf('username') and self.conf('password'):
            self.qb = QBittorrentClient(url)
            self.qb.login(username=self.conf('username'), password=self.conf('password'))
        else:
            self.qb = QBittorrentClient(url)

        return self.qb._is_authenticated

    def test(self):
        """ Check if connection works
        :return: bool
        """
        return self.connect()

    def download(self, data = None, media = None, filedata = None):
        """ Send a torrent/nzb file to the downloader

        :param data: dict returned from provider
            Contains the release information
        :param media: media dict with information
            Used for creating the filename when possible
        :param filedata: downloaded torrent/nzb filedata
            The file gets downloaded in the searcher and send to this function
            This is done to have failed checking before using the downloader, so the downloader
            doesn't need to worry about that
        :return: boolean
            One faile returns false, but the downloaded should log his own errors
        """

        if not media: media = {}
        if not data: data = {}

        log.debug('Sending "%s" to qBittorrent.', (data.get('name')))

        if not self.connect():
            return False

        if not filedata and data.get('protocol') == 'torrent':
            log.error('Failed sending torrent, no data')
            return False

        if data.get('protocol') == 'torrent_magnet':
            # Send request to qBittorrent directly as a magnet
            try:
                self.qb.download_from_link(data.get('url'), label=self.conf('label'))
                torrent_hash = re.findall('urn:btih:([\w]{32,40})', data.get('url'))[0].upper()
                log.info('Torrent [magnet] sent to QBittorrent successfully.')
                return self.downloadReturnId(torrent_hash)

            except Exception as e:
                log.error('Failed to send torrent to qBittorrent: %s', e)
                return False

        if data.get('protocol')  == 'torrent':
             info = bdecode(filedata)["info"]
             torrent_hash = sha1(bencode(info)).hexdigest()

             # Convert base 32 to hex
             if len(torrent_hash) == 32:
                torrent_hash = b16encode(b32decode(torrent_hash))

             # Send request to qBittorrent
             try:
                self.qb.download_from_file(filedata, label=self.conf('label'))
                log.info('Torrent [file] sent to QBittorrent successfully.')
                return self.downloadReturnId(torrent_hash)
             except Exception as e:
                log.error('Failed to send torrent to qBittorrent: %s', e)
                return False

    def getTorrentStatus(self, torrent):

        if torrent['state'] in ('uploading', 'queuedUP', 'stalledUP'):
            return 'seeding'

        if torrent['progress'] == 1:
            return 'completed'

        return 'busy'

    def getAllDownloadStatus(self, ids):
        """ Get status of all active downloads

        :param ids: list of (mixed) downloader ids
            Used to match the releases for this downloader as there could be
            other downloaders active that it should ignore
        :return: list of releases
        """

        log.debug('Checking qBittorrent download status.')

        if not self.connect():
            return []

        try:
            torrents = self.qb.torrents(status='all', label=self.conf('label'))

            release_downloads = ReleaseDownloadList(self)

            for torrent in torrents:
                if torrent['hash'] in ids:
                    torrent_filelist = self.qb.get_torrent_files(torrent['hash'])

                    torrent_files = []
                    torrent_dir = os.path.join(torrent['save_path'], torrent['name'])

                    if os.path.isdir(torrent_dir):
                        torrent['save_path'] = torrent_dir

                    if len(torrent_filelist) > 1 and os.path.isdir(torrent_dir): # multi file torrent, path.isdir check makes sure we're not in the root download folder
                        for root, _, files in os.walk(torrent['save_path']):
                            for f in files:
                                torrent_files.append(sp(os.path.join(root, f)))

                    else: # multi or single file placed directly in torrent.save_path
                        for f in torrent_filelist:
                            file_path = os.path.join(torrent['save_path'], f['name'])
                            if os.path.isfile(file_path):
                                torrent_files.append(sp(file_path))

                    release_downloads.append({
                        'id': torrent['hash'],
                        'name': torrent['name'],
                        'status': self.getTorrentStatus(torrent),
                        'seed_ratio': torrent['ratio'],
                        'original_status': torrent['state'],
                        'timeleft': str(timedelta(seconds = torrent['eta'])),
                        'folder': sp(torrent['save_path']),
                        'files': torrent_files
                    })

            return release_downloads

        except Exception as e:
            log.error('Failed to get status from qBittorrent: %s', e)
            return []

    def pause(self, release_download, pause = True):
        if not self.connect():
            return False

        torrent = self.qb.get_torrent(release_download['id'])
        if torrent is None:
            return False

        if pause:
            return self.qb.pause(release_download['id'])
        return self.qb.resume(release_download['id'])

    def removeFailed(self, release_download):
        log.info('%s failed downloading, deleting...', release_download['name'])
        return self.processComplete(release_download, delete_files = True)

    def processComplete(self, release_download, delete_files):
        log.debug('Requesting qBittorrent to remove the torrent %s%s.',
                  (release_download['name'], ' and cleanup the downloaded files' if delete_files else ''))

        if not self.connect():
            return False

        torrent = self.qb.get_torrent(release_download['id'])

        if torrent is None:
            return False

        if delete_files:
            self.qb.delete_permanently(release_download['id']) # deletes torrent with data
        else:
            self.qb.delete(release_download['id']) # just removes the torrent, doesn't delete data

        return True


config = [{
    'name': 'qbittorrent',
    'groups': [
        {
            'tab': 'downloaders',
            'list': 'download_providers',
            'name': 'qbittorrent',
            'label': 'qBittorrent',
            'description': 'Use <a href="http://www.qbittorrent.org/" target="_blank">qBittorrent</a> to download torrents.',
            'wizard': True,
            'options': [
                {
                    'name': 'enabled',
                    'default': 0,
                    'type': 'enabler',
                    'radio_group': 'torrent',
                },
                {
                    'name': 'host',
                    'default': 'http://localhost:8080/',
                    'description': 'RPC Communication URI. Usually <strong>http://localhost:8080/</strong>'
                },
                {
                    'name': 'username',
                },
                {
                    'name': 'password',
                    'type': 'password',
                },
                {
                    'name': 'label',
                    'label': 'Torrent Label',
                    'default': 'couchpotato',
                },
                {
                    'name': 'remove_complete',
                    'label': 'Remove torrent',
                    'default': False,
                    'advanced': True,
                    'type': 'bool',
                    'description': 'Remove the torrent after it finishes seeding.',
                },
                {
                    'name': 'delete_files',
                    'label': 'Remove files',
                    'default': True,
                    'type': 'bool',
                    'advanced': True,
                    'description': 'Also remove the leftover files.',
                },
                {
                    'name': 'paused',
                    'type': 'bool',
                    'advanced': True,
                    'default': False,
                    'description': 'Add the torrent paused.',
                },
                {
                    'name': 'manual',
                    'default': 0,
                    'type': 'bool',
                    'advanced': True,
                    'description': 'Disable this downloader for automated searches, but use it when I manually send a release.',
                },
            ],
        }
    ],
}]
PS. I've confirmed that SickRage is working fine with or without SSL enabled on qB's webUI.
Last edited by jrochet on Fri Jun 09, 2017 6:15 pm, edited 1 time in total.
jrochet

Re: CouchPotatoServer unable to access qBittorrent webUI

Post by jrochet »

Also, here are the contents of CouchPotatoServer's \libs\qbittorrent\client.py

Code: Select all

import requests
import json

class LoginRequired(Exception):
    def __str__(self):
        return 'Please login first.'


class QBittorrentClient(object):
    """class to interact with qBittorrent WEB API"""
    def __init__(self, url):
        if not url.endswith('/'):
            url += '/'
        self.url = url

        session = requests.Session()
        check_prefs = session.get(url+'query/preferences')

        if check_prefs.status_code == 200:
            self._is_authenticated = True
            self.session = session
        else:
            self._is_authenticated = False

    def _get(self, endpoint, **kwargs):
        """
        Method to perform GET request on the API.

        :param endpoint: Endpoint of the API.
        :param kwargs: Other keyword arguments for requests.

        :return: Response of the GET request.
        """
        return self._request(endpoint, 'get', **kwargs)

    def _post(self, endpoint, data, **kwargs):
        """
        Method to perform POST request on the API.

        :param endpoint: Endpoint of the API.
        :param data: POST DATA for the request.
        :param kwargs: Other keyword arguments for requests.

        :return: Response of the POST request.
        """
        return self._request(endpoint, 'post', data, **kwargs)

    def _request(self, endpoint, method, data=None, **kwargs):
        """
        Method to hanle both GET and POST requests.

        :param endpoint: Endpoint of the API.
        :param method: Method of HTTP request.
        :param data: POST DATA for the request.
        :param kwargs: Other keyword arguments.

        :return: Response for the request.
        """
        final_url = self.url + endpoint

        if not self._is_authenticated:
            raise LoginRequired

        rq = self.session
        if method == 'get':
            request = rq.get(final_url, **kwargs)
        else:
            request = rq.post(final_url, data, **kwargs)

        request.raise_for_status()

        if len(request.text) == 0:
            data = json.loads('{}')
        else:
            try:
                data = json.loads(request.text)
            except ValueError:
                data = request.text

        return data

    def login(self, username, password):
        """
        Method to authenticate the qBittorrent Client.

        Declares a class attribute named ``session`` which
        stores the authenticated session if the login is correct.
        Else, shows the login error.

        :param username: Username.
        :param password: Password.

        :return: Response to login request to the API.
        """
        self.session = requests.Session()
        login = self.session.post(self.url+'login',
                                  data={'username': username,
                                        'password': password})
        if login.text == 'Ok.':
            self._is_authenticated = True
        else:
            return login.text

    def logout(self):
        """
        Logout the current session.
        """
        response = self._get('logout')
        self._is_authenticated = False
        return response

    @property
    def qbittorrent_version(self):
        """
        Get qBittorrent version.
        """
        return self._get('version/qbittorrent')

    @property
    def api_version(self):
        """
        Get WEB API version.
        """
        return self._get('version/api')

    @property
    def api_min_version(self):
        """
        Get minimum WEB API version.
        """
        return self._get('version/api_min')

    def shutdown(self):
        """
        Shutdown qBittorrent.
        """
        return self._get('command/shutdown')

    def torrents(self, status='active', label='', sort='priority',
                 reverse=False, limit=10, offset=0):
        """
        Returns a list of torrents matching the supplied filters.

        :param status: Current status of the torrents.
        :param label: Fetch all torrents with the supplied label. qbittorrent < 3.3.5
        :param category: Fetch all torrents with the supplied label. qbittorrent >= 3.3.5
        :param sort: Sort torrents by.
        :param reverse: Enable reverse sorting.
        :param limit: Limit the number of torrents returned.
        :param offset: Set offset (if less than 0, offset from end).

        :return: list() of torrent with matching filter.
        """

        STATUS_LIST = ['all', 'downloading', 'completed',
                       'paused', 'active', 'inactive']
        if status not in STATUS_LIST:
            raise ValueError("Invalid status.")
        
        if self.api_version < 10:
            params = {
                'filter': status,
                'label': label,
                'sort': sort,
                'reverse': reverse,
                'limit': limit,
                'offset': offset
            }
            
        elif self.api_version >= 10:
            params = {
                'filter': status,
                'category': label,
                'sort': sort,
                'reverse': reverse,
                'limit': limit,
                'offset': offset
            }
        
        return self._get('query/torrents', params=params)

    def get_torrent(self, infohash):
        """
        Get details of the torrent.

        :param infohash: INFO HASH of the torrent.
        """
        return self._get('query/propertiesGeneral/' + infohash.lower())

    def get_torrent_trackers(self, infohash):
        """
        Get trackers for the torrent.

        :param infohash: INFO HASH of the torrent.
        """
        return self._get('query/propertiesTrackers/' + infohash.lower())

    def get_torrent_webseeds(self, infohash):
        """
        Get webseeds for the torrent.

        :param infohash: INFO HASH of the torrent.
        """
        return self._get('query/propertiesWebSeeds/' + infohash.lower())

    def get_torrent_files(self, infohash):
        """
        Get list of files for the torrent.

        :param infohash: INFO HASH of the torrent.
        """
        return self._get('query/propertiesFiles/' + infohash.lower())

    @property
    def global_transfer_info(self):
        """
        Get JSON data of the global transfer info of qBittorrent.
        """
        return self._get('query/transferInfo')

    @property
    def preferences(self):
        """
        Get the current qBittorrent preferences.
        Can also be used to assign individual preferences.
        For setting multiple preferences at once,
        see ``set_preferences`` method.

        Note: Even if this is a ``property``,
        to fetch the current preferences dict, you are required
        to call it like a bound method.

        Wrong::

            qb.preferences

        Right::

            qb.preferences()

        """
        prefs = self._get('query/preferences')

        class Proxy(Client):
            """
            Proxy class to to allow assignment of individual preferences.
            this class overrides some methods to ease things.

            Because of this, settings can be assigned like::

                In [5]: prefs = qb.preferences()

                In [6]: prefs['autorun_enabled']
                Out[6]: True

                In [7]: prefs['autorun_enabled'] = False

                In [8]: prefs['autorun_enabled']
                Out[8]: False

            """

            def __init__(self, url, prefs, auth, session):
                super(Proxy, self).__init__(url)
                self.prefs = prefs
                self._is_authenticated = auth
                self.session = session

            def __getitem__(self, key):
                return self.prefs[key]

            def __setitem__(self, key, value):
                kwargs = {key: value}
                return self.set_preferences(**kwargs)

            def __call__(self):
                return self.prefs

        return Proxy(self.url, prefs, self._is_authenticated, self.session)

    def sync(self, rid=0):
        """
        Sync the torrents by supplied LAST RESPONSE ID.
        Read more @ http://git.io/vEgXr

        :param rid: Response ID of last request.
        """
        return self._get('sync/maindata', params={'rid': rid})

    def download_from_link(self, link,
                           save_path=None, label=''):
        """
        Download torrent using a link.

        :param link: URL Link or list of.
        :param save_path: Path to download the torrent.
        :param label: Label of the torrent(s). qbittorrent < 3.3.5
        :param category: Label of the torrent(s). qbittorrent >= 3.3.5

        :return: Empty JSON data.
        """
        if not isinstance(link, list):
            link = [link]
        data = {'urls': link}

        if save_path:
            data.update({'savepath': save_path})
        if self.api_version < 10 and label:
            data.update({'label': label})
            
        elif self.api_version >= 10 and label:
            data.update({'category': label})
        

        return self._post('command/download', data=data)

    def download_from_file(self, file_buffer,
                           save_path=None, label=''):
        """
        Download torrent using a file.

        :param file_buffer: Single file() buffer or list of.
        :param save_path: Path to download the torrent.
        :param label: Label of the torrent(s). qbittorrent < 3.3.5
        :param category: Label of the torrent(s). qbittorrent >= 3.3.5

        :return: Empty JSON data.
        """
        if isinstance(file_buffer, list):
            torrent_files = {}
            for i, f in enumerate(file_buffer):
                torrent_files.update({'torrents%s' % i: f})
            print torrent_files
        else:
            torrent_files = {'torrents': file_buffer}

        data = {}

        if save_path:
            data.update({'savepath': save_path})
        if self.api_version < 10 and label:
            data.update({'label': label})
            
        elif self.api_version >= 10 and label:
            data.update({'category': label})
            
        return self._post('command/upload', data=data, files=torrent_files)

    def add_trackers(self, infohash, trackers):
        """
        Add trackers to a torrent.

        :param infohash: INFO HASH of torrent.
        :param trackers: Trackers.
        """
        data = {'hash': infohash.lower(),
                'urls': trackers}
        return self._post('command/addTrackers', data=data)

    @staticmethod
    def process_infohash_list(infohash_list):
        """
        Method to convert the infohash_list to qBittorrent API friendly values.

        :param infohash_list: List of infohash.
        """
        if isinstance(infohash_list, list):
            data = {'hashes': '|'.join([h.lower() for h in infohash_list])}
        else:
            data = {'hashes': infohash_list.lower()}
        return data

    def pause(self, infohash):
        """
        Pause a torrent.

        :param infohash: INFO HASH of torrent.
        """
        return self._post('command/pause', data={'hash': infohash.lower()})

    def pause_all(self):
        """
        Pause all torrents.
        """
        return self._get('command/pauseAll')

    def pause_multiple(self, infohash_list):
        """
        Pause multiple torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/pauseAll', data=data)

    def resume(self, infohash):
        """
        Resume a paused torrent.

        :param infohash: INFO HASH of torrent.
        """
        return self._post('command/resume', data={'hash': infohash.lower()})

    def resume_all(self):
        """
        Resume all torrents.
        """
        return self._get('command/resumeAll')

    def resume_multiple(self, infohash_list):
        """
        Resume multiple paused torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/resumeAll', data=data)

    def delete(self, infohash_list):
        """
        Delete torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/delete', data=data)

    def delete_permanently(self, infohash_list):
        """
        Permanently delete torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/deletePerm', data=data)

    def recheck(self, infohash_list):
        """
        Recheck torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/recheck', data=data)

    def increase_priority(self, infohash_list):
        """
        Increase priority of torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/increasePrio', data=data)

    def decrease_priority(self, infohash_list):
        """
        Decrease priority of torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/decreasePrio', data=data)

    def set_max_priority(self, infohash_list):
        """
        Set torrents to maximum priority level.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/topPrio', data=data)

    def set_min_priority(self, infohash_list):
        """
        Set torrents to minimum priority level.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/bottomPrio', data=data)

    def set_file_priority(self, infohash, file_id, priority):
        """
        Set file of a torrent to a supplied priority level.

        :param infohash: INFO HASH of torrent.
        :param file_id: ID of the file to set priority.
        :param priority: Priority level of the file.
        """
        if priority not in [0, 1, 2, 7]:
            raise ValueError("Invalid priority, refer WEB-UI docs for info.")
        elif not isinstance(file_id, int):
            raise TypeError("File ID must be an int")

        data = {'hash': infohash.lower(),
                'id': file_id,
                'priority': priority}

        return self._post('command/setFilePrio', data=data)

    # Get-set global download and upload speed limits.

    def get_global_download_limit(self):
        """
        Get global download speed limit.
        """
        return self._get('command/getGlobalDlLimit')

    def set_global_download_limit(self, limit):
        """
        Set global download speed limit.

        :param limit: Speed limit in bytes.
        """
        return self._post('command/setGlobalDlLimit', data={'limit': limit})

    global_download_limit = property(get_global_download_limit,
                                     set_global_download_limit)

    def get_global_upload_limit(self):
        """
        Get global upload speed limit.
        """
        return self._get('command/getGlobalUpLimit')

    def set_global_upload_limit(self, limit):
        """
        Set global upload speed limit.

        :param limit: Speed limit in bytes.
        """
        return self._post('command/setGlobalUpLimit', data={'limit': limit})

    global_upload_limit = property(get_global_upload_limit,
                                   set_global_upload_limit)

    # Get-set download and upload speed limits of the torrents.
    def get_torrent_download_limit(self, infohash_list):
        """
        Get download speed limit of the supplied torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/getTorrentsDlLimit', data=data)

    def set_torrent_download_limit(self, infohash_list, limit):
        """
        Set download speed limit of the supplied torrents.

        :param infohash_list: Single or list() of infohashes.
        :param limit: Speed limit in bytes.
        """
        data = self.process_infohash_list(infohash_list)
        data.update({'limit': limit})
        return self._post('command/setTorrentsDlLimit', data=data)

    def get_torrent_upload_limit(self, infohash_list):
        """
        Get upoload speed limit of the supplied torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/getTorrentsUpLimit', data=data)

    def set_torrent_upload_limit(self, infohash_list, limit):
        """
        Set upload speed limit of the supplied torrents.

        :param infohash_list: Single or list() of infohashes.
        :param limit: Speed limit in bytes.
        """
        data = self.process_infohash_list(infohash_list)
        data.update({'limit': limit})
        return self._post('command/setTorrentsUpLimit', data=data)

    # setting preferences
    def set_preferences(self, **kwargs):
        """
        Set preferences of qBittorrent.
        Read all possible preferences @ http://git.io/vEgDQ

        :param kwargs: set preferences in kwargs form.
        """
        json_data = "json={}".format(json.dumps(kwargs))
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        return self._post('command/setPreferences', data=json_data,
                          headers=headers)

    def get_alternative_speed_status(self):
        """
        Get Alternative speed limits. (1/0)
        """
        return self._get('command/alternativeSpeedLimitsEnabled')

    alternative_speed_status = property(get_alternative_speed_status)

    def toggle_alternative_speed(self):
        """
        Toggle alternative speed limits.
        """
        return self._get('command/toggleAlternativeSpeedLimits')

    def toggle_sequential_download(self, infohash_list):
        """
        Toggle sequential download in supplied torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/toggleSequentialDownload', data=data)

    def toggle_first_last_piece_priority(self, infohash_list):
        """
        Toggle first/last piece priority of supplied torrents.

        :param infohash_list: Single or list() of infohashes.
        """
        data = self.process_infohash_list(infohash_list)
        return self._post('command/toggleFirstLastPiecePrio', data=data)

    def force_start(self, infohash_list, value=True):
        """
        Force start selected torrents.

        :param infohash_list: Single or list() of infohashes.
        :param value: Force start value (bool)
        """
        data = self.process_infohash_list(infohash_list)
        data.update({'value': json.dumps(value)})
        return self._post('command/setForceStart', data=data)

johnhtig

Re: CouchPotatoServer unable to access qBittorrent webUI

Post by johnhtig »

Have you found a reason or a fix yet .... i'm having the same problem
jrochet

Re: CouchPotatoServer unable to access qBittorrent webUI

Post by jrochet »

I can't remember if I fixed anything or if it started to work with either a CP or QBT later version.

I have put the IP and fqdn in my hosts file for the QBT website and I'm using a let's encrypt cert.  Both CP and QBT are current versions and it's working.

Might want to make sure CP can resolve the IP and that QBT web server is set to allow either 0.0.0.0 or at least the CP server's IP.

CP is about the flaky'est piece of software I've ever encountered.  I regularly wish the Sickrage team would do a movies edition.  Another thing, I use Jackett for grabbing torrents and configure CP's Potato Torrent provider accordingly, rather than having CP reach out to search Torrent site(s) directly.  That solved a lot of recurring headaches there too.
johnhtig

Re: CouchPotatoServer unable to access qBittorrent webUI

Post by johnhtig »

Thank You for responding so quickly ...... Can you please explain further about this"
I have put the IP and fqdn in my hosts file for the QBT website and I'm using a let's encrypt cert.  Both CP and QBT are current versions and it's working.
Might want to make sure CP can resolve the IP and that QBT web server is set to allow either 0.0.0.0 or at least the CP server's IP.


I also use Jackett .... please look at this screen shot https://1drv.ms/u/s!AsnwYFe1b8WTkliDe8xIe2lkSv2-
Am i on the right track
jrochet

Re: CouchPotatoServer unable to access qBittorrent webUI

Post by jrochet »

I see you have checked the bypass authentication boxes.  If CP is on the same computer, or is one of those IP's in the list, you might want to uncheck the corresponding box and then make sure to enter the admin username and password in CP's settings.  I haven't tested but maybe CP doesn't like doing no authentication.
johnhtig

Re: CouchPotatoServer unable to access qBittorrent webUI

Post by johnhtig »

CP and Qbt are on the same box @ 10.0.0.179... i tried unchecking the auth bypass box.... still not working. Do you have any other suggestions
jrochet

Re: CouchPotatoServer unable to access qBittorrent webUI

Post by jrochet »

Sorry I don't have any other thoughts.  I remember being in the same boat and like I said can't remember doing any specific thing to make it work.  It looked as though you're running either Mac or Linux in the screenshot, I'm using Windows, so it could be something specific to your setup.  I also am using CouchPotatoServer from GitHub - https://github.com/CouchPotato/CouchPotatoServer - on the master branch.  There were times I changed to the development branch to get around other issues.  To do that, it's in CP -> Settings -> General -> Show Advanced -> there's a "Development" checkbox.  That changes your branch to 'develop' instead of 'master' and then you can check for updates and it should find a different version to update to.  But there would be new different issues potentially in the develop branch so it's a toughy.

You might do well to use Blackhole instead of qBittorrent's webUI for CouchPotato.  The only real loss is you can't add a torrent label that way.  I did donate to qb and request a feature to automatically add a category/label based on which blackhole folder the torrent was dropped in.  This would even the scores for blackhole vs webUI as far as CP+qB goes.  Maybe do the same and hope they'll add the feature.
johnhtig

Re: CouchPotatoServer unable to access qBittorrent webUI

Post by johnhtig »

I'm going with Blackhole for now ..... I'm tired of the headache
Thank You for all your help
Post Reply