Usage

This guide explains how to use aiobtclientapi.

Basics

First, you need to create an instance of one of the APIBase subclasses.

api_dg = aiobtclientapi.DelugeAPI("AzureDiamond:hunter2@localhost:1234")
api_qb = aiobtclientapi.QbittorrentAPI("AzureDiamond:hunter2@localhost:1234")
api_rt = aiobtclientapi.RtorrentAPI("path/to/rpc.socket")
api_tm = aiobtclientapi.TransmissionAPI("AzureDiamond:hunter2@localhost:1234")

You can also pick a subclass by client name. client_names() returns a sorted sequence of valid client names.

client_name = "rtorrent"
url = "path/to/rpc.socket"
api = aiobtclientapi.api(client_name, url)

API URLs

Most clients accept URLs like [USERNAME:PASSWORD@]HOST[:PORT].

Below are the exact URL formats for each client. Uppercase words are placeholders and square brackets ([]) mark optional parts.

Deluge
[USERNAME:PASSWORD@]HOST[:PORT]
qBittorrent
[http[s]://][USERNAME:PASSWORD@]HOST[:PORT]
rTorrent
[scgi://]HOST[:PORT]
[file://]SOCKET_PATH
http[s]://[USERNAME:PASSWORD@]HOST[:PORT][/PATH]
Transmission
[http[s]://][USERNAME:PASSWORD@]HOST[:PORT][/PATH]

API Methods

Methods that can operate on multiple torrents always return Response instances and don’t raise exceptions. This is because the first operation might fail, but the remaining operations might still succeed. You also don’t want to ignore the failed operation.

A Response provides both return values and Errors as attributes. It can also provide Warnings about non-fatal operations that didn’t happen as planned. For example, you will get warned when you try to add a torrent that was already added.

Return values are provided as one or more custom attributes that are documented by the API method.

See the Example Code below.

RPC Calls

You can call() arbtitrary RPC methods if there is no common API method.

See the aiobtclientrpc documentation for details.

api = aiobtclientapi.TransmissionAPI("AzureDiamond:hunter2@localhost:1234")
info = await api.call("session-get")
info['arguments']['version']
>>> 3.21 (d34db33f)

Virtual Environment

There is a Makefile with a venv target that should set up everything you need. You can undo this by simply deleting the venv directory.

$ make venv
$ source venv/bin/activate

Command Line Tool

aiobtclientapi comes with a very simple CLI command, btclient, that allows you to call API methods and inspect the response. It is intended for manual testing, not for productive use, but you may find it useful to start your own project.

Example Usage

$ btclient qbittorrent 'AzureDiamond:hunter2@localhost' get_infohashes
>>> CALLING get_infohashes()
>>> Connection status changed: ConnectionStatus.connecting
>>> Connection status changed: ConnectionStatus.connected
>>> RESPONSE get_infohashes()
>>> * 8f6e8660855b91fc3facee3845d3dd9e8def32de
>>> * be7d32a5b47322efef9e9f42b1785c76bbefce7c
>>> Connection status changed: ConnectionStatus.disconnected
$ btclient qbittorrent 'AzureDiamond:hunter2@localhost' stop be7d32a5b47322efef9e9f42b1785c76bbefce7c
>>> CALLING stop('be7d32a5b47322efef9e9f42b1785c76bbefce7c')
>>> Connection status changed: ConnectionStatus.connecting
>>> Connection status changed: ConnectionStatus.connected
>>> RESPONSE stop('be7d32a5b47322efef9e9f42b1785c76bbefce7c')
>>>            SUCCESS: True
>>>           WARNINGS: []
>>>             ERRORS: []
>>>              TASKS: []
>>>            STOPPED: ['be7d32a5b47322efef9e9f42b1785c76bbefce7c']
>>>    ALREADY_STOPPED: []
>>> Connection status changed: ConnectionStatus.disconnected
$ btclient qbittorrent 'AzureDiamond:hunter2@localhost' call app/version
>>> CALLING call('app/version')
>>> Connection status changed: ConnectionStatus.connecting
>>> Connection status changed: ConnectionStatus.connected
>>> RESPONSE call('app/version')
>>> v4.4.3.1
>>> Connection status changed: ConnectionStatus.disconnected

Example Code

import asyncio
import aiobtclientapi

async def run():
    # Create API instance
    try:
        api = aiobtclientapi.api(
            name="qbittorrent",
            url="localhost:5000",
            username="AzureDiamond",
            password="hunter2",
        )
    except aiobtclientapi.ValueError as e:
        # Invalid client name or URL
        print('Error:', e)
        exit(1)

    # Add torrents
    response = await api.add(
        "path/to/my.first.torrent",
        "path/to/my.second.torrent",
        "path/to/my.third.torrent",
        stopped=True,
    )

    # success is only True if all of the torrents were added
    if not response.success:
        print("Something went wrong!")

    # Handle errors
    for error in response.errors:
        print("Error:", error)

    # Handle warnings
    for warning in response.warnings:
        print("Warning:", warning)

    # Show which torrents were actually added
    for infohash in response.added:
        print("Added:", infohash)

    # Get a list of existing torrents
    try:
        infohashes = await api.get_infohashes()
    except aiobtclientapi.ConnectionError as e:
        print("Unable to get infohashes:", e)
    else:
        print("Infohashes:")
        for infohash in infohashes:
            print(f" * {infohash}")

asyncio.run(run())