Giter Site home page Giter Site logo

rmartin16 / qbittorrent-api Goto Github PK

View Code? Open in Web Editor NEW
386.0 4.0 66.0 3.68 MB

Python client implementation for qBittorrent's Web API

Home Page: https://qbittorrent-api.readthedocs.io/

License: MIT License

Python 100.00%
qbittorrent python-client torrents client webapi api api-client python

qbittorrent-api's Introduction

qBittorrent Web API Client

Python client implementation for qBittorrent Web API

GitHub Workflow Status (branch) Codecov branch PyPI PyPI - Python Version

Currently supports qBittorrent v4.6.5 (Web API v2.9.3) released on May 26, 2024.

User Guide and API Reference available on Read the Docs.

Features

  • The entire qBittorrent Web API is implemented.
  • qBittorrent version checking for an endpoint's existence/features is automatically handled.
  • If the authentication cookie expires, a new one is automatically requested in line with any API call.

Installation

Install via pip from PyPI

python -m pip install qbittorrent-api

Getting Started

import qbittorrentapi

# instantiate a Client using the appropriate WebUI configuration
conn_info = dict(
    host="localhost",
    port=8080,
    username="admin",
    password="adminadmin",
)
qbt_client = qbittorrentapi.Client(**conn_info)

# the Client will automatically acquire/maintain a logged-in state
# in line with any request. therefore, this is not strictly necessary;
# however, you may want to test the provided login credentials.
try:
    qbt_client.auth_log_in()
except qbittorrentapi.LoginFailed as e:
    print(e)

# if the Client will not be long-lived or many Clients may be created
# in a relatively short amount of time, be sure to log out:
qbt_client.auth_log_out()

# or use a context manager:
with qbittorrentapi.Client(**conn_info) as qbt_client:
    if qbt_client.torrents_add(urls="...") != "Ok.":
        raise Exception("Failed to add torrent.")

# display qBittorrent info
print(f"qBittorrent: {qbt_client.app.version}")
print(f"qBittorrent Web API: {qbt_client.app.web_api_version}")
for k, v in qbt_client.app.build_info.items():
    print(f"{k}: {v}")

# retrieve and show all torrents
for torrent in qbt_client.torrents_info():
    print(f"{torrent.hash[-6:]}: {torrent.name} ({torrent.state})")

# stop all torrents
qbt_client.torrents.stop.all()

qbittorrent-api's People

Contributors

angristan avatar bobokun avatar burritothief avatar dependabot[bot] avatar miigotu avatar moius avatar rmartin16 avatar trim21 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

qbittorrent-api's Issues

Implement add torrent from bytes

As I have seen in https://github.com/rmartin16/qbittorrent-api/blob/master/qbittorrentapi/torrents.py#L618, we can pass only string/ list of strings (path/paths) to torrents_add(torrent_files=), could you make it so that we can pass the bytes directly.

I am creating a python code where it downloads .torrent file using requests and directly start downloading the content by passing the response bytes. I could do this before with another package I was using python-qBitorrent, now I could save the file and then pass the path, but my aim is not to keep the .torrent file.

An example that I was using with python-qBitorrent is:

data = requests.get('url_to_torrentfile.torrent')
qb.download_from_file(data.content)

Now I see 2 approaches that can be implemented

  1. Maybe create another parameter for torrents_add something like torrents_bytes that takes 1 or list of bytes
  2. Let the users directly pass open('filepath') to torrent_files, 1 or list of them. Like how it's done in this:
    https://github.com/v1k45/python-qBittorrent/blob/master/qbittorrent/client.py#L363
    https://github.com/v1k45/python-qBittorrent#downloading-torrents

As I see it 2nd approach is the easiest.

DISABLE_LOGGING_DEBUG_OUTPUT: no effect

I'm trying to disable API log output. Here is my code:

logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', datefmt='%d.%m.%Y %H:%M:%S')
…
logging.getLogger('qbittorrentapi').setLevel(logging.INFO)
logging.getLogger('requests').setLevel(logging.INFO)
logging.getLogger('urllib3').setLevel(logging.INFO)
QBT_CLIENT = qbittorrentapi.Client(host='IP', username='admin', password='adminadmin', DISABLE_LOGGING_DEBUG_OUTPUT=True)

try:
    QBT_CLIENT.auth_log_in()
except Exception as e:
    logging.critical("Exit: " + str(e))
    quit()

But I keep seeing WARNINGs from the API:

13.08.2022 15:14:49 WARNING: Retrying (Retry(total=0, connect=0, read=1, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPSConnection object at 0xb5572870>: Failed to establish a new connection: [Errno 111] Connection refused')': /api/v2/auth/login
13.08.2022 15:14:49 WARNING: Retrying (Retry(total=0, connect=0, read=1, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPSConnection object at 0xb55182f0>: Failed to establish a new connection: [Errno 111] Connection refused')': /api/v2/auth/login
13.08.2022 15:14:50 WARNING: Retrying (Retry(total=0, connect=0, read=1, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPSConnection object at 0xb5572b10>: Failed to establish a new connection: [Errno 111] Connection refused')': /api/v2/auth/login
13.08.2022 15:14:50 CRITICAL: Exit: Failed to connect to qBittorrent. Connection Error: ConnectionError(MaxRetryError("HTTPSConnectionPool(host='IP', port=PORT): Max retries exceeded with url: /api/v2/auth/login (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0xb5572430>: Failed to establish a new connection: [Errno 111] Connection refused'))"))

What's wrong?

qbt: v4.4.3.1
qbittorrent-api: 2022.8.34
Python: 3.7.3

allow port to be explicitly provided when instantiating Client

add a port parameter to Client.

qbt_client = qbittorrentapi.Client(host='localhost', username='admin', password='adminadmin')

port should still be supported as part of host...although, port should probably trump host if a port is passed in both places.

torrents_setLocation with spaces

If the new Location includes spaces in the directory names they are replaced with +.
I've tried to escape the spaces or replace them with \x20 to no avail.

If I use urllib.parse.quote(location) then qbittorren's API doesn't decode that and creates a new path with a literal %20 replacing the spaces.

The WebUI doesn't have this problem. (torrents_set_location does not change location before submitting it as a dict using _post, so I presume this is from urllib.parse import urljoin being "helpful" and replacing the spaces with + ?)

Feature request: Return torrent hash on add()

Hello :)
First of all thanks a lot for your API, it roxx !

I'm having a use-case where I want to:

  • add torrent to qbitorrent
  • track that the torrent is complete
  • download the torrent

Right now adding a torrent returns "Ok." or "Fail". therefore I cannot track the current torrent that have been added.

I have a way of fixing my use-case with

src = '%s/%s' % (self.torrent_folder, filename)
t_name = re.sub('\.torrent$', '', filename)
client.add_torrent(src); # client is an instance of a custom class that abstract the API

for torrent in client.torrents.info.all():
    if torrent.name != t_name:
        continue
...

But having a condition on the torrent name is not really secure/safe/proper/beautiful/... ^^ :(

Would it be possible to retrieve the torrent hash in the response of the torrent_add function ?

Goal would be:

src = '%s/%s' % (self.torrent_folder, filename)
hash = client.add_torrent(src);

# dirty code example
while True:
  if complete(hash):
      break
...

There is one thing I don't understand in the code, the return of torrents_add is supposed to be requests.request response where there should have a lot of data available in the response no ?

decrease_priority() simultaneously

sorry for my bad English and this is very basic,
I have this part code:

    for torrent in qbt_client.torrents_info():
        if str(torrent.state) == 'stalledDL':
            print(torrent.name,"priority is reduced")
            torrent.decrease_priority()

my problem is: when 2 or more queues are "sequentially", they stacks,
how to select multiple torrents, and decrease_priority them together at once?
thank you, have a nice day

Set preferences seems not working

qbittorrent is 4.1.5, api version is 2.2, with python2.7
I follow the instructions:
">>> from qbittorrentapi import Client
">>> client = Client(host='localhost:8080', username='admin', password='adminadmin')
">>> is_dht_enabled = client.application.preferences.dht
">>>is_dht_enabled
True
">>> client.application.preferences = dict(dht=(not is_dht_enabled))
">>> client.application.preferences.dht
True
The results show that the set preferences is not working.
So I tried the set_preferences methods:
">>> client.app.set_preferences(dict(dht=(not is_dht_enabled)))
<Response [200]>
">>> client.application.preferences.dht
True
It is also not working.
Am I wrong to use the methods?
Best wishes!

Timeout seems to be in multiples of 10

Describe the bug

When I set requests_args={'timeout': 1} it takes 10 seconds to stop trying.

So setting it to something like requests_args={'timeout': 4} would take 40 seconds. Is this intended?

Steps to reproduce

requests_args={'timeout': 1}

Expected behavior

For this to only take 1 second

Screenshots

No response

Environment

  • Operating System: Windows 10
  • Python version: Version 3.10
  • Software versions:
    • qBittorrent: Latest
    • qbittorrent-api: Latest

Additional context

No response

torrents_rename_folder method has no effect

In qBitorrent v4.2.5,
when using the torrents_rename_folder method to rename a folder that is the content of a torrent, no error is raised, nor does it generate any rename effect.

I try to change the folder of a torrent's internal content, similar to what can be done using the qbittorrent application by going to the 'Content' tab, selecting a folder, hitting the 'F2' button and renaming it.

initialize_lesser() got an unexpected keyword argument 'requests_args'

As https://qbittorrent-api.readthedocs.io/en/latest/behavior&configuration.html?highlight=timeout#requests-configuration
But I get err

  File "download_task_manager_qb.py", line 171, in __init__
    qbt_client = qbittorrentapi.Client(
  File "/usr/local/lib/python3.8/dist-packages/qbittorrentapi/client.py", line 94, in __init__
    super(Client, self).__init__(
  File "/usr/local/lib/python3.8/dist-packages/qbittorrentapi/request.py", line 111, in __init__
    self._initialize_lesser(**kwargs)
TypeError: _initialize_lesser() got an unexpected keyword argument 'requests_args'

Confused about paths in torrents_rename_folder

I'm trying to rename a torrent folder using the API..
I use an absolute path for both the new and old paths (in linux, haven't tried windows), and I get an error message that absolute paths are not allowed.
So what are the paths supposed to be relative to? I can't find any examples or explanations in the documentation.
This should be more of a forum question, so where is the best place to ask questions like this?

Process left behind when preferences are set

qbittorrent-api leaves behind a QThread process every time the preferences are set for every new client. At first I thought this was happening because I was not logging out using auth_log_out(), but nothing changed even after logging out.

$ pip show qbittorrent-api
Name: qbittorrent-api
Version: 2022.11.40
[...]

Steps to reproduce

  1. Launch the daemon (if it is not already running)
qbittorrent-nox --daemon
  1. Open an interactive process viewer (htop) in a separate window and monitor qbittorrent-nox processes
  2. Run the following Python script and observe QThread processes spawn
from qbittorrentapi import Client

for _ in range(10):
    c = Client(host="localhost:8080", username="admin", password="adminadmin")
    c.application.preferences = {"max_ratio": 2.0}
    # c.app_set_preferences({"max_ratio": 2.0})

Before
image

After
image

Expectation

Expected QThread to properly terminate after the connection ends.

client.torrents.info.paused() is returning completed torrents?

Hi!.

First I would like to thank you for your excellent work on this api-client. I'm currently using it to handle my qbittorrent queue. Anyway I stumbled into a small hiccup, which is when retrieving paused torrents with the statement qbt_client.torrents.info.paused() the api returns torrents that are in 'Completed' status too. Is this normal behaviour or it's a bug?

Version:

api: qbittorrent-api==2020.12.15
qbt: 4.3.1
python: python:3.8 image from Dockerhub

Regards

Document which version of qBittorrent API we are up to?

I'm curious - do you know which version of the qBittorrent API we are up to please?

https://github.com/qbittorrent/qBittorrent/wiki/Web-API-Documentation#changes

For example, we have a RSS refreshItem call - so we're definitely past 2.2.1.

But it's not clear if we support torrents/renameFile, which came in 2.4.0? (There's a rename call, but that's for torrents?)

Would it be worth documenting which version we're up to in the README somewhere?

Return Torrent hash or `TorrentDictionary` from `Client.torrents.add()` and Support Additional Actions when Adding a Torrent

I want to enable super seeding at the time that I add a torrent via an additional parameter to qbt_client.torrents_add(urls='...'), like qbt_client.torrents_add(urls='...', enable_super_seeding=True).

I don't want to have to lookup the torrent hash, and make a separate request to enable super seeding. Using qbt_client.set_super_seeding(...) is less convenient.

I understand that this may mean straying from implementing the existing API calls exactly, but I think that the UX benefit of this Python library will make it worth it.

missing getting progress

Hi, lovely lib!
I'm trying to query the client for progress of a specific torrent.
right now I don't see any method to get progress as described here:
https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-Documentation#get-torrent-contents

moreover, the methods that are available (i.e. top priority) only seem to be available though a torrent instance, that must be be received through iteration on torrent list?
I want to address a specific torrent through its hash, and I can't find a way.

torrents_add(torrent_files=raw_bytes) does not work in Python 3

The torrents_add() function is documented as accepting a byte string as one of the possible types for the torrent_files argument, but this does not work in Python 3.

At line 647, the if statement is skipped for type 'bytes', and user_files does not get wrapped in a list
https://github.com/rmartin16/qbittorrent-api/blob/master/qbittorrentapi/torrents.py#L647

At line 651, type 'bytes' is not a Mapping, so we end up with the "else" statement which creates a massive dictionary due to enumerating over every byte in the byte string.
https://github.com/rmartin16/qbittorrent-api/blob/master/qbittorrentapi/torrents.py#L651

I think the bug is on line 647, where checking against six.string_types (which resolves to only "str" in Python 3), should instead check against "unicode", "str", and "bytes". For example:

isinstance(user_files, (bytes, six.text_type))

[Question] get only recently added torrents.

This is a question. Sorry for asking here but not sure where else to. I had a look through the wiki but dont see it so said i would ask or else i missed it.

Currently its not possible to add tags to a torrent when adding them from the webUI manually so I want to write a script which checks the last X recently added torrents and add tags to them depending on the tracker, source and if the torrent is private. I plan to run this once every 30 minutes or so inn a cron job. In my case i have thousands of torrents and dont want to have to check each one when it was added, does it have tags etc.. so am hoping to be able to get n most recently added torrents.

Have you any suggestions on how to do this without getting all torrents and then filtering them.

qbittorrent-api Doesn't Work At All on Python 3.10-dev Since AttrDict Breaks

AttrDict imports Mapping directly from collections....the latest dev version of python 3.10 started raising ImportError for this since they want you to import it from collections.abc.

AttrDict was also abandoned by the original developer....so i'll probably have to find someone managing a fork....or fork it myself i guess.

Python 3.10 isn't being released till late Q3 or Q4 2021....so there's time.

ImportError while loading conftest '/home/runner/work/qbittorrent-api/qbittorrent-api/tests/conftest.py'.
tests/conftest.py:8: in <module>
    from qbittorrentapi import APIConnectionError
qbittorrentapi/__init__.py:1: in <module>
    from qbittorrentapi.client import Client
qbittorrentapi/client.py:1: in <module>
    from qbittorrentapi.app import AppAPIMixIn
qbittorrentapi/app.py:10: in <module>
    from qbittorrentapi.definitions import APINames
qbittorrentapi/definitions.py:8: in <module>
    from attrdict import AttrDict
/opt/hostedtoolcache/Python/3.10.0-alpha.5/x64/lib/python3.10/site-packages/attrdict/__init__.py:5: in <module>
    from attrdict.mapping import AttrMap
/opt/hostedtoolcache/Python/3.10.0-alpha.5/x64/lib/python3.10/site-packages/attrdict/mapping.py:4: in <module>
    from collections import Mapping
E   ImportError: cannot import name 'Mapping' from 'collections' (/opt/hostedtoolcache/Python/3.10.0-alpha.5/x64/lib/python3.10/collections/__init__.py)
Error: Process completed with exit code 4.

Can't show uncategorized torrents

torrents = qbt_client.torrents_info(category='null');
torrents = qbt_client.torrents_info(category='NULL');
torrents = qbt_client.torrents_info(category='');
torrents = qbt_client.torrents_info(category='Uncategorized');
torrents = qbt_client.torrents_info(category='uncategorized');

I just want to print uncategorized torrents, and I tried all above way, but none of them works.

From qbittorrent official api guide:

Get torrents with the given category (empty string means "without category"; no "category" param means "any category")

Could you help a bit?Thanks a lot .

Get torrent object on adding torrent

Is it possible that you can make it so that when torrents_add is called it returns torrent object? Supposedly I have a torrent magnet url and no other info about it, and the hash is tagged-info-hash which is not info-hash,

Example magnet link:
magnet:?xt=urn:btih:GQMKCY7EZSUS3PDQY7FL23X2AM763ESE&tr=udp://tracker.coppersurfer.tk:6969/announce
I thought assuming and using GQMKCY7EZSUS3PDQY7FL23X2AM763ESE as info hash was enough, but after I added the magnet url the info hash came out as 3418a163e4cca92dbc70c7cabd6efa033fed9244 and then I learnt that there are 2 types of hashes from here: https://stackoverflow.com/questions/61640538/obtaining-metadata-from-magnetlink-infohash

In this scenario after adding the torrent I don't know how to get the torrent object, because torrents_add returns Ok. and the torrent is then lost (No way to find which is the added torrent)

torrents_info does not work with tag

Example code:

torrents_with_tag = qbt.torrents_info(category="TestingTags", tag='Test')
for torrent in torrents_with_tag:
    print(torrent.name)

The output prints all torrent names with the category TestingTags. It ignores the tag parameter or does not process it.

Unauthorized even though curl works

Following my comment on your PR, here's my current problem

Running

import qbittorrentapi

# instantiate a Client using the appropriate WebUI configuration
qbt_client = qbittorrentapi.Client(host='https://qbittorrent.DOMAIN.TLD', port=443, username='USER', password='PASS')

# the Client will automatically acquire/maintain a logged in state in line with any request.
# therefore, this is not necessary; however, you may want to test the provided login credentials.
try:
    qbt_client.auth_log_in()
except qbittorrentapi.LoginFailed as e:
    print(e)

# display qBittorrent info
print(f'qBittorrent: {qbt_client.app.version}')
print(f'qBittorrent Web API: {qbt_client.app.web_api_version}')
for k,v in qbt_client.app.build_info.items(): print(f'{k}: {v}')

# retrieve and show all torrents
for torrent in qbt_client.torrents_info():
    print(f'{torrent.hash[-6:]}: {torrent.name} ({torrent.state})')

gives me a

/home/seluj78/Pytorr/.venv/lib/python3.8/site-packages/urllib3/connectionpool.py:1013: InsecureRequestWarning: Unverified HTTPS request is being made to host 'qbittorrent.seluj78.fr'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
  warnings.warn(
Traceback (most recent call last):
  File "/home/seluj78/Pytorr/test_qbittorrent_api.py", line 9, in <module>
    qbt_client.auth_log_in()
  File "/home/seluj78/Pytorr/.venv/lib/python3.8/site-packages/qbittorrentapi/auth.py", line 92, in auth_log_in
    self._post(
  File "/home/seluj78/Pytorr/.venv/lib/python3.8/site-packages/qbittorrentapi/request.py", line 212, in _post
    return self._request_manager(
  File "/home/seluj78/Pytorr/.venv/lib/python3.8/site-packages/qbittorrentapi/request.py", line 258, in _request_manager
    return self._request(**kwargs)
  File "/home/seluj78/Pytorr/.venv/lib/python3.8/site-packages/qbittorrentapi/request.py", line 290, in _request
    self.handle_error_responses(params=params, response=response)
  File "/home/seluj78/Pytorr/.venv/lib/python3.8/site-packages/qbittorrentapi/request.py", line 542, in handle_error_responses
    raise Unauthorized401Error(response.text)
qbittorrentapi.exceptions.Unauthorized401Error: Unauthorized

Process finished with exit code 1

while running

curl -v -d "username=USER&password=PASS" -X POST https://qbittorrent.DOMAIN.TLD/api/v2/auth/login

returns

Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 62.212.90.183:443...
* TCP_NODELAY set
* Connected to qbittorrent.DOMAIN.TLD (62.212.90.183) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=qbittorrent.DOMAIN.TLD
*  start date: Oct 27 04:40:42 2021 GMT
*  expire date: Jan 25 04:40:41 2022 GMT
*  subjectAltName: host "qbittorrent.DOMAIN.TLD" matched cert's "qbittorrent.DOMAIN.TLD"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x5609d5161e10)
> POST /api/v2/auth/login HTTP/2
> Host: qbittorrent.DOMAIN.TLD
> user-agent: curl/7.68.0
> accept: */*
> content-length: 38
> content-type: application/x-www-form-urlencoded
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
* We are completely uploaded and fine
< HTTP/2 200 
< content-security-policy: default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; object-src 'none'; form-action 'self'; frame-ancestors 'self';
< content-type: text/plain; charset=UTF-8
< date: Wed, 03 Nov 2021 15:57:29 GMT
< referrer-policy: same-origin
< set-cookie: SID=XXXX; HttpOnly; path=/; SameSite=Strict
< x-content-type-options: nosniff
< x-frame-options: SAMEORIGIN
< x-xss-protection: 1; mode=block
< content-length: 3
< 
* Connection #0 to host qbittorrent.DOMAIN.TLD left intact

Any clue ?

Specify the use of http, but the client has been trying to connect using https

qbt_client = qbittorrentapi.Client(host='http://127.0.0.1:6600/qb/', username='admin', password='adminadmin')

The error message is as follows:
Failed to connect to qBittorrent. Connection Error: ConnectionError(MaxRetryError("HTTPSConnectionPool(host='127.0.0.1', port=6600): Max retries exceeded with url: /qb/api/v2/auth/login (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f0a38170040>: Failed to establish a new connection: [Errno 111] Connection refused'))"))

I found that the error is caused by here:
qbittorrent-api/qbittorrentapi/request.py
369: r = requests_head(base_url.geturl(), allow_redirects=True, verify=False)

My listening address 127.0.0.1:6600 is transferred through a proxy called gost,
Proxy to my intranet address 192.168.1.100:8888.
When allow_redirects=True, it will cause the following error message:
HTTPConnectionPool(host='127.0.0.1', port=8888): Max retries exceeded with url: /qb/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f0ca86fa8b0>: Failed to establish a new connection: [Errno 111] Connection refused'))

Because the port is redirected from 6600 to 8888, and the host address remains at 127.0.0.1, the execution of requests.head fails
Then the scheme was redefined as alt_scheme='https'

Incorrect URL created when qBittorrent is behind a reverse proxy causing 404 error

I have my qBittorrent instance on a docker network along with a reverse proxy and the Web UI is available at http://[HOST]/qBittorrent/. The API is available and works correctly, when using curl or my browser. qbittorrent-api seems to ignore the base url and so I've been getting 404s when trying to use the API. Here is the example code:

qbt_client = qbittorrentapi.Client(host='http://[HOST]/qBittorrent/', username='[USERNAME]', password='[PASSWORD]')

`torrents_info` argument `tag` does not filter by tag

Running a script on Python 3.8.10, Ubuntu 20.04.5 LTS, and latest qbittorrent-api package. When using the torrents_info method and supplying an argument for tag, the JSON returned contains all the torrents. The results are not filtered by the tag in the argument.

import qbittorrentapi
import json

qbt_client = qbittorrentapi.Client(host=XXX, port=XXX, username=XXX, password=XXX, REQUESTS_ARGS={"auth": ("XXX", "XXX")})
qbt_client.auth_log_in()

torrentinfoJSON = qbt_client.torrents_info(tag="MyTag")

for torrentinfo in torrentinfoJSON:
    sum=sum + torrentinfo.ratio
    x=x+1

if x > 0:    
    avg = sum/x

print(str(x) + "torrents in MyTag = " + str(avg))
qbt_client.auth_log_out()

Client connect block forever

Hello, I use this lib to connect a qbt client but its network is unstable, and the client block forever,.
Could I add timeout in the requests?
Thank you.

`fileUrl` doesn't return a torrent or magnet link

Hi all,

From the qbittorrent API , the fileUrl attribute from the search result should return a torrent or magnet link.

( running for example: `qbt_client.search.results(12345)['results'][0]['fileUrl'])

After a few tries, the values I got from fileUrl was always the same as the descrLink attribute.

Is this normal behavior?

`torrents_export` returns None

  • qBittorrent version: 4.3.9
  • Web API version: 2.8.2

Calling method torrents_export(hash) does not return bytes of the .torrent file, but only None.

What's odd for me is that I cannot find the corresponding web api in official wiki. Does it mean this method is deprecated?

Client method to get statistics

Hey !

I've searched the docs and didn't find a route to get statistics for the client.

For example, current down and up speed, total downloaded, uploaded etc... So I can put those in a chart :) Is this something that you plan on adding ? Or am I blind 🤣

Python 3.8 Not Working - qBittorrent Host URL Determination Fails

Something changed in Python 3.8. When it attempts to connect to qBittorrent, the address is malformed. For instance, if the host address is localhost:8080, then the connection attempt us being made to http://8080 instead of http://localhost:8080.

The underlying issue most likely stems from a change in urllib.parse.urlparse.

>>> qbt_client.auth_log_in()
[2020-01-01 12:40:48,759] {qbittorrentapi.request:54} DEBUG - Detecting scheme for URL...
# /usr/local/lib/python3.8/__pycache__/netrc.cpython-38.pyc matches /usr/local/lib/python3.8/netrc.py
# code object from '/usr/local/lib/python3.8/__pycache__/netrc.cpython-38.pyc'
# /usr/local/lib/python3.8/__pycache__/shlex.cpython-38.pyc matches /usr/local/lib/python3.8/shlex.py
# code object from '/usr/local/lib/python3.8/__pycache__/shlex.cpython-38.pyc'
import 'shlex' # <_frozen_importlib_external.SourceFileLoader object at 0x7f8a985f1610>
import 'netrc' # <_frozen_importlib_external.SourceFileLoader object at 0x7f8a985f1340>
[2020-01-01 12:40:48,767] {urllib3.connectionpool:221} DEBUG - Starting new HTTP connection (1): 8080:80
[2020-01-01 12:42:59,442] {qbittorrentapi.request:70} DEBUG - Using HTTPS scheme
[2020-01-01 12:42:59,442] {qbittorrentapi.request:74} DEBUG - Base URL: https://8080
[2020-01-01 12:42:59,452] {urllib3.connectionpool:955} DEBUG - Starting new HTTPS connection (1): 8080:443
[2020-01-01 12:45:10,513] {qbittorrentapi.request:116} DEBUG - Connection error. Retrying.
[2020-01-01 12:45:10,514] {qbittorrentapi.request:54} DEBUG - Detecting scheme for URL...
[2020-01-01 12:45:10,516] {urllib3.connectionpool:221} DEBUG - Starting new HTTP connection (1): 8080:80
[2020-01-01 12:47:21,585] {qbittorrentapi.request:70} DEBUG - Using HTTPS scheme
[2020-01-01 12:47:21,586] {qbittorrentapi.request:74} DEBUG - Base URL: https://8080
[2020-01-01 12:47:21,590] {urllib3.connectionpool:955} DEBUG - Starting new HTTPS connection (1): 8080:443
[2020-01-01 12:49:32,663] {qbittorrentapi.request:112} DEBUG - Failed to connect to qBittorrent. Connection Er
ror: ConnectionError(MaxRetryError("HTTPSConnectionPool(host='8080', port=443): Max retries exceeded with url:
 /api/v2/auth/login (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f8
a98598ac0>: Failed to establish a new connection: [Errno 110] Connection timed out'))"))

Impossible to rename torrent with spaces

When using torrents_rename("Hello World") torrent will get name "Hello+World", but web interface allows to rename torrent correctly. Could you fix it please?
Using qbittorrent-api version 2021.5.22

The Setting of Content-Length Header to 0 is Probably Not Always Right

Improve the accuracy of setting Content-Length header to 0......this probably isn't actually a problem since Requests will update Content-Length for us if necessary......and it only exists because qBittorrent spams its logs otherwise.

# send Content-Length as 0 for empty POSTs...Requests will not send Content-Length
# if data is empty but qBittorrent may complain otherwise
if http_method == "post" and not any(filter(None, data.values())):
    headers["Content-Length"] = "0"

One problem is filter(None, (...)) will return nothing if simply all the values evaluate to False as a bool.
Second, data can be updated after this point....

torrents_set_location fails with qbittorrentapi.exceptions.MissingRequiredParameters400Error

Hi,
I'm using the library to move some torrents and noticed this method seems to be failing.

client.torrents_set_location(hash=t['hash'], location=os.path.dirname(new_path))

I've validated that t['hash'] and os.path.dirname(new_path) are both valid and they are:

logger.info(f"Moving torrent({t['hash']}))
Moving torrent(0daeeee48df26cfb066e55b970ca57741e7e400e)

I was able to get around this issue by using the method within the torrent object.

t.set_location(location=os.path.dirname(new_path))

Here's the full error:

  File "/some/path/main.py", line 101, in move_torrent
    client.torrents_set_location(hash=t['hash'], location=os.path.dirname(new_path))
  File "/some/path-tec6xMoE/lib/python3.9/site-packages/qbittorrentapi/decorators.py", line 112, in wrapper
    return func(client, *args, **kwargs)
  File "/some/path-tec6xMoE/lib/python3.9/site-packages/qbittorrentapi/decorators.py", line 84, in wrapper
    return func(client, *args, **kwargs)
  File "/some/path-tec6xMoE/lib/python3.9/site-packages/qbittorrentapi/torrents.py", line 1895, in torrents_set_location
    self._post(_name=APINames.Torrents, _method="setLocation", data=data, **kwargs)
  File "/some/path-tec6xMoE/lib/python3.9/site-packages/qbittorrentapi/request.py", line 183, in _post
    return self._request_manager(
  File "/some/path-tec6xMoE/lib/python3.9/site-packages/qbittorrentapi/request.py", line 231, in _request_manager
    return self._request(**kwargs)
  File "/some/path-tec6xMoE/lib/python3.9/site-packages/qbittorrentapi/request.py", line 264, in _request
    self._handle_error_responses(api_args, response)
  File "/some/path-tec6xMoE/lib/python3.9/site-packages/qbittorrentapi/request.py", line 596, in _handle_error_responses
    raise MissingRequiredParameters400Error()
qbittorrentapi.exceptions.MissingRequiredParameters400Error

Thanks for your awesome work

make the "IS PRIVATE" flag usable please

What is the problem or limitation you are having?

Hello!

In qBittorrent v4.5.1's changelog there is a line that says:
WEBUI: Expose "IS PRIVATE" flag

Is this available in this qbittorrent-api?

If not, please implement it.

I'm not a programmer so I can't check myself if it's usable already, sorry.

Thank you!

Describe the solution you'd like

Have a way to differentiate torrents that are private as in have trackers only for private trackers, no DHT, PEX, LSD.

Describe alternatives you've considered

Checking torrents by hand or trying to filter for tracker.

Additional context

No response

Qbittorrent-nox

Hi, hope everything is well

It's not a bug in your package.

But i don't know what to report for qbitorrent team, maybe if you can understand what the issue so you or me can open issue.

magnet:?xt=urn:btih:ZRV5MMSDGGHSVTFPCQEOWK5MMSD3WT6E&dn=Cavaleiro%20da%20Lua%20S01E06%20WEB-DL%201080p%20DUAL%205.1&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce

With v.4.3.9 this magnet link works normally, the hash will converted to base16. I use this:

hash_ = b16encode(b32decode(str(hash_))).decode()

In the latest version 4.4.3.1 it's not working and i can't pause it. I'm using also tag so I'm trying to get info from tag also nothing.

I add this magnet locally on my phone and have have generated torrent file and it worked on latest version but with different hash.

So if you can understand the issue then I can report to qbittorrent team and thanks in advance.

Version Checking Requires Too Much Cognitive Overhead To Read

Since a lot of things change in the qBittorrent Web API, there is a lot of qBittorrent version comparisons to see which features are available.

Like this:

if (
    content_layout is None
    and is_root_folder is not None
    and self._is_version_less_than("2.7", api_version, lteq=True)
):
    content_layout = "Original" if is_root_folder else "NoSubfolder"
    is_root_folder = None

Every time I read this, I have to really think about what's happening......create wrappers to make this more intuitive.

[Feature Request]: Get supported version

Thank you for building and maintaining this API!

With the new release of v4.4 breaking the web API, would it be possible to add to this a supported version variable somewhere so I know what version of qbittorrent this currently supports? Right now the other alternative option is to look at the README page and filter out Currently supports up to qBittorrent v4.3.9 (Web API v2.8.2) released on Oct 31, 2021.

The "torrents" Endpoint Calls Are Slow for Many Torrents

OS:Ubuntu19.10
CPU:J3455
qbittorrent is in the localhost。

It takes about 20 seconds to connect to qb client
there are one 465 torrents and 8000 files totally。It takes more than one minute to print all the files。one of the torrents have 6000+ files,It will stop for a long time to get the files。

I changed another api(python-qbittorrent project),it runs very fast。but there are some methods it have not developed

tags does not seem to work

Shouldn't this work?

In [30]: qc.torrent_tags.tags

In [31]: qc.torrent_tags.create_tags(tags='atag')

In [32]: qc.torrent_tags.tags

In [33]: 

Unterminated string starting at

Im getting a strange error. Im currently using seedcross and get this error with your API. Im unsure of why.

here is the traceback.

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/qbittorrentapi/decorators.py", line 161, in wrapper
    result = response.json()
  File "/root/.local/lib/python3.8/site-packages/requests/models.py", line 910, in json
    return complexjson.loads(self.text, **kwargs)
  File "/usr/local/lib/python3.8/json/__init__.py", line 357, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.8/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/local/lib/python3.8/json/decoder.py", line 353, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 239700 (char 239699)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/root/.local/lib/python3.8/site-packages/background_task/tasks.py", line 43, in bg_runner
    func(*args, **kwargs)
  File "/root/seedcross/crseed/tasks.py", line 80, in backgroundCrossSeedTask
    iterTorrents(dlclient, param, log)
  File "/root/seedcross/crseed/CrossSeedAutoDL.py", line 356, in iterTorrents
    torList = dlclient.loadTorrents()
  File "/root/seedcross/crseed/torclient.py", line 196, in loadTorrents
    torList = self.qbClient.torrents_info()
  File "/usr/local/lib/python3.8/site-packages/qbittorrentapi/decorators.py", line 112, in wrapper
    return func(client, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/qbittorrentapi/decorators.py", line 170, in wrapper
    raise APIError("Exception during response parsing. Error: %r" % exc)
qbittorrentapi.exceptions.APIError: Exception during response parsing. Error: JSONDecodeError('Unterminated string starting at: line 1 column 239700 (char 239699)')

Any idea what the cause could be?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.