Skip to content

Commit 68ccfb7

Browse files
authored
Merge pull request #34 from anxdpanic/dev
Addition of Twitch Helix API
2 parents fd481e5 + afb9303 commit 68ccfb7

16 files changed

Lines changed: 260 additions & 40 deletions

File tree

resources/lib/twitch/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# -*- encoding: utf-8 -*-
22

3-
VERSION = '1.3.0'
3+
import xbmcaddon
4+
5+
VERSION = xbmcaddon.Addon('script.module.python.twitch').getAddonInfo('version')
46
CLIENT_ID = ''
7+
CLIENT_SECRET = ''
58
OAUTH_TOKEN = ''
9+
APP_TOKEN = ''

resources/lib/twitch/api/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22

33
from twitch.api import v5 # V5 is deprecated and will be removed entirely on 2/14/18
44
from twitch.api import v5 as default
5+
from twitch.api import helix
56

6-
__all__ = ['v5', 'default']
7+
__all__ = ['v5', 'default', 'helix']
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# -*- encoding: utf-8 -*-
2+
# https://dev.twitch.tv/docs/
3+
4+
from twitch.api.helix import users # NOQA
5+
from twitch.api.helix import streams # NOQA
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# -*- encoding: utf-8 -*-
2+
# https://dev.twitch.tv/docs/api/reference
3+
4+
from twitch import keys
5+
from twitch.api.parameters import Cursor, Language, StreamTypes
6+
from twitch.queries import HelixQuery as Qry
7+
from twitch.queries import query
8+
9+
10+
# required scope: none
11+
@query
12+
def get_streams(community_id=list(), game_id=list(), user_id=list(),
13+
user_login=list(), stream_type=StreamTypes.ALL, language=list(),
14+
after='MA==', first=20, use_app_token=False):
15+
q = Qry('streams', use_app_token=use_app_token)
16+
q.add_param(keys.AFTER, Cursor.validate(after), 'MA==')
17+
q.add_param(keys.FIRST, first, 20)
18+
q.add_param(keys.COMMUNITY_ID, community_id, list())
19+
q.add_param(keys.GAME_ID, game_id, list())
20+
q.add_param(keys.USER_ID, user_id, list())
21+
q.add_param(keys.USER_LOGIN, user_login, list())
22+
q.add_param(keys.TYPE, StreamTypes.validate(stream_type), StreamTypes.ALL)
23+
if isinstance(language, list):
24+
_language = [lang for lang in language if lang in Language.valid()]
25+
q.add_param(keys.LANGUAGE, _language, list())
26+
else:
27+
q.add_param(keys.LANGUAGE, Language.validate(language), '')
28+
29+
return q
30+
31+
32+
# required scope: none
33+
@query
34+
def get_metadata(community_id=list(), game_id=list(), user_id=list(),
35+
user_login=list(), stream_type=StreamTypes.ALL, language=list(),
36+
after='MA==', first=20, use_app_token=False):
37+
q = Qry('streams/metadata', use_app_token=use_app_token)
38+
q.add_param(keys.AFTER, Cursor.validate(after), 'MA==')
39+
q.add_param(keys.FIRST, first, 20)
40+
q.add_param(keys.COMMUNITY_ID, community_id, list())
41+
q.add_param(keys.GAME_ID, game_id, list())
42+
q.add_param(keys.USER_ID, user_id, list())
43+
q.add_param(keys.USER_LOGIN, user_login, list())
44+
q.add_param(keys.TYPE, StreamTypes.validate(stream_type), StreamTypes.ALL)
45+
if isinstance(language, list):
46+
_language = [lang for lang in language if lang in Language.valid()]
47+
q.add_param(keys.LANGUAGE, _language, list())
48+
else:
49+
q.add_param(keys.LANGUAGE, Language.validate(language), '')
50+
51+
return q
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# -*- encoding: utf-8 -*-
2+
# https://dev.twitch.tv/docs/api/reference
3+
4+
from twitch import keys, methods
5+
from twitch.api.parameters import Cursor
6+
from twitch.queries import HelixQuery as Qry
7+
from twitch.queries import query
8+
9+
10+
# optional scope: user:read:email
11+
@query
12+
def get_users(user_id=list(), user_login=list(), use_app_token=False):
13+
use_token = (not user_id and not user_login)
14+
use_app_token = False if use_token else use_app_token
15+
q = Qry('users', use_app_token=use_app_token)
16+
q.add_param(keys.ID, user_id, list())
17+
q.add_param(keys.LOGIN, user_login, list())
18+
return q
19+
20+
21+
# required scope: none
22+
@query
23+
def get_follows(from_id='', to_id='', after='MA==', before='MA==', first=20, use_app_token=False):
24+
q = Qry('users/follows', use_app_token=use_app_token)
25+
q.add_param(keys.FROM_ID, from_id, '')
26+
q.add_param(keys.TO_ID, to_id, '')
27+
q.add_param(keys.AFTER, Cursor.validate(after), 'MA==')
28+
q.add_param(keys.BEFORE, Cursor.validate(before), 'MA==')
29+
q.add_param(keys.FIRST, first, 20)
30+
return q
31+
32+
33+
# required scope: user:edit
34+
@query
35+
def put_users(description):
36+
q = Qry('users', method=methods.PUT)
37+
q.add_param(keys.DESCRIPTION, description, '')
38+
return q

resources/lib/twitch/api/parameters.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ class StreamType(_Parameter):
8484
_valid = [LIVE, PLAYLIST, ALL]
8585

8686

87+
class StreamTypes(_Parameter):
88+
LIVE = 'live'
89+
VODCAST = 'vodcast'
90+
ALL = 'all'
91+
92+
_valid = [LIVE, VODCAST, ALL]
93+
94+
8795
class Platform(_Parameter):
8896
XBOX_ONE = 'xbox_one'
8997
PS4 = 'ps4'

resources/lib/twitch/keys.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
string constants
66
"""
77

8+
AFTER = 'after'
89
ALLOW_AUDIO_ONLY = 'allow_audio_only'
910
ALLOW_SOURCE = 'allow_source'
1011
ALLOW_SPECTRE = 'allow_spectre'
1112
AVATAR_IMAGE = 'avatar_image'
13+
BEFORE = 'before'
1214
BROADCAST_TYPE = 'broadcast_type'
1315
BROADCASTER_LANGUAGE = 'broadcaster_language'
1416
BROADCASTS = 'broadcasts'
@@ -36,8 +38,11 @@
3638
EMOTESETS = 'emotesets'
3739
ERROR = 'error'
3840
FEATURED = 'featured'
41+
FIRST = 'first'
3942
FOLLOWS = 'follows'
43+
FROM_ID = 'from_id'
4044
GAME = 'game'
45+
GAME_ID = 'game_id'
4146
HLS = 'hls'
4247
ID = 'id'
4348
IDENTIFIER = 'identifier'
@@ -46,6 +51,7 @@
4651
LANGUAGE = 'language'
4752
LIMIT = 'limit'
4853
LIVE = 'live'
54+
LOGIN = 'login'
4955
MESSAGE = 'message'
5056
NAME = 'name'
5157
NAUTH = 'nauth'
@@ -73,6 +79,7 @@
7379
TARGET_ID = 'target_id'
7480
TEAM = 'team'
7581
TITLE = 'title'
82+
TO_ID = 'to_id'
7683
TOKEN = 'token'
7784
TRENDING = 'trending'
7885
TYPE = 'type'
@@ -82,6 +89,7 @@
8289
USER_AGENT_STRING = ('Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) '
8390
'Gecko/20100101 Firefox/6.0')
8491
USER_ID = 'user_id'
92+
USER_LOGIN = 'user_login'
8593
UPLOAD_TOKEN = 'upload_token'
8694
VIDEO_ID = 'video_id'
8795
VOD = 'vod'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# -*- encoding: utf-8 -*-
2+
3+
from twitch.oauth import v5 # V5 is deprecated and will be removed entirely on 2/14/18
4+
from twitch.oauth import helix
5+
from twitch.oauth import v5 as default
6+
from twitch.oauth import clients
7+
8+
__all__ = ['v5', 'default', 'helix', 'clients']
Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
# -*- encoding: utf-8 -*-
22

3-
from twitch import CLIENT_ID
4-
from twitch import scopes
3+
from twitch import CLIENT_ID, CLIENT_SECRET
4+
55
from six.moves.urllib_parse import urlsplit, urlencode
66

77

88
class MobileClient:
9-
_auth_base_url = 'https://api.twitch.tv/kraken/oauth2/authorize'
9+
_base_url = 'https://api.twitch.tv/kraken/oauth2/{0}'
1010

11-
def __init__(self, client_id=''):
11+
def __init__(self, client_id='', client_secret=''):
1212
self.client_id = client_id if client_id else CLIENT_ID
13+
self.client_secret = client_secret if client_secret else CLIENT_SECRET
1314

1415
def prepare_request_uri(self, redirect_uri='http://localhost:3000/', scope=list(), force_verify=False, state=''):
1516
params = {'response_type': 'token',
@@ -19,7 +20,22 @@ def prepare_request_uri(self, redirect_uri='http://localhost:3000/', scope=list(
1920
'force_verify': str(force_verify).lower(),
2021
'state': state}
2122
params = urlencode(params)
22-
url = '{base_uri}?{params}'.format(base_uri=self._auth_base_url, params=params)
23+
url = '{base_uri}?{params}'.format(base_uri=self._base_url.format('authorize'), params=params)
24+
return url
25+
26+
def prepare_token_uri(self, scope=list()):
27+
params = {'client_id': self.client_id,
28+
'client_secret': self.client_secret,
29+
'scope': ' '.join(scope)}
30+
params = urlencode(params)
31+
url = '{base_uri}?{params}'.format(base_uri=self._base_url.format('token'), params=params)
32+
return url
33+
34+
def prepare_revoke_uri(self, token):
35+
params = {'client_id': self.client_id,
36+
'token': token}
37+
params = urlencode(params)
38+
url = '{base_uri}?{params}'.format(base_uri=self._base_url.format('revoke'), params=params)
2339
return url
2440

2541
@staticmethod
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# -*- encoding: utf-8 -*-
2+
3+
from twitch.oauth.helix import scopes

0 commit comments

Comments
 (0)