Compare commits

..

1 Commits

Author SHA1 Message Date
1b8e8c9a79 Merge pull request '1.0.0: Релиз' (#1) from dev into latest
All checks were successful
Build And Publish Package / publish (push) Successful in 32s
Reviewed-on: #1
2025-12-17 06:31:41 +03:00
7 changed files with 255 additions and 418 deletions

View File

@ -1,18 +1,18 @@
repos: repos:
- repo: https://github.com/crate-ci/typos - repo: https://github.com/crate-ci/typos
rev: v1.42.0 rev: v1.36.3
hooks: hooks:
- id: typos - id: typos
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.13 rev: v0.13.2
hooks: hooks:
- id: ruff - id: ruff
args: [ --fix ] args: [ --fix ]
- id: ruff-format - id: ruff-format
- repo: https://github.com/RobertCraigie/pyright-python - repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.408 rev: v1.1.405
hooks: hooks:
- id: pyright - id: pyright

170
README.md
View File

@ -1,170 +0,0 @@
# Twitch Client (Async)
An internal **async Twitch API client** built on top of **AioHTTPX**, providing typed access to the Twitch **Helix API** and **OAuth2** endpoints with built-in rate limiting and optional caching.
---
## What it provides
* `TwitchAPIClient` — async client for Twitch **Helix API**
* `TwitchAuthClient` — async client for Twitch **OAuth2**
* Built on **AioHTTPX** (aiohttp transport, Redis rate limiting & caching)
* Strongly typed responses using **Pydantic models**
* Automatic request parameter cleanup (`None` values removed)
---
## Installation (internal)
Configure your private package index, then:
```bash
pip install twitchclient
```
---
## Authentication
### OAuth helper client
```python
from twitchclient.auth import TwitchAuthClient
from twitchclient import scopes
auth = TwitchAuthClient(
client_id="CLIENT_ID",
client_secret="CLIENT_SECRET",
redirect_uri="https://your.app/callback",
)
url = await auth.create_authorization_code_grant_flow_url(
scope=[scopes.USER_READ_EMAIL, scopes.CHAT_READ],
)
```
### App access token
```python
token = await auth.app_access_token()
print(token.access_token)
```
### User access token
```python
token = await auth.user_access_token(code="AUTH_CODE")
```
---
## API Client
```python
from twitchclient.api import TwitchAPIClient
client = TwitchAPIClient(
client_id="CLIENT_ID",
client_secret="CLIENT_SECRET",
redirect_uri="https://your.app/callback",
redis_url="redis://localhost:6379", # optional
)
```
* Base URL: `https://api.twitch.tv/helix`
* `Client-Id` header is set automatically
* Rate limit defaults to **700 req/min** when Redis is enabled
---
## Example usage
### Get channel information
```python
channels = await client.get_channel_information(
access_token=token.access_token,
broadcaster_id=123456,
)
```
### Start a commercial
```python
await client.start_commercial(
access_token=token.access_token,
broadcaster_id=123456,
)
```
### Cached request
Caching is controlled via the `X-Cache-TTL` header:
```python
streams = await client.get_streams(
access_token=token.access_token,
game_id=509658,
cache_time=30,
)
```
---
## Rate limiting & caching
* **Redis-backed**
* Shared key: `twitch`
* Enabled automatically when `redis_url` is provided
* Cache TTL is per-request (`X-Cache-TTL` header)
Implementation is inherited from **AioHTTPX transports** .
---
## Errors
All API methods raise typed exceptions:
* `ClientError(status_code, message)`
* `InternalError(status_code, message)`
Defined in schema module .
---
## Scopes
OAuth scopes are defined as constants and typed literals:
```python
from twitchclient import scopes
scopes.CHANNEL_READ_SUBSCRIPTIONS
scopes.CHAT_READ
```
See `scopes.py` for the full list .
---
## Typed responses
All successful responses return **Pydantic models**, e.g.:
* `ChannelsInformation`
* `Streams`
* `Users`
* `EventsubSubscriptions`
Models live in `schema.py` .
---
## Notes & limitations
* Async-only (no sync client)
* Internal API, no stability guarantees
* Some endpoints still marked TODO (e.g. Guest Star)
---

View File

@ -1,11 +1,16 @@
[project] [project]
name = "twitchclient" name = "twitchclient"
version = "1.1.0" version = "1.0.0"
description = "Client for Twitch API" description = "Client for Twitch API"
readme = "README.md" readme = "README.md"
authors = [{ name = "Miwory", email = "miwory.uwu@gmail.com" }] authors = [
{ name = "Miwory", email = "miwory.uwu@gmail.com" }
]
requires-python = ">=3.13" requires-python = ">=3.13"
dependencies = ["aiohttpx>=1.3,<=2.0", "pydantic>=2.12,<=2.13"] dependencies = [
"aiohttpx>=1.3,<=2.0",
"pydantic>=2.12,<=2.13",
]
[build-system] [build-system]
requires = ["uv_build>=0.9.2,<0.10.0"] requires = ["uv_build>=0.9.2,<0.10.0"]
@ -13,10 +18,10 @@ build-backend = "uv_build"
[project.optional-dependencies] [project.optional-dependencies]
dev = [ dev = [
"ruff==0.14.13", "ruff==0.14.9",
"pyright==1.1.408", "pyright==1.1.407",
"poethepoet==0.40.0", "poethepoet==0.38.0",
"pre-commit==4.5.1", "pre-commit==4.5.0",
] ]
[[tool.uv.index]] [[tool.uv.index]]

View File

@ -13,10 +13,10 @@ from .eventsub import types as sub_type
class TwitchAPIClient(AioHTTPXClient): class TwitchAPIClient(AioHTTPXClient):
def __init__( def __init__(
self, self,
redis_url: str,
client_id: str, client_id: str,
client_secret: str, client_secret: str,
redirect_uri: str, redirect_uri: str,
redis_url: str | None = None,
): ):
self.base_uri = 'https://api.twitch.tv/helix' self.base_uri = 'https://api.twitch.tv/helix'
self.client_id = client_id self.client_id = client_id
@ -27,8 +27,8 @@ class TwitchAPIClient(AioHTTPXClient):
base_url=self.base_uri, base_url=self.base_uri,
headers={'Client-Id': self.client_id}, headers={'Client-Id': self.client_id},
redis_url=redis_url, redis_url=redis_url,
key='twitch' if redis_url else None, key='twitch',
limit=700 if redis_url else None, limit=700,
logger='Twitch API', logger='Twitch API',
) )
@ -67,7 +67,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.AdSchedule.model_validate(req.json()) return s.AdSchedule.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED: case st.BAD_REQUEST | st.UNAUTHORIZED:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -86,7 +86,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.SnoozeNextAd.model_validate(req.json()) return s.SnoozeNextAd.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS: case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -122,7 +122,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.ExtensionAnalytics.model_validate(req.json()) return s.ExtensionAnalytics.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.NOT_FOUND: case st.BAD_REQUEST | st.UNAUTHORIZED | st.NOT_FOUND:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -158,7 +158,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.GameAnalytics.model_validate(req.json()) return s.GameAnalytics.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.NOT_FOUND: case st.BAD_REQUEST | st.UNAUTHORIZED | st.NOT_FOUND:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -190,7 +190,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.BitsLeaderboard.model_validate(req.json()) return s.BitsLeaderboard.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.FORBIDDEN: case st.BAD_REQUEST | st.UNAUTHORIZED | st.FORBIDDEN:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -209,7 +209,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.Cheermotes.model_validate(req.json()) return s.Cheermotes.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED: case st.BAD_REQUEST | st.UNAUTHORIZED:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -241,7 +241,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.ExtensionTransactions.model_validate(req.json()) return s.ExtensionTransactions.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.NOT_FOUND: case st.BAD_REQUEST | st.UNAUTHORIZED | st.NOT_FOUND:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -262,7 +262,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.ChannelsInformation.model_validate(req.json()) return s.ChannelsInformation.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS: case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -328,7 +328,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.ChannelEditors.model_validate(req.json()) return s.ChannelEditors.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS: case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -358,7 +358,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.FollowedChannels.model_validate(req.json()) return s.FollowedChannels.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS: case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -390,7 +390,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.ChannelFollowers.model_validate(req.json()) return s.ChannelFollowers.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS: case st.BAD_REQUEST | st.UNAUTHORIZED | st.TOO_MANY_REQUESTS:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -446,7 +446,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.CustomRewards.model_validate(req.json()) return s.CustomRewards.model_validate(req.json()).data
case ( case (
st.BAD_REQUEST st.BAD_REQUEST
@ -506,7 +506,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.CustomRewards.model_validate(req.json()) return s.CustomRewards.model_validate(req.json()).data
case ( case (
st.BAD_REQUEST st.BAD_REQUEST
@ -550,7 +550,9 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.CustomRewardRedemptions.model_validate(req.json()) return s.CustomRewardRedemptions.model_validate(
req.json()
).data
case ( case (
st.BAD_REQUEST st.BAD_REQUEST
@ -613,7 +615,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.CustomRewards.model_validate(req.json()) return s.CustomRewards.model_validate(req.json()).data
case ( case (
st.BAD_REQUEST st.BAD_REQUEST
@ -631,8 +633,8 @@ class TwitchAPIClient(AioHTTPXClient):
self, self,
access_token: str, access_token: str,
broadcaster_id: int, broadcaster_id: int,
reward_id: str, reward_id: int,
redemption_id: str | list[str], redemption_id: int | list[int],
status: Literal['CANCELED', 'FULFILLED'], status: Literal['CANCELED', 'FULFILLED'],
): ):
req = await self.post( req = await self.post(
@ -673,7 +675,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.CharityCampaign.model_validate(req.json()) return s.CharityCampaign.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.FORBIDDEN: case st.BAD_REQUEST | st.UNAUTHORIZED | st.FORBIDDEN:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -702,14 +704,14 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
) )
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.CharityDonations.model_validate(req.json()) return s.CharityDonations.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.FORBIDDEN: case st.BAD_REQUEST | st.UNAUTHORIZED | st.FORBIDDEN:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -728,7 +730,7 @@ class TwitchAPIClient(AioHTTPXClient):
cache_time: int | None = None, cache_time: int | None = None,
): ):
req = await self.get( req = await self.get(
'/chat/chatters', '/chatters',
params=self.clean_dict( params=self.clean_dict(
{ {
'broadcaster_id': broadcaster_id, 'broadcaster_id': broadcaster_id,
@ -740,14 +742,14 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
) )
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.Chatters.model_validate(req.json()) return s.Chatters.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.FORBIDDEN: case st.BAD_REQUEST | st.UNAUTHORIZED | st.FORBIDDEN:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -767,7 +769,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'broadcaster_id': broadcaster_id}, params={'broadcaster_id': broadcaster_id},
@ -791,7 +793,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
) )
@ -818,7 +820,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'emote_set_id': emote_set_id}, params={'emote_set_id': emote_set_id},
@ -846,7 +848,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'broadcaster_id': broadcaster_id}, params={'broadcaster_id': broadcaster_id},
@ -870,7 +872,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
) )
@ -898,7 +900,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -911,7 +913,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.ChatSettings.model_validate(req.json()) return s.ChatSettings.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED: case st.BAD_REQUEST | st.UNAUTHORIZED:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -931,7 +933,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'broadcaster_id': broadcaster_id}, params={'broadcaster_id': broadcaster_id},
@ -939,7 +941,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.SharedChatSession.model_validate(req.json()) return s.SharedChatSession.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED: case st.BAD_REQUEST | st.UNAUTHORIZED:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -961,7 +963,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -1025,7 +1027,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.ChatSettings.model_validate(req.json()) return s.ChatSettings.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED: case st.BAD_REQUEST | st.UNAUTHORIZED:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -1121,7 +1123,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.Message.model_validate(req.json()) return s.Message.model_validate(req.json()).data
case ( case (
st.BAD_REQUEST st.BAD_REQUEST
@ -1146,7 +1148,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'user_id': user_id}, params={'user_id': user_id},
@ -1231,7 +1233,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -1251,7 +1253,7 @@ class TwitchAPIClient(AioHTTPXClient):
match req.status_code: match req.status_code:
case st.OK: case st.OK:
return s.Clips.model_validate(req.json()) return s.Clips.model_validate(req.json()).data
case st.BAD_REQUEST | st.UNAUTHORIZED | st.NOT_FOUND: case st.BAD_REQUEST | st.UNAUTHORIZED | st.NOT_FOUND:
raise s.ClientError(req.status_code, req.json()['message']) raise s.ClientError(req.status_code, req.json()['message'])
@ -1273,7 +1275,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -1308,7 +1310,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
) )
@ -1390,7 +1392,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -1498,7 +1500,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -1570,7 +1572,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {jwt_token}', 'Authorization': f'Bearer {jwt_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -1703,7 +1705,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -1737,7 +1739,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {jwt_token}', 'Authorization': f'Bearer {jwt_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'extension_id': extension_id}, params={'extension_id': extension_id},
@ -1814,7 +1816,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {jwt_token}', 'Authorization': f'Bearer {jwt_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -1848,7 +1850,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -1881,7 +1883,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -2023,7 +2025,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -2061,7 +2063,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -2097,7 +2099,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -2131,7 +2133,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'broadcaster_id': broadcaster_id}, params={'broadcaster_id': broadcaster_id},
@ -2161,7 +2163,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'broadcaster_id': broadcaster_id}, params={'broadcaster_id': broadcaster_id},
@ -2189,7 +2191,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'broadcaster_id': broadcaster_id}, params={'broadcaster_id': broadcaster_id},
@ -2248,7 +2250,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={ params={
@ -2509,7 +2511,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -2632,7 +2634,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -2669,7 +2671,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -2750,7 +2752,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -2867,7 +2869,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={ params={
@ -2941,7 +2943,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3045,7 +3047,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3201,7 +3203,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3239,7 +3241,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'broadcaster_id': broadcaster_id}, params={'broadcaster_id': broadcaster_id},
@ -3409,7 +3411,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3442,7 +3444,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3477,7 +3479,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'broadcaster_id': broadcaster_id}, params={'broadcaster_id': broadcaster_id},
@ -3512,7 +3514,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3553,7 +3555,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3623,7 +3625,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3664,7 +3666,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3700,7 +3702,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3733,7 +3735,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'broadcaster_id': broadcaster_id}, params={'broadcaster_id': broadcaster_id},
@ -3762,7 +3764,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict({'name': name, 'id': team_id}), params=self.clean_dict({'name': name, 'id': team_id}),
@ -3791,7 +3793,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict({'id': user_id, 'login': login}), params=self.clean_dict({'id': user_id, 'login': login}),
@ -3840,7 +3842,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'user_id': user_id}, params={'user_id': user_id},
@ -3875,7 +3877,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(
@ -3960,7 +3962,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
) )
@ -3987,7 +3989,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params={'user_id': user_id}, params={'user_id': user_id},
@ -4044,7 +4046,7 @@ class TwitchAPIClient(AioHTTPXClient):
headers=self.clean_dict( headers=self.clean_dict(
{ {
'Authorization': f'Bearer {access_token}', 'Authorization': f'Bearer {access_token}',
'X-Cache-TTL': str(cache_time), 'X-Cache-TTL': cache_time,
} }
), ),
params=self.clean_dict( params=self.clean_dict(

View File

@ -10,10 +10,10 @@ from . import scopes
class TwitchAuthClient(AioHTTPXClient): class TwitchAuthClient(AioHTTPXClient):
def __init__( def __init__(
self, self,
redis_url: str,
client_id: str, client_id: str,
client_secret: str, client_secret: str,
redirect_uri: str, redirect_uri: str,
redis_url: str | None = None,
): ):
self.base_uri = 'https://id.twitch.tv/oauth2' self.base_uri = 'https://id.twitch.tv/oauth2'
self.client_id = client_id self.client_id = client_id
@ -23,8 +23,8 @@ class TwitchAuthClient(AioHTTPXClient):
super().__init__( super().__init__(
base_url=self.base_uri, base_url=self.base_uri,
redis_url=redis_url, redis_url=redis_url,
key='twitch' if redis_url else None, key='twitch',
limit=700 if redis_url else None, limit=700,
logger='Twitch Auth', logger='Twitch Auth',
) )

View File

@ -309,7 +309,7 @@ class CustomReward(BaseSchema):
broadcaster_id: int broadcaster_id: int
broadcaster_login: str broadcaster_login: str
broadcaster_name: str broadcaster_name: str
id: str id: int
title: str title: str
prompt: str prompt: str
cost: int cost: int
@ -1263,7 +1263,6 @@ class Stream(BaseSchema):
type: Literal['live'] type: Literal['live']
title: str title: str
tags: list[str] tags: list[str]
tag_ids: list[str] = Field(..., deprecated=True)
viewer_count: int viewer_count: int
started_at: datetime started_at: datetime
language: str language: str
@ -1390,7 +1389,6 @@ class User(BaseSchema):
offline_image_url: str offline_image_url: str
email: str | None = None email: str | None = None
created_at: datetime created_at: datetime
view_count: int = Field(..., deprecated=True)
class Users(BaseSchema): class Users(BaseSchema):

View File

@ -1,166 +1,168 @@
# Analytics
from typing import Literal from typing import Literal
ANALYTICS_READ_EXTENSIONS = 'analytics:read:extensions' # Analytics
ANALYTICS_READ_GAMES = 'analytics:read:games' ANALYTICS_READ_EXTENSIONS = Literal['analytics:read:extensions']
ANALYTICS_READ_GAMES = Literal['analytics:read:games']
# Bits # Bits
BITS_READ = 'bits:read' BITS_READ = Literal['bits:read']
# Channel # Channel
CHANNEL_MANAGE_ADS = 'channel:manage:ads' CHANNEL_MANAGE_ADS = Literal['channel:manage:ads']
CHANNEL_READ_ADS = 'channel:read:ads' CHANNEL_READ_ADS = Literal['channel:read:ads']
CHANNEL_MANAGE_BROADCAST = 'channel:manage:broadcast' CHANNEL_MANAGE_BROADCAST = Literal['channel:manage:broadcast']
CHANNEL_READ_CHARITY = 'channel:read:charity' CHANNEL_READ_CHARITY = Literal['channel:read:charity']
CHANNEL_EDIT_COMMERCIAL = 'channel:edit:commercial' CHANNEL_EDIT_COMMERCIAL = Literal['channel:edit:commercial']
CHANNEL_READ_EDITORS = 'channel:read:editors' CHANNEL_READ_EDITORS = Literal['channel:read:editors']
CHANNEL_MANAGE_EXTENSIONS = 'channel:manage:extensions' CHANNEL_MANAGE_EXTENSIONS = Literal['channel:manage:extensions']
CHANNEL_READ_GOALS = 'channel:read:goals' CHANNEL_READ_GOALS = Literal['channel:read:goals']
CHANNEL_READ_GUEST_STAR = 'channel:read:guest_star' CHANNEL_READ_GUEST_STAR = Literal['channel:read:guest_star']
CHANNEL_MANAGE_GUEST_STAR = 'channel:manage:guest_star' CHANNEL_MANAGE_GUEST_STAR = Literal['channel:manage:guest_star']
CHANNEL_READ_HYPE_TRAIN = 'channel:read:hype_train' CHANNEL_READ_HYPE_TRAIN = Literal['channel:read:hype_train']
CHANNEL_MANAGE_MODERATORS = 'channel:manage:moderators' CHANNEL_MANAGE_MODERATORS = Literal['channel:manage:moderators']
CHANNEL_READ_POLLS = 'channel:read:polls' CHANNEL_READ_POLLS = Literal['channel:read:polls']
CHANNEL_MANAGE_POLLS = 'channel:manage:polls' CHANNEL_MANAGE_POLLS = Literal['channel:manage:polls']
CHANNEL_READ_PREDICTIONS = 'channel:read:predictions' CHANNEL_READ_PREDICTIONS = Literal['channel:read:predictions']
CHANNEL_MANAGE_PREDICTIONS = 'channel:manage:predictions' CHANNEL_MANAGE_PREDICTIONS = Literal['channel:manage:predictions']
CHANNEL_MANAGE_RAIDS = 'channel:manage:raids' CHANNEL_MANAGE_RAIDS = Literal['channel:manage:raids']
CHANNEL_READ_REDEMPTIONS = 'channel:read:redemptions' CHANNEL_READ_REDEMPTIONS = Literal['channel:read:redemptions']
CHANNEL_MANAGE_REDEMPTIONS = 'channel:manage:redemptions' CHANNEL_MANAGE_REDEMPTIONS = Literal['channel:manage:redemptions']
CHANNEL_MANAGE_SCHEDULE = 'channel:manage:schedule' CHANNEL_MANAGE_SCHEDULE = Literal['channel:manage:schedule']
CHANNEL_READ_STREAM_KEY = 'channel:read:stream_key' CHANNEL_READ_STREAM_KEY = Literal['channel:read:stream_key']
CHANNEL_READ_SUBSCRIPTIONS = 'channel:read:subscriptions' CHANNEL_READ_SUBSCRIPTIONS = Literal['channel:read:subscriptions']
CHANNEL_MANAGE_VIDEOS = 'channel:manage:videos' CHANNEL_MANAGE_VIDEOS = Literal['channel:manage:videos']
CHANNEL_READ_VIPS = 'channel:read:vips' CHANNEL_READ_VIPS = Literal['channel:read:vips']
CHANNEL_MANAGE_VIPS = 'channel:manage:vips' CHANNEL_MANAGE_VIPS = Literal['channel:manage:vips']
CHANNEL_BOT = 'channel:bot' CHANNEL_BOT = Literal['channel:bot']
CHANNEL_MODERATE = 'channel:moderate' CHANNEL_MODERATE = Literal['channel:moderate']
# clips # clips
CLIPS_EDIT = 'clips:edit' CLIPS_EDIT = Literal['clips:edit']
# Moderation # Moderation
MODERATION_READ = 'moderation:read' MODERATION_READ = Literal['moderation:read']
MODERATOR_MANAGE_ANNOUNCEMENTS = 'moderator:manage:announcements' MODERATOR_MANAGE_ANNOUNCEMENTS = Literal['moderator:manage:announcements']
MODERATOR_MANAGE_AUTOMOD = 'moderator:manage:automod' MODERATOR_MANAGE_AUTOMOD = Literal['moderator:manage:automod']
MODERATOR_READ_AUTOMOD_SETTINGS = 'moderator:read:automod_settings' MODERATOR_READ_AUTOMOD_SETTINGS = Literal['moderator:read:automod_settings']
MODERATOR_MANAGE_AUTOMOD_SETTINGS = 'moderator:manage:automod_settings' MODERATOR_MANAGE_AUTOMOD_SETTINGS = Literal[
MODERATOR_MANAGE_BANNED_USERS = 'moderator:manage:banned_users' 'moderator:manage:automod_settings'
MODERATOR_READ_BLOCKED_TERMS = 'moderator:read:blocked_terms' ]
MODERATOR_MANAGE_BLOCKED_TERMS = 'moderator:manage:blocked_terms' MODERATOR_MANAGE_BANNED_USERS = Literal['moderator:manage:banned_users']
MODERATOR_MANAGE_CHAT_MESSAGES = 'moderator:manage:chat_messages' MODERATOR_READ_BLOCKED_TERMS = Literal['moderator:read:blocked_terms']
MODERATOR_READ_CHAT_SETTINGS = 'moderator:read:chat_settings' MODERATOR_MANAGE_BLOCKED_TERMS = Literal['moderator:manage:blocked_terms']
MODERATOR_MANAGE_CHAT_SETTINGS = 'moderator:manage:chat_settings' MODERATOR_MANAGE_CHAT_MESSAGES = Literal['moderator:manage:chat_messages']
MODERATOR_READ_CHATTERS = 'moderator:read:chatters' MODERATOR_READ_CHAT_SETTINGS = Literal['moderator:read:chat_settings']
MODERATOR_READ_FOLLOWERS = 'moderator:read:followers' MODERATOR_MANAGE_CHAT_SETTINGS = Literal['moderator:manage:chat_settings']
MODERATOR_READ_GUEST_STAR = 'moderator:read:guest_star' MODERATOR_READ_CHATTERS = Literal['moderator:read:chatters']
MODERATOR_MANAGE_GUEST_STAR = 'moderator:manage:guest_star' MODERATOR_READ_FOLLOWERS = Literal['moderator:read:followers']
MODERATOR_READ_SHIELD_MODE = 'moderator:read:shield_mode' MODERATOR_READ_GUEST_STAR = Literal['moderator:read:guest_star']
MODERATOR_MANAGE_SHIELD_MODE = 'moderator:manage:shield_mode' MODERATOR_MANAGE_GUEST_STAR = Literal['moderator:manage:guest_star']
MODERATOR_READ_SHOUTOUTS = 'moderator:read:shoutouts' MODERATOR_READ_SHIELD_MODE = Literal['moderator:read:shield_mode']
MODERATOR_MANAGE_SHOUTOUTS = 'moderator:manage:shoutouts' MODERATOR_MANAGE_SHIELD_MODE = Literal['moderator:manage:shield_mode']
MODERATOR_READ_UNBAN_REQUESTS = 'moderator:read:unban_requests' MODERATOR_READ_SHOUTOUTS = Literal['moderator:read:shoutouts']
MODERATOR_MANAGE_UNBAN_REQUESTS = 'moderator:manage:unban_requests' MODERATOR_MANAGE_SHOUTOUTS = Literal['moderator:manage:shoutouts']
MODERATOR_READ_WARNINGS = 'moderator:read:warnings' MODERATOR_READ_UNBAN_REQUESTS = Literal['moderator:read:unban_requests']
MODERATOR_MANAGE_WARNINGS = 'moderator:manage:warnings' MODERATOR_MANAGE_UNBAN_REQUESTS = Literal['moderator:manage:unban_requests']
MODERATOR_READ_WARNINGS = Literal['moderator:read:warnings']
MODERATOR_MANAGE_WARNINGS = Literal['moderator:manage:warnings']
# User # User
USER_EDIT = 'user:edit' USER_EDIT = Literal['user:edit']
USER_EDIT_FOLLOWS = 'user:edit:follows' USER_EDIT_FOLLOWS = Literal['user:edit:follows']
USER_READ_BLOCKED_USERS = 'user:read:blocked_users' USER_READ_BLOCKED_USERS = Literal['user:read:blocked_users']
USER_MANAGE_BLOCKED_USERS = 'user:manage:blocked_users' USER_MANAGE_BLOCKED_USERS = Literal['user:manage:blocked_users']
USER_READ_BROADCAST = 'user:read:broadcast' USER_READ_BROADCAST = Literal['user:read:broadcast']
USER_MANAGE_CHAT_COLOR = 'user:manage:chat_color' USER_MANAGE_CHAT_COLOR = Literal['user:manage:chat_color']
USER_READ_EMAIL = 'user:read:email' USER_READ_EMAIL = Literal['user:read:email']
USER_READ_EMOTES = 'user:read:emotes' USER_READ_EMOTES = Literal['user:read:emotes']
USER_READ_FOLLOWS = 'user:read:follows' USER_READ_FOLLOWS = Literal['user:read:follows']
USER_READ_MODERATED_CHANNELS = 'user:read:moderated_channels' USER_READ_MODERATED_CHANNELS = Literal['user:read:moderated_channels']
USER_READ_SUBSCRIPTIONS = 'user:read:subscriptions' USER_READ_SUBSCRIPTIONS = Literal['user:read:subscriptions']
USER_MANAGE_WHISPERS = 'user:manage:whispers' USER_MANAGE_WHISPERS = Literal['user:manage:whispers']
USER_BOT = 'user:bot' USER_BOT = Literal['user:bot']
USER_READ_CHAT = 'user:read:chat' USER_READ_CHAT = Literal['user:read:chat']
USER_WRITE_CHAT = 'user:write:chat' USER_WRITE_CHAT = Literal['user:write:chat']
# Chat # Chat
CHAT_EDIT = 'chat:edit' CHAT_EDIT = Literal['chat:edit']
CHAT_READ = 'chat:read' CHAT_READ = Literal['chat:read']
# Whispers # Whispers
WHISPERS_READ = 'whispers:read' WHISPERS_READ = Literal['whispers:read']
WHISPERS_EDIT = 'whispers:edit' WHISPERS_EDIT = Literal['whispers:edit']
type Any = Literal[ Any = (
'analytics:read:extensions', ANALYTICS_READ_EXTENSIONS
'analytics:read:games', | ANALYTICS_READ_GAMES
'bits:read', | BITS_READ
'channel:manage:ads', | CHANNEL_MANAGE_ADS
'channel:read:ads', | CHANNEL_READ_ADS
'channel:manage:broadcast', | CHANNEL_MANAGE_BROADCAST
'channel:read:charity', | CHANNEL_READ_CHARITY
'channel:edit:commercial', | CHANNEL_EDIT_COMMERCIAL
'channel:read:editors', | CHANNEL_READ_EDITORS
'channel:manage:extensions', | CHANNEL_MANAGE_EXTENSIONS
'channel:read:goals', | CHANNEL_READ_GOALS
'channel:read:guest_star', | CHANNEL_READ_GUEST_STAR
'channel:manage:guest_star', | CHANNEL_MANAGE_GUEST_STAR
'channel:read:hype_train', | CHANNEL_READ_HYPE_TRAIN
'channel:manage:moderators', | CHANNEL_MANAGE_MODERATORS
'channel:read:polls', | CHANNEL_READ_POLLS
'channel:manage:polls', | CHANNEL_MANAGE_POLLS
'channel:read:predictions', | CHANNEL_READ_PREDICTIONS
'channel:manage:predictions', | CHANNEL_MANAGE_PREDICTIONS
'channel:manage:raids', | CHANNEL_MANAGE_RAIDS
'channel:read:redemptions', | CHANNEL_READ_REDEMPTIONS
'channel:manage:redemptions', | CHANNEL_MANAGE_REDEMPTIONS
'channel:manage:schedule', | CHANNEL_MANAGE_SCHEDULE
'channel:read:stream_key', | CHANNEL_READ_STREAM_KEY
'channel:read:subscriptions', | CHANNEL_READ_SUBSCRIPTIONS
'channel:manage:videos', | CHANNEL_MANAGE_VIDEOS
'channel:read:vips', | CHANNEL_READ_VIPS
'channel:manage:vips', | CHANNEL_MANAGE_VIPS
'channel:bot', | CHANNEL_BOT
'channel:moderate', | CHANNEL_MODERATE
'clips:edit', | CLIPS_EDIT
'moderation:read', | MODERATION_READ
'moderator:manage:announcements', | MODERATOR_MANAGE_ANNOUNCEMENTS
'moderator:manage:automod', | MODERATOR_MANAGE_AUTOMOD
'moderator:read:automod_settings', | MODERATOR_READ_AUTOMOD_SETTINGS
'moderator:manage:automod_settings', | MODERATOR_MANAGE_AUTOMOD_SETTINGS
'moderator:manage:banned_users', | MODERATOR_MANAGE_BANNED_USERS
'moderator:read:blocked_terms', | MODERATOR_READ_BLOCKED_TERMS
'moderator:manage:blocked_terms', | MODERATOR_MANAGE_BLOCKED_TERMS
'moderator:manage:chat_messages', | MODERATOR_MANAGE_CHAT_MESSAGES
'moderator:read:chat_settings', | MODERATOR_READ_CHAT_SETTINGS
'moderator:manage:chat_settings', | MODERATOR_MANAGE_CHAT_SETTINGS
'moderator:read:chatters', | MODERATOR_READ_CHATTERS
'moderator:read:followers', | MODERATOR_READ_FOLLOWERS
'moderator:read:guest_star', | MODERATOR_READ_GUEST_STAR
'moderator:manage:guest_star', | MODERATOR_MANAGE_GUEST_STAR
'moderator:read:shield_mode', | MODERATOR_READ_SHIELD_MODE
'moderator:manage:shield_mode', | MODERATOR_MANAGE_SHIELD_MODE
'moderator:read:shoutouts', | MODERATOR_READ_SHOUTOUTS
'moderator:manage:shoutouts', | MODERATOR_MANAGE_SHOUTOUTS
'moderator:read:unban_requests', | MODERATOR_READ_UNBAN_REQUESTS
'moderator:manage:unban_requests', | MODERATOR_MANAGE_UNBAN_REQUESTS
'moderator:read:warnings', | MODERATOR_READ_WARNINGS
'moderator:manage:warnings', | MODERATOR_MANAGE_WARNINGS
'user:edit', | USER_EDIT
'user:edit:follows', | USER_EDIT_FOLLOWS
'user:read:blocked_users', | USER_READ_BLOCKED_USERS
'user:manage:blocked_users', | USER_MANAGE_BLOCKED_USERS
'user:read:broadcast', | USER_READ_BROADCAST
'user:manage:chat_color', | USER_MANAGE_CHAT_COLOR
'user:read:email', | USER_READ_EMAIL
'user:read:emotes', | USER_READ_EMOTES
'user:read:follows', | USER_READ_FOLLOWS
'user:read:moderated_channels', | USER_READ_MODERATED_CHANNELS
'user:read:subscriptions', | USER_READ_SUBSCRIPTIONS
'user:manage:whispers', | USER_MANAGE_WHISPERS
'user:bot', | USER_BOT
'user:read:chat', | USER_READ_CHAT
'user:write:chat', | USER_WRITE_CHAT
'chat:edit', | CHAT_EDIT
'chat:read', | CHAT_READ
'whispers:read', | WHISPERS_READ
'whispers:edit', | WHISPERS_EDIT
] )