PHPackages                             marque/bloodhound - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. marque/bloodhound

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

marque/bloodhound
=================

BitTorrent tracker (announce/scrape) for Marque platform

v2.0.0(3mo ago)04MITPHPPHP ^8.2

Since Feb 11Pushed 3mo agoCompare

[ Source](https://github.com/letterofmarque/bloodhound)[ Packagist](https://packagist.org/packages/marque/bloodhound)[ RSS](/packages/marque-bloodhound/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (9)Versions (2)Used By (0)

Marque Bloodhound
=================

[](#marque-bloodhound)

BitTorrent tracker for the [Marque](https://github.com/letterofmarque/marque) platform. Handles announce/scrape with Redis-backed peer storage, client validation, and anti-cheat detection.

Installation
------------

[](#installation)

Requires [marque/trove](https://packagist.org/packages/marque/trove).

```
composer require marque/bloodhound
```

Publish the config and run migrations:

```
php artisan vendor:publish --tag=bloodhound-config
php artisan migrate
```

How It Works
------------

[](#how-it-works)

Bloodhound registers two endpoints:

EndpointPurpose`GET /announce/{passkey}`Peer announces (start, stop, complete)`GET /scrape/{passkey?}`Swarm statisticsUsers authenticate via their passkey (auto-generated by Trove's `HasTrackerStats` trait). Peer data is stored in Redis for performance - no database queries on the announce hot path.

### Announce Flow

[](#announce-flow)

1. Passkey validated, user looked up
2. Torrent identified by info\_hash
3. Anti-cheat checks run
4. Client validated against whitelist
5. Peer upserted in Redis, stats calculated
6. Upload/download deltas queued for database update
7. Bencoded peer list returned to client

### Peer Storage

[](#peer-storage)

All peer data lives in Redis with configurable key prefix. Peers auto-expire after the configured TTL (default: 1 hour). Seeder/leecher counts are maintained as atomic counters.

Configuration
-------------

[](#configuration)

Published to `config/bloodhound.php`:

### Timing

[](#timing)

KeyDefaultDescription`announce_interval``1800`Seconds between announces (sent to clients)`min_announce_interval``300`Minimum allowed interval`peer_expiry``3600`Seconds before inactive peers are removed### Redis

[](#redis)

KeyDefaultDescription`redis.connection``default`Laravel Redis connection name`redis.prefix``bloodhound:`Key namespace### Peer Response

[](#peer-response)

KeyDefaultDescription`max_peers_per_announce``50`Max peers returned per announce`peer_response_format``auto``auto`, `compact`, or `dictionary`### Client Validation

[](#client-validation)

Bloodhound validates BitTorrent clients by peer ID. Default mode is `whitelist` with 17 pre-configured clients including qBittorrent, Deluge, Transmission, rTorrent, libtorrent, Vuze, and others.

KeyDefaultDescription`client_validation.enabled``true`Enable client checks`client_validation.mode``whitelist``whitelist` or `blacklist``client_validation.whitelist`*(see config)*Allowed clients with version ranges`client_validation.blacklist`*(see config)*Blocked clients (Xunlei, etc.)Each whitelist entry specifies a peer ID pattern, version format, and allowed version range. You can add custom clients or adjust version requirements.

### Anti-Cheat

[](#anti-cheat)

KeyDefaultDescription`anti_cheat.enabled``true`Master switch`anti_cheat.max_upload_speed``104857600`100 MB/s cap`anti_cheat.max_download_speed``104857600`100 MB/s cap`anti_cheat.min_announce_gap``60`Min seconds between announces`anti_cheat.max_connections_per_torrent``3`Per user, per torrent`anti_cheat.max_connections_per_ip``10`Per IP addressAnti-cheat runs these checks on every announce:

1. **Port blacklist** - Blocks known P2P/ISP-blocked ports
2. **Announce frequency** - Prevents tracker hammering
3. **Connection limits** - Per user and per IP
4. **Speed checks** - Flags impossibly fast transfers
5. **Data consistency** - Validates reported download vs torrent size
6. **Swarm consistency** - Samples 5% of announces for coordinated inflation

Violations fire a `CheatDetected` event and are logged to Redis for admin review.

### Stats Queue

[](#stats-queue)

KeyDefaultDescription`queue.enabled``true`Queue user stat updates`queue.connection``null`Queue connection (null = default)`queue.queue``tracker`Queue nameUpload/download deltas are dispatched as queued jobs to avoid database writes on the announce path.

### Port Blacklist

[](#port-blacklist)

Default blocked ports include Direct Connect (411-413), Kazaa (1214), eMule (4662), Gnutella (6346-6347), and legacy BitTorrent defaults (6881-6889).

Events
------

[](#events)

EventFired WhenProperties`TorrentCompleted`Peer finishes downloaduserId, torrentId, ip, userAgent`CheatDetected`Anti-cheat violationtype, userId, torrentId, reason`TorrentCompleted` automatically records a snatch (completion record) via the built-in listener.

Listen to these in your app for custom behaviour:

```
use Marque\Bloodhound\Events\CheatDetected;

Event::listen(CheatDetected::class, function ($event) {
    // Ban user, notify admin, etc.
});
```

Middleware
----------

[](#middleware)

Bloodhound applies `BlockBrowsers` middleware to tracker endpoints. This rejects requests from web browsers (detected by cookies, Accept-Language headers, and user agent strings) - only BitTorrent clients should hit these endpoints.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 12+
- Redis
- [marque/trove](https://packagist.org/packages/marque/trove)

License
-------

[](#license)

MIT

###  Health Score

36

—

LowBetter than 82% of packages

Maintenance82

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

93d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/074f3e81cde0a435c57bded42781ae326daa5493d02de1b45e710b82856abd5a?d=identicon)[lomsoftware](/maintainers/lomsoftware)

---

Top Contributors

[![lomsoftware](https://avatars.githubusercontent.com/u/257575579?v=4)](https://github.com/lomsoftware "lomsoftware (3 commits)")

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/marque-bloodhound/health.svg)

```
[![Health](https://phpackages.com/badges/marque-bloodhound/health.svg)](https://phpackages.com/packages/marque-bloodhound)
```

###  Alternatives

[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[psalm/plugin-laravel

Psalm plugin for Laravel

3274.9M308](/packages/psalm-plugin-laravel)[watson/active

Laravel helper for recognising the current route, controller and action

3253.6M14](/packages/watson-active)[illuminate/broadcasting

The Illuminate Broadcasting package.

7126.5M178](/packages/illuminate-broadcasting)[laragear/preload

Effortlessly make a Preload script for your Laravel application.

119363.5k](/packages/laragear-preload)[flarum/core

Delightfully simple forum software.

211.3M1.9k](/packages/flarum-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
