tryhackx / flarum-homepage-blocks
Customizable homepage blocks for tracker-style Flarum forums featuring dual statistics (internal & OpenTracker), advanced filters, and rate-limiting protection.
Package info
github.com/TryHackX/flarum-homepage-blocks
Type:flarum-extension
pkg:composer/tryhackx/flarum-homepage-blocks
Requires
- php: ^8.3
- flarum/core: ^2.0.2
- flarum/tags: ^2.0
Requires (Dev)
- flarum/testing: ^2.0
- tryhackx/flarum-topic-rating: ^2.5
Suggests
- fof/discussion-views: For view count stats
- tryhackx/flarum-magnet-link: For magnet link stats
- tryhackx/flarum-topic-rating: For rating-based filtering and sorting
Provides
None
Conflicts
None
Replaces
None
README
A Flarum extension that adds powerful customisable homepage blocks: tracker information panels, dual statistics (internal database + external OpenTracker), advanced discussion filters, content-validation overrides, and a per-IP rate limiter.
Designed to plug cleanly into a tracker-style Flarum forum. Works hand in hand with the rest of the TryHackX extension family —
tryhackx/flarum-topic-ratingunlocks rating filters and sorts,tryhackx/flarum-magnet-linkunlocks magnet click stats and sorts,fof/discussion-viewsunlocks view counters / view-based sort.
Note: Recent updates target the 2.x line only. The 1.x branch (Flarum 1.8+) is no longer actively developed — it stays available for legacy installs but won't receive new features.
Screenshots
Mobile view — discussion list rendered with different combinations of TryHackX extensions (thumbnails + ratings + views, thumbnails + views, thumbnails only, ratings only, views only, vanilla Flarum).
TryHackX Homepage Blocks admin panel — section toggles, theme mode, custom filter labels, tracker info / announce URLs, internal & external (OpenTracker) statistics, content title / length overrides and rate-limit settings.
Desktop discussion list with the full TryHackX stack — thumbnail sliders on the left, star ratings on the right, magnet button next to each topic.
Desktop discussion list — hover state showing the magnet tooltip loading inline (powered by tryhackx/flarum-magnet-link).
Support Development
If you find this extension useful, consider supporting its development:
- Monero (XMR):
45hvee4Jv7qeAm6SrBzXb9YVjb8DkHtFtFh7qkDMxS9zYX3NRi1dV27MtSdVC5X8T1YVoiG8XFiJkh4p9UncqWGxHi4tiwk - Bitcoin (BTC):
bc1qncavcek4kknpvykedxas8kxash9kdng990qed2 - Ethereum (ETH):
0xa3d38d5Cf202598dd782C611e9F43f342C967cF5
You can also find the donation option in the extension's admin settings panel.
Features
- Tracker info panel — display BitTorrent tracker announce URLs with copy-to-clipboard support, a custom heading and sub-heading.
- Dual statistics system — show internal forum stats (from the
database) and external OpenTracker stats side by side:
- Internal stats — torrents, users, magnets, downloads, views, average rating (pulled from the forum database).
- External stats (OpenTracker) — seeds, leechers, peers, completed
downloads, uptime, fetched directly from the OpenTracker XML endpoint
(
/stats?mode=everything). Leechers are derived aspeers − seeds(OpenTracker'speerscount is the whole swarm). - Shared cache + single-flight — the backend fetches the tracker at most once per cache lifetime, globally, and serves everyone from one shared cache; when a fetch is already running, other requests are never triggered and get the cached/stale value instead. Configurable cache lifetime, max fetch time (large trackers can take ~a minute to compute stats) and client refresh interval.
- Advanced discussion filters — filter bar for the discussion list
with 7 filter types:
- Title search
- User search
- Rating interval (requires
tryhackx/flarum-topic-rating) - Date interval (Today, 1 day, 1 week, 2 weeks, 1 month, 3 / 6 months, 1 year)
- Category (primary tag) and Resolution / add-on (secondary tag) selection with live counts: every option shows how many discussions the list returns if you pick it together with all the other active filters (title, user, intervals, the other tag list), recalculated on every change — so a number never promises results that aren't there.
- Sort by — creation date (always available), plus a Steam-DB-style
confidence rating, average rating, rating count and recently rated
(with
tryhackx/flarum-topic-rating), views (withfof/discussion-views), and magnet clicks total / top magnet / recently clicked (withtryhackx/flarum-magnet-link). Options whose extension isn't installed are hidden automatically. - Sort direction (ascending / descending)
- More filters (2.8.0, opt-in) — a collapsible panel at the bottom right of
the filter bar, plus extra sorts. Every filter is a separate admin switch
(all off by default — nothing changes until you turn them on):
- Type: movies / series — an All / Movies / Series switch next to the More filters button (or, per admin setting, a list in the main row or a field inside the panel); with live counts like the tag lists.
- Size from – to (MB / GB / TB), release year (a series or trilogy matches when its years overlap), running time, seasons, episodes, IMDb and Filmweb rating — read from each discussion's title and first post (see Metadata index below).
- Everything the list can be sorted by, as a range: Steam DB rating (%), average rating, number of ratings and last rated (topic-rating), views (discussion-views), replies, magnet clicks (all magnets / top magnet), last magnet click and with / without a magnet link (magnet-link), date started and last activity (dates in the visitor's own time zone).
- The panel groups its fields (Release, Ratings & popularity, Dates) and starts collapsed on every visit unless the admin makes it open by default.
- Extra sort options: size and release year (unknown values last).
- Live counts of the Category / Resolution / Type lists include these filters; an invalid range (from > to) is flagged and never sent; the panel's open / closed state is remembered per browser.
- Metadata index (for the size / type / year / … filters) — release data
is read once per discussion into an indexed table, so filtering stays a
plain index lookup even on big forums. Kept current automatically (new
discussion, first-post edit, rename, delete); rebuilt from the admin panel
(batched, resumable, with progress and a per-discussion preview of what the
parser reads) or with
php flarum homepage-blocks:reindex [--only-stale]. Everything the parser looks for is configurable: the field labels (Size:,Seasons:,Year:…, comma separated, matched literally), which size sources to use (magnetxl=exact length → aSize:line → a size in the title), binary or decimal units, and the series rules (a kind field such asSerial: TV Series, seasons / episodes values,S01E01markers). Posts are read as plain text, so BBCode, Markdown and literal markup all work. - Content-validation overrides — override Flarum's built-in title
and content length limits without patching core:
- Title length: 1–200 characters (
varchar(200)column max). - Content length: 0–16,000,000 characters (
mediumtextcolumn max). - Each toggle is independent.
- Title length: 1–200 characters (
- Rate limiting — a built-in per-IP points limiter on the search /
filters action. Each visitor has a budget that refills over time; when it
runs out the IP is temporarily blocked for a configurable duration and
the visitor sees a friendly countdown. Client IPs are resolved from Flarum
core (proxy-aware), so the limit can't be bypassed with a spoofed
X-Forwarded-Forheader. The per-IP budget is kept on the local filesystem with per-IP locking — ideal for a single server; if you run several app servers behind a load balancer, front them with a shared store (Redis).- Enforced server-side. The authoritative charge is a middleware on
core's
GET /api/discussionsthat meters requests carrying the heavyfilter[title]/filter[user](LIKE%…%) parameters — so bots, scrapers and flooders hitting the API directly are throttled and blocked before the query touches the database, not just users of the on-page filter bar. The client-side pre-flight is kept purely for UX (instant countdown before a query fires); to avoid double-billing, a successful pre-flight grants a short-lived per-IP grace that the middleware consumes for the follow-up real request. Only heavy searches are metered — a title/user filter of 3+ characters, or a More filters range no index can serve (Steam DB score, magnet clicks); ordinary browsing, short (<3-char) filters and light changes (a tag, the sort, an indexed range) are never charged, and the filter bar runs its pre-flight only for heavy searches. (A shared cache such as Redis is still recommended if you run several app servers, so the per-IP bucket is consistent across nodes.)
- Enforced server-side. The authoritative charge is a middleware on
core's
- Collapsible sections — Section 1 (tracker + stats) can be collapsed by default to save space.
- Hide hero banner — optional toggle to hide Flarum's default hero banner.
- Tag filtering — show only tags that actually have discussions under the current filters (the picked tag always stays listed), optionally with the live counts next to tag names.
- Light / dark mode — the blocks follow Flarum 2's colour scheme live (header theme switcher, user preference, OS setting, high-contrast modes), using the forum's own theme colours. The Theme mode setting can instead pin the forum's light or dark palette.
- Two styles — Fitted blends the blocks into the forum; Original is a card design (rounded cards, primary-tinted header with an accent bar, stat tiles with icon chips, pill-shaped tracker URLs). Both use the forum's colours and follow light / dark mode.
- Tracker whitelist sync (2.6.0) — when your OpenTracker runs in
whitelist mode (only registered info hashes are served — see
tryhackx-tracker ≥ 1.2.0),
every magnet link posted on the forum is registered on the tracker
automatically: new posts, edits and (with
flarum/approval) approvals are pushed live through the tracker's server-to-server API (bearer key), and a Scan whole forum button walks all visible posts in small batches (one request per batch, well inside the PHP time limit, resumable). Failures never block a post: short timeout + failure cooldown + one-line logging. The API secret is stored server-side only (never sent to the admin frontend) and saved through its own endpoint. - Polish & English locales — fully translated UI.
Requirements
- Flarum
^2.0.2 - PHP
^8.3(matches Flarum 2.x's own minimum);ext-curlfor the tracker statistics fetch and the whitelist sync flarum/tags(required)- For Tracker whitelist sync: tryhackx-tracker
≥ 1.2.0 with
tracker_mode = whitelist, an API client created in its admin panel (Whitelist → API clients) and the tracker's API ban exempt IPs list containing this forum's outbound IP (a wrong secret from a non-exempt IP is banned for 30 days by design).
Recommended companions
These aren't strictly required but unlock additional functionality:
- fof/discussion-views — view count statistics and view-based sorting.
- tryhackx/flarum-topic-rating — rating-based filtering and sorting (Steam-DB-style, average rating, etc.).
- tryhackx/flarum-magnet-link — magnet click statistics (tracker stats block) and topic-scoped magnet-click sorts (clicks total / top magnet / recently clicked).
Installation
composer require tryhackx/flarum-homepage-blocks php flarum cache:clear
Updating
composer update tryhackx/flarum-homepage-blocks php flarum migrate php flarum cache:clear
Using the More filters index-based filters? Build the index once after
enabling them (admin → Index → Rebuild index, or
php flarum homepage-blocks:reindex).
Configuration
- Navigate to the Administration panel.
- Find TryHackX Homepage Blocks in the extensions list and enable it.
- Click the extension to access the configuration sections:
| Section | Description |
|---|---|
| General | Section titles, default-collapsed state, hero banner toggle, tag display options, theme mode (auto / light / dark) and style (fitted / original). |
| Tracker Info | Tracker heading, sub-heading, announce URLs. |
| Tracker Statistics | Toggle internal stats, set the OpenTracker XML URL, cache lifetime, max fetch time and client refresh interval. |
| Content Settings | Override title and content length limits. |
| Rate limiting | Per-IP points limiter on search/filters. When a visitor runs out of points the IP is temporarily blocked (configurable duration and post-block budget reset). Guests pay an extra per-action cost. |
| Tracker whitelist sync | Enable toggle (reveals the settings), tracker URL, API key ID, API secret (own Save secret button — stored server-side only), live-sync timeout, optional bare-hash detection, Test connection and Scan whole forum with a progress bar (batched, resumable). |
| ↳ Only sync magnets that point at our tracker (2.6.1) | Off by default. When on, a hash is sent only if its magnet link has a tr= announce URL on one of the Tracker hosts (comma / newline separated hostnames or IPs, e.g. tracker.example.org, 203.0.113.10; host:port / full URLs accepted, case-insensitive). Hashes without a magnet (bare btih: / bare 40-hex) are skipped; the scan reports them as skipped. An empty host list sends nothing and is reported on the last-error line. |
| Advanced filters (2.8.0) | Master switch (off by default), panel expanded by default, one switch per filter (filters needing a missing extension are greyed out), Type position / field name, extra sorts, How release data is read from posts (size sources, units, labels, series rules — placeholders show the defaults) and the Index card (status, Rebuild index, Only missing / outdated, per-discussion preview). After enabling an index-based filter, rebuild the index once; after changing the parser rules, save and rebuild. |
Advanced filters — API
The panel sends ordinary GET /api/discussions filters, so they also work for
API clients. Ranges are min..max with either side optional (10GB..,
..2010, 5..20); malformed values are ignored, -key negates. A disabled
filter is ignored server-side too.
| Filter | Value |
|---|---|
filter[mediaType] |
movie / series |
filter[sizeRange] |
numbers with an optional unit B, KB…TB, KiB…TiB (default GB) |
filter[yearRange], filter[seasonsRange], filter[episodesRange], filter[durationRange] (minutes) |
numbers |
filter[imdbRange], filter[filmwebRange] (0–10), filter[ratingRange] (0–5), filter[steamRange] (0–100 %), filter[ratingCountRange], filter[viewsRange], filter[repliesRange], filter[clicksRange], filter[clicksTopRange] |
numbers |
filter[createdRange], filter[activeRange], filter[ratedRange], filter[clickedRange] |
unix timestamps or YYYY-MM-DD (UTC day, end day included) |
filter[hasMagnet] |
1 / 0 |
sort |
-hbSize / hbSize, -hbYear / hbYear |
The Steam DB score (filter and sort) uses SQL POWER() — available on
MySQL, MariaDB and PostgreSQL; on SQLite it needs a build with math functions.
API endpoints
| Method | Path | Purpose |
|---|---|---|
GET |
/api/tryhackx/homepage/stats |
Forum / tracker statistics (served from a shared server-side cache). |
POST |
/api/tryhackx/homepage/points/check |
Rate-limiter pre-flight for a search (?action=search, &facets=1 when the live counts will be fetched too). |
GET |
/api/tryhackx/homepage/facets |
Live Category / Resolution (and Type) counts for the filter bar: `filter[title |
GET |
/api/tryhackx/homepage/meta/status |
Admin only — Advanced Filters index status (total, indexed, missing, stale, with_size, series, movies) + the parser defaults. |
POST |
/api/tryhackx/homepage/meta/reindex |
Admin only — one batch of the index rebuild ({cursor, only_stale?} → {next_cursor, done, processed, elapsed_ms, status?}); single-flight (409 while another batch runs). |
GET |
/api/tryhackx/homepage/meta/preview?id=N |
Admin only — what the parser reads from discussion N with the current settings, next to what the index holds. |
POST |
/api/tryhackx/homepage/whitelist/test |
Admin only — pings the tracker API with the (unsaved) settings and reports mode / whitelist size / clock skew. |
POST |
/api/tryhackx/homepage/whitelist/scan |
Admin only — one batch of the forum scan ({cursor} → {next_cursor, done, processed, hashes_found, skipped_no_tracker, added, exists, banned, …}); on a tracker error the cursor is not advanced. |
POST |
/api/tryhackx/homepage/whitelist/secret |
Admin only — stores / clears the tracker API secret (accepts a full key_id.secret token). |
Development & tests
composer install composer test:setup # one-off: installs a throw-away Flarum (SQLite by default) composer test # PHP unit + integration tests cd js && npm ci && npm run build
The integration suite sends real API requests to a test install (SQLite unless
DB_DRIVER / DB_HOST / DB_PORT / DB_DATABASE / DB_USERNAME /
DB_PASSWORD / DB_PREFIX point at a MySQL, MariaDB or PostgreSQL test
database — all its tables are dropped).
Links
License
MIT License. See LICENSE for details.



