PHP code example of unkybadtouch / qbbittorrent

1. Go to this page and download the library: Download unkybadtouch/qbbittorrent library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

unkybadtouch / qbbittorrent example snippets


use Blackout\Qbittorrent\Client;

$qb = new Client('http://localhost:8080', 'admin', 'adminadmin');

foreach ($qb->getTorrents(['filter' => 'downloading']) as $torrent) {
    echo "{$torrent->name}: {$torrent->progress_percent}%\n";
}

use Blackout\Qbittorrent\Client;

$qb = new Client($baseUri, $username, $password);

$torrent = $qb->getTorrents(['hashes' => $hash])[0];
foreach ($torrent->files as $file) { ... } // fires getTorrentFiles() here
foreach ($torrent->files as $file) { ... } // cached, no second request

use Blackout\Qbittorrent\Client;
use Blackout\Qbittorrent\Enum\TorrentState;

$qb = new Client('http://localhost:8080', 'admin', 'adminadmin');

$qb->addTorrentUrls($magnetUri, [
    'category' => 'linux',
    'paused'   => 'false',
    // never pass 'savepath' here (PROJECT.md gotcha — qBittorrent mishandles it
    // on /torrents/add); set the save path after the add instead:
    // $torrent->setSavePath('/data/downloads/linux')
]);

// addTorrentUrls()/addTorrentFile() don't return the new Torrent — the API
// doesn't echo it back — so fetch it once you know the hash (magnet URIs
// carry it in the `xt=urn:btih:...` param; for .torrent files, hash it
// yourself or grep the newest entry in the category)
$hash = strtolower(preg_match('/btih:([a-f0-9]{40})/i', $magnetUri, $m) ? $m[1] : '');

do {
    $torrent = $qb->getTorrents(['hashes' => $hash])[0] ?? null;
    usleep(500_000);
} while ($torrent === null || $torrent->state === TorrentState::META_DL);

while (!$torrent->is_complete) {
    sleep(2);
    $torrent = $qb->getTorrents(['hashes' => $hash])[0];
}

echo "{$torrent->name} finished ({$torrent->size_human})\n";

foreach ($torrent->files as $file) { // fires getTorrentFiles($hash) here, once
    echo "  {$file->basename} ({$file->size_human})\n";
}

$torrent = $qb->getTorrents(['hashes' => $hash])[0];

// Nothing below has fired a request yet — files/trackers/peers/pieces/webseeds
// are declared as hooked `get` properties (Torrent.php), not hydrated fields.

foreach ($torrent->files as $file) {          // -> Client::getTorrentFiles($hash)
    printf("  [%d] %-40s %6.2f%% prio=%s\n",
        $file->index, $file->basename, $file->progress_percent, $file->priority->label());
}

foreach ($torrent->trackers as $tracker) {    // -> Client::getTorrentTrackers($hash)
    printf("  %-50s %s (%s)\n", $tracker->url, $tracker->status->label(), $tracker->msg);
}

foreach ($torrent->peers as $peer) {          // -> Client::getTorrentPeers($hash)
    printf("  %-15s:%-5d %-20s %5.1f%%\n", $peer->ip, $peer->port, $peer->client, $peer->progress * 100);
}

$piecesHave = count(array_filter($torrent->pieces, fn ($p) => $p->is_downloaded)); // -> Client::getTorrentPiecesStates($hash)
echo "{$piecesHave}/{$torrent->pieces_num} pieces\n";

foreach ($torrent->webseeds as $seed) {       // -> Client::getTorrentWebSeeds($hash)
    echo "  {$seed->url}\n";
}

// Second access to any of these is free — cached in $torrent->_relations
$torrent->files; // no request

// Mutating through a relation invalidates its own cache so the next read refetches:
$torrent->addTrackers('udp://new-tracker.example.com:80');
$torrent->trackers; // -> Client::getTorrentTrackers($hash) again, 

$toGrab = array_sum(array_map(fn ($f) => $f->size, $torrent->downloadable_files));
echo "Will download " . \Blackout\Helper::filesize($toGrab) . "\n";

use Blackout\Qbittorrent\DTO\Rss\Feed;

function walkRssTree(array $node, string $indent = ''): void
{
    foreach ($node as $name => $item) {
        if ($item instanceof Feed) {
            // hasError/isLoading/title etc. are only initialized when fetched
            // with withData=true — accessing them otherwise throws (uninitialized
            // typed property), so guard with isInitialized-style try/catch or,
            // as here, only read them when you know withData was passed
            $status = $item->hasError ? 'ERROR' : 'ok';
            echo "{$indent}{$name}  [{$item->url}]  {$status}\n";
        } else {
            echo "{$indent}{$name}/\n";
            walkRssTree($item, $indent . '    '); // recurse into the folder
        }
    }
}

walkRssTree($qb->getRssFeeds(['withData' => true]));

// Direct access once you know the path:
$feed = $qb->getRssFeeds()['tech']['linux-distros'];
$feed->setRefreshInterval(1800);

use Blackout\Qbittorrent\Enum\SearchStatus;

$id = $qb->startSearch('debian netinst iso', plugins: 'all', category: 'all');

do {
    sleep(1);
    $status = $qb->getSearchStatus($id)[0]; // Search\Status
} while ($status->status === SearchStatus::RUNNING);

echo "{$status->total} results\n";

foreach ($status->results(limit: 25) as $result) { // Search\Result[], via Status::results()
    printf("%-60s %5d seeds  %s\n", $result->fileName, $result->nbSeeders, $result->engineName);

    if ($result->nbSeeders > 10 && str_contains($result->fileName, 'netinst')) {
        $result->download(); // -> Client::downloadSearchTorrent()
    }
}

$status->delete(); // after this, don't call getSearchStatus($id) again — the id 404s

$rule = $qb->getRssRules()['tv-releases'];

var_dump($rule->torrentParams);
// ['category' => 'tv', 'save_path' => '/data/tv', 'content_layout' => 'Original', ...]

$rule->assignedCategory = 'anime';        // also sets $rule->torrentParams['category'] = 'anime'
$rule->torrentParams['save_path'] = '/data/anime'; // or write the nested array directly — same effect

$rule->save(); // POSTs jsonSerialize() (minus the synthesized `name`) to setRule

$qb->createCategory('archived', savePath: '/data/archive');

foreach ($qb->getTorrentsByCategory('linux') as $torrent) {
    if ($torrent->is_complete && $torrent->ratio >= 2.0) {
        $torrent->setCategory('archived');   // Client::setTorrentCategory + local field update
        $torrent->setSavePath('/data/archive');
    }
}

$categories = $qb->getCategories();          // string-keyed array of Category
echo $categories['archived']->savePath;      // "/data/archive"
$categories['archived']->edit(savePath: '/data/archive/linux'); // moves + updates local field

$torrent = $qb->getTorrents(['hashes' => $hash])[0];

echo json_encode($torrent, JSON_PRETTY_PRINT);
// { "hash": "...", "name": "...", ... }  <- no "files"/"trackers"/etc. keys yet

$torrent->files; // triggers the fetch

echo json_encode($torrent, JSON_PRETTY_PRINT);
// { "hash": "...", ..., "files": [ { "index": 0, "name": "...", ... }, ... ] }
// nested Torrent\File DTOs serialize themselves too — jsonSerialize() recurses naturally

$lastId = -1;
$allMessages = [];

do {
    $batch = $qb->getLog(['last_known_id' => $lastId]); // Log\Message[]
    $allMessages = [...$allMessages, ...$batch];
    $lastId = end($batch)?->id ?? $lastId;
} while (count($batch) > 0 && count($allMessages) < 5000);

try {
    $qb->addTorrentUrls($url);
} catch (\Exception $e) {
    // message is either the raw text/JSON body qBittorrent returned,
    // or an extracted error/message/reason field — see describeAddTorrentFailure()
    error_log("Add failed: {$e->getMessage()}");
}

try {
    $qb = (new Client($baseUri, $username, $wrongPassword))->login($username, $wrongPassword);
} catch (\Exception $e) {
    // "Authentication failed: ... (403)"
}

$torrent = $qb->getTorrents(['hashes' => $hash])[0];

$torrent->addTags(['linux-iso', 'archive']);      // Client::addTorrentTags + local update
$torrent->removeTags('archive');
$torrent->setCategory('linux');
$torrent->setSavePath('/data/downloads/linux');
$torrent->setDownloadPath('/data/incomplete/linux');
$torrent->setComment('verified checksum');
$torrent->setTags(['a', 'b']);                    // replaces, not merges

$torrent->stop();
$torrent->start();
$torrent->recheck();
$torrent->reannounce();
$torrent->delete(deleteFiles: true);

$torrent->setDownloadLimit(500_000);              // bytes/sec, local field updates immediately
$torrent->setUploadLimit(100_000);
$torrent->setShareLimits(ratioLimit: 2.0, seedingTimeLimit: 1440, inactiveSeedingTimeLimit: -1);

$torrent->increasePrio();
$torrent->topPrio();
$torrent->setFilePrio([0, 1], priority: 7);        // FilePriority::MAXIMUM

$torrent->setLocation('/mnt/nas/downloads');
$torrent->rename('New Name');
$torrent->renameFile('old/path.mkv', 'new/path.mkv');
$torrent->renameFolder('old-dir', 'new-dir');

$torrent->setAutoManagement(true);
$torrent->toggleSequentialDownload();
$torrent->toggleFirstLastPiecePrio();
$torrent->setForceStart(true);
$torrent->setSuperSeeding(true);

$torrent->addTrackers(['udp://tracker.example.com:80']);
$torrent->editTracker('udp://old', 'udp://new');
$torrent->removeTrackers('udp://dead-tracker.example.com:80');
$torrent->addPeers(['1.2.3.4:6881']);
$torrent->addWebSeeds('https://example.com/webseed/');

$bytes = $torrent->downloadFile($torrent->files[0]); // raw file bytes
$torrentFileBytes = $torrent->export();               // the .torrent itself

$props = $qb->getTorrentProperties($hash);
echo "{$props->seeds}/{$props->seeds_total} seeds, avg dl {$props->dl_speed_avg} B/s";

foreach ($torrent->files as $file) {
    if ($file->priority->isDoNotDownload()) continue;
    echo "{$file->basename}: {$file->progress_percent}%\n";
}

$bytes = $qb->downloadFile($hash, $torrent->files[2]); // or pass the index directly

foreach ($torrent->trackers as $tracker) {
    if (!$tracker->status->isHealthy()) {
        echo "{$tracker->url}: {$tracker->msg}\n";
    }
}

foreach ($torrent->peers as $peer) {
    echo "{$peer->ip}:{$peer->port} ({$peer->client}) {$peer->progress}\n";
}

$have = array_filter($torrent->pieces, fn ($p) => $p->is_downloaded);

$categories = $qb->getCategories();
$categories['linux']->edit(savePath: '/data/linux');
$categories['old-stuff']->delete();

$qb->setCookies([
    new Cookie(['name' => 'session', 'value' => 'abc', 'domain' => 'example.com', 'path' => '/', 'expirationDate' => '+30 days']),
]);

// or import from a browser export / Netscape cookie file:
$qb->importBrowserCookies('/home/me/.mozilla/.../cookies.sqlite', domains: 'example.com');
$qb->importCurlCookies(file_get_contents('cookies.txt'), domains: ['example.com']);
$qb->clearCookies(); // empties the store

$info = $qb->getBuildInfo();
echo "libtorrent {$info->libtorrent} on {$info->platform}";

$t = $qb->getTransferInfo();

$t->speedLimitsMode();        // bool — alt speed limits active?
$t->toggleSpeedLimitsMode();
$t->setDownloadLimit(1_000_000);  // global, bytes/sec — distinct from per-torrent limits
$t->setUploadLimit(500_000);
$t->banPeers(['1.2.3.4:6881', '5.6.7.8:6882']);

foreach ($status->results() as $result) {
    if ($result->nbSeeders > 5) $result->download(); // downloadSearchTorrent()
}

$id = $qb->startSearch('debian iso', plugins: 'all', category: 'all');
$status = $qb->getSearchStatus($id)[0];

$status->results(limit: 20);
$status->stop();
$status->delete();

foreach ($qb->getSearchPlugins() as $plugin) {
    if (!$plugin->enabled) $plugin->enable();
}
$qb->getSearchPlugins()['legittorrents']->uninstall();
$qb->installSearchPlugin('https://example.com/my-plugin.py');
$qb->updateSearchPlugins();

$feeds = $qb->getRssFeeds(['withData' => true]);
$linux = $feeds['tech']['linux-distros']; // nested by folder

$linux->setUrl('https://example.com/new-feed.xml');
$linux->setRefreshInterval(1800);
$linux->refresh();
$linux->markAsRead();
$linux->move('archive/linux-distros');
$linux->remove();

$qb->addRssFolder('tech');
$qb->addRssFeed('https://example.com/feed.xml', 'tech/new-feed');

$rules = $qb->getRssRules();
$rule = $rules['new-releases'];

$rule->mustContain = '1080p|2160p';
$rule->assignedCategory = 'tv';       // also sets torrentParams['category']
$rule->save();                         // POSTs the whole object

$rule->rename('tv-releases');
$rule->clone('tv-releases-copy');      // undocumented endpoint, not live until qBittorrent ships it past 5.2.2
$rule->matchingArticles();
$rule->delete();

$qb->addRssRule('new-rule', [
    'enabled' => true,
    'mustContain' => 'S\d{2}E\d{2}',
    'affectedFeeds' => ['tech\\linux-distros'],
    'torrentParams' => ['category' => 'tv', 'save_path' => '/data/tv'],
]);

$prefs = $qb->getPreferences();
echo $prefs->web_ui_port;

$qb->setPreferences([
    'dl_limit' => 5_000_000,
    'max_ratio' => 2.0,
    'max_ratio_enabled' => true,
]);