fix(services): match service aliases without case

Uppercase entries in ALIASES never resolved, because get_tag lowercased the input but not the alias. Match real tags first so a service's own tag cannot be taken by another service's alias.
This commit is contained in:
imSp4rky
2026-08-24 11:56:46 -06:00
parent 87cdb30229
commit 0a68cc2452
5 changed files with 58 additions and 20 deletions
+3 -3
View File
@@ -95,13 +95,13 @@ Declared at class level to configure framework behaviour:
| Variable | Type | Purpose |
|---|---|---|
| `ALIASES` | `tuple[str, ...]` | Extra tags that resolve to this service (e.g. `("EX", "DOMAIN")`). Default `()`. |
| `GEOFENCE` | `tuple[str, ...]` | IP region codes the service requires. Empty = no geofence. The **first** entry is treated as the main region for auto-proxy. |
| `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. |
| `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. |
| `ANIME` | `bool` | Set `True` when the catalogue is anime, so metadata lookups prefer AniList. A title's own `anime` flag overrides it. |
| `DAILY` | `bool` | Set `True` when the catalogue is daily/date-based (talk shows, news, sports), so episodes are named by air date. A title's own `daily` flag overrides it. |
| `DAILY` | `bool` | Set `True` when the catalogue is daily/date-based (talk shows, news, sports), so unshackle names episodes by air date. A title's own `daily` flag overrides it. |
!!! note "`NO_SUBTITLES` is a convention, not a base-class attribute"
`dl.py` uses `hasattr` to find `NO_SUBTITLES`, and the `Service` base class
+5 -5
View File
@@ -61,12 +61,12 @@ Declared at the top of your service class, these are static descriptors:
| Class variable | Type | Purpose |
|---|---|---|
| `ALIASES` | `tuple[str, ...]` | Alternate tags the service answers to (resolved by `Services.get_tag`). |
| `GEOFENCE` | `tuple[str, ...]` | ISO region codes the service requires; empty means no geofence. The first entry is treated as the "main region" for automatic proxy selection. |
| `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. |
| `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. |
| `DAILY` | `bool` | The catalogue is daily/date-based, so episodes are named by air date. A title's own `daily` flag overrides it. |
| `DAILY` | `bool` | The catalogue is daily/date-based, so unshackle names episodes by air date. A title's own `daily` flag overrides it. |
### Required methods
@@ -141,7 +141,7 @@ families, one per media kind:
All items subclass `Title`, which carries the shared identity: a **unique `id`**, the
originating `service` class, an optional original `language`, arbitrary `data`, and a
freshly-constructed `self.tracks = Tracks()` that `get_tracks` will fill. Collections
are sorted lists, so titles stay in a stable order.
use sorted lists, so titles stay in a stable order.
!!! warning "The unique ID is validated"
`Title.__init__` rejects a falsy `id_`, and rejects any ID shorter than 4 characters
@@ -330,7 +330,7 @@ in `unshackle.core.manifests`. Each parser has the same three-part contract:
### The parser contract
1. **Construct**: `DASH.from_url(url, session=...)` or `DASH.from_text(text, url)`
(and likewise for `HLS` / `ISM`). A `url` is always required, even for `from_text`,
(and likewise for `HLS` / `ISM`). Always pass a `url`, even to `from_text`,
because the parser needs it to make relative segment paths absolute.
2. **`to_tracks(...)`**: parses the manifest into a `Tracks` container of `Video`,
`Audio`, and `Subtitle` objects, each carrying descriptor-specific state.