mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 12:05:07 +00:00
feat(service): add GEOBLOCK negative geofence
Regions in GEOBLOCK refuse the service and everything else is allowed. A hit stops the run with a region error instead of auto-proxying; the check also covers proxy exits and the remote-dl client region.
This commit is contained in:
@@ -97,6 +97,7 @@ Declared at class level to configure framework behaviour:
|
||||
|---|---|---|
|
||||
| `ALIASES` | `tuple[str, ...]` | Extra tags that resolve to this service (e.g. `("EX", "DOMAIN")`). Case does not matter. Default `()`. |
|
||||
| `GEOFENCE` | `tuple[str, ...]` | IP region codes the service requires. Empty = no geofence. unshackle treats the **first** entry as the main region for auto-proxy. |
|
||||
| `GEOBLOCK` | `tuple[str, ...]` | IP region codes where the service refuses to work. Every other region is allowed. Default `()`. |
|
||||
| `VAULT_TAG` | `Optional[str]` | Overrides the key-vault namespace so sibling services can share one vault. Default `None` (use the service's own tag). |
|
||||
| `AUTH_METHODS` | `Optional[tuple[str, ...]]` | Auth methods accepted (`"cookies"` / `"credentials"`). When `None`, the REST `/services` endpoint infers them from `authenticate()`. |
|
||||
| `NO_SUBTITLES` | `bool` | Set `True` on a service with no subtitle tracks to skip subtitle handling entirely. |
|
||||
@@ -113,11 +114,19 @@ Declared at class level to configure framework behaviour:
|
||||
explicit `--proxy`, the base class does a live IP check and, if your region is
|
||||
blocked, fetches a proxy to `GEOFENCE[0]` from your configured proxy providers.
|
||||
|
||||
`GEOBLOCK` is the negative form: the service works everywhere except the listed
|
||||
regions. With no `GEOFENCE` to name a main region, a `GEOBLOCK` hit stops the run
|
||||
with a "not available in your region" error; pass `--proxy` yourself.
|
||||
|
||||
```python
|
||||
class EXAMPLE(Service):
|
||||
ALIASES = ("EX", "DOMAIN")
|
||||
GEOFENCE = ("US", "UK")
|
||||
VAULT_TAG = "DIFFERENT_NAME"
|
||||
|
||||
|
||||
class WORLDWIDE(Service):
|
||||
GEOBLOCK = ("GB",)
|
||||
```
|
||||
|
||||
### What `Service.__init__` wires up
|
||||
|
||||
@@ -182,7 +182,7 @@ GET /api/dashboard/services
|
||||
[{"tag": "EXAMPLE", "state": "staged", "error": null,
|
||||
"commit": "9cc230c98f13b83f6c6fe831595b9702d3ba2786", "staged_commit": "5f0aa17...",
|
||||
"staged_since": 1756908900.0, "sessions": 1, "jobs": 1,
|
||||
"aliases": ["EXMPL"], "geofence": ["US"]}]
|
||||
"aliases": ["EXMPL"], "geofence": ["US"], "geoblock": []}]
|
||||
```
|
||||
|
||||
`state` is `loaded`, `staged` or `failed`. A service that failed to import keeps its error
|
||||
|
||||
@@ -79,6 +79,7 @@ Show the streaming services available on this server, filtered by your allowlist
|
||||
"tag": "EXAMPLE",
|
||||
"aliases": ["EX"],
|
||||
"geofence": ["US"],
|
||||
"geoblock": [],
|
||||
"title_regex": "^https?://example\\.com/.+",
|
||||
"url": "https://example.com",
|
||||
"help": "EXAMPLE\nAuthorization: Cookies\nSecurity: FHD@L3",
|
||||
@@ -112,6 +113,7 @@ Field notes:
|
||||
| `tag` | Canonical service tag; use this as the `service` value on other endpoints. |
|
||||
| `aliases` | Alternate tags the service also answers to. |
|
||||
| `geofence` | Region codes the service is geofenced to (may be empty). |
|
||||
| `geoblock` | Region codes where the service refuses to work (may be empty). |
|
||||
| `title_regex` | URL/ID pattern the service matches, as a string or list of strings (or `null`). |
|
||||
| `url` | Service URL, taken from the service's CLI short help. |
|
||||
| `help` | The service module's docstring. |
|
||||
|
||||
@@ -152,7 +152,7 @@ The classification is keyword-based, checked in order:
|
||||
|---|---|---|
|
||||
| `auth`, `login`, `credential`, `unauthorized`, `forbidden`, `token` | `AUTH_FAILED` (401) | no |
|
||||
| `connection`, `timeout`, `network`, `unreachable`, `socket`, `dns`, `resolve` (or `ConnectionError`, `TimeoutError`, `URLError`, `SSLError`) | `NETWORK_ERROR` (503) | yes |
|
||||
| `geofence`, `region`, `not available in`, `territory` | `GEOFENCE` (403) | no |
|
||||
| `geofence`, `geoblock`, `region`, `not available in`, `territory` | `GEOFENCE` (403) | no |
|
||||
| `not found`, `404`, `does not exist`, `invalid id` | `NOT_FOUND` (404) | no |
|
||||
| `rate limit`, `too many requests`, `429`, `throttle` | `RATE_LIMITED` (429) | yes |
|
||||
| `drm`, `license`, `widevine`, `playready`, `decrypt` | `DRM_ERROR` (502) | no |
|
||||
|
||||
@@ -141,6 +141,7 @@ curl "$BASE/api/services" \
|
||||
"tag": "EXAMPLE",
|
||||
"aliases": ["EX"],
|
||||
"geofence": [],
|
||||
"geoblock": [],
|
||||
"title_regex": null,
|
||||
"url": "https://example.com",
|
||||
"help": "EXAMPLE service documentation...",
|
||||
|
||||
@@ -63,6 +63,7 @@ Declared at the top of your service class, these are static descriptors:
|
||||
|---|---|---|
|
||||
| `ALIASES` | `tuple[str, ...]` | Alternate tags the service answers to, in any case (resolved by `Services.get_tag`). |
|
||||
| `GEOFENCE` | `tuple[str, ...]` | ISO region codes the service requires; empty means no geofence. unshackle treats the first entry as the "main region" for automatic proxy selection. |
|
||||
| `GEOBLOCK` | `tuple[str, ...]` | ISO region codes where the service refuses to work; every other region is allowed. Use it for a service that works worldwide except in its home market. |
|
||||
| `VAULT_TAG` | `Optional[str]` | Overrides the key-vault namespace; defaults to the service's own tag. |
|
||||
| `AUTH_METHODS` | `Optional[tuple[str, ...]]` | Accepted auth methods (`"cookies"` / `"credentials"`). When `None`, the REST `/services` endpoint infers them from `authenticate()`. |
|
||||
| `ANIME` | `bool` | The catalogue is anime, so metadata lookups prefer AniList. A title's own `anime` flag overrides it. |
|
||||
@@ -117,7 +118,10 @@ up the objects your methods rely on:
|
||||
The constructor also resolves proxies: it reads `--proxy` and the `proxy_query` and
|
||||
`proxy_provider` context params that `dl` derives from it, consults the per-service
|
||||
`proxy_map`, and, if `GEOFENCE` is set and you did not give an explicit proxy, does a live
|
||||
IP check and auto-fetches a proxy to `GEOFENCE[0]` when it detects a geoblock.
|
||||
IP check and auto-fetches a proxy to `GEOFENCE[0]` when it detects a geoblock. A
|
||||
`GEOBLOCK` hit with no `GEOFENCE` stops the run with a "not available in your region"
|
||||
error, because there is no main region to fetch a proxy for; pass `--proxy` yourself.
|
||||
A proxy whose exit is in a `GEOBLOCK` region stops the run the same way.
|
||||
See [Proxies and VPN](../guide/proxies-and-vpn.md).
|
||||
|
||||
!!! note "`TrackRequest`"
|
||||
|
||||
Reference in New Issue
Block a user