Quiblo wiki

Code reference · Source

:source:xtream

The Xtream Codes client, and the four guards that keep an account alive.

dev.quiblo.source.xtream

Also pure JVM, with one practical consequence when debugging: android.util.Log does not resolve here, so temporary instrumentation uses println and is read back from logcat.

Never log a request URL. It carries the username and the password. That is an acceptance criterion, not a style preference.

classXtreamSource

The MediaSource implementation, and the home of the block gate.

When a panel refuses, this stops asking for fifteen minutes — across all four call paths: refresh, guide, series details and film details. Before that gate existed, a blocked account kept being asked by the three paths that were not the guide, which is how a short block becomes a lasting one.

The catalogue walk stops at the first refusal. Four of its seven calls used to swallow a block as "this account has no films" and carry on.

classXtreamClient

The HTTP layer. Every call passes the rate limiter here.

The limiter is applied inside request rather than at each call site, which is what makes it a backstop: a future caller reintroducing a storm from a screen nobody has written yet still passes through it.

classPanelRateLimiter

A token bucket: burst of 8, refilling one per 400 ms.

The sizing is deliberate on both sides. The burst is eight because a refresh is authentication plus six catalogue calls and must not be slowed. The refill caps sustained traffic at two and a half requests a second, however many rows go by.

A concurrency cap is not a rate limit. The guard this replaced allowed three requests in flight, which at 100 ms each is thirty a second — and that is what got the test account blocked.

The balance is allowed to go negative, and that one detail is the sustained rate. A caller takes its token and waits off exactly what it borrowed. Clamping at zero instead lets the wait accrue a token that the next caller finds and passes straight through, so requests leave in pairs — which is what this limiter did for its whole life, pacing at 200 ms while the constant beside it said 400.

Its regression test asserts elapsed time across twenty requests rather than the gap between two: a pairwise assertion passes happily while requests leave two at a time.

objectXtreamUrl

Builds panel URLs. The one place credentials enter a string.

sealed interfaceApiResult

A response, an error, or a refusal — the third being the one that matters.

data classAuthResponse / UserInfo / ServerInfo

The authentication payload, including whether the account is active.

data classLiveStreamDto / VodStreamDto / SeriesDto / CategoryDto

Catalogue entries as the panel returns them, before mapping to domain types.

data classSeriesInfoResponse / SeasonDto / EpisodeDto / EpisodeInfoDto

A series and its episodes.

data classVodInfoResponse / VodInfoDto / VodMovieDataDto

A film's details.

data classEpgResponse / EpgListingDto

Short-range guide data for one channel.

objectFlexibleIntSerializer / FlexibleLongSerializer / FlexibleStringSerializer / FlexibleBooleanSerializer

Tolerant deserialisers for a family of APIs that are not internally consistent.

Panels return the same field as a number in one response and a quoted string in another, and booleans as true, "true", 1 or "1". These exist so one inconsistent field does not fail an entire catalogue — the alternative is a user whose account works everywhere else and not here.

objectSeriesInfoResponseSerializer

Handles a series payload whose shape changes with its contents.