1
- # SPDX-FileCopyrightText: 2023 DJDevon3
1
+ # SPDX-FileCopyrightText: 2024 DJDevon3
2
2
# SPDX-License-Identifier: MIT
3
3
# Coded for Circuit Python 8.2.x
4
- # Twitch_API_Example
4
+ """Twitch API Example"""
5
+ # pylint: disable=import-error
5
6
6
7
import os
7
- import ssl
8
8
import time
9
9
10
- import socketpool
10
+ import adafruit_connection_manager
11
11
import wifi
12
12
13
13
import adafruit_requests
14
14
15
- # Initialize WiFi Pool (There can be only 1 pool & top of script)
16
- pool = socketpool .SocketPool (wifi .radio )
17
-
18
15
# Twitch Developer Account & oauth App Required:
19
16
# Visit https://dev.twitch.tv/console to create an app
20
-
21
- # Ensure these are in secrets.py or settings.toml
22
- # "Twitch_ClientID": "Your Developer APP ID Here",
23
- # "Twitch_Client_Secret": "APP ID secret here",
24
- # "Twitch_UserID": "Your Twitch UserID here",
17
+ # Ensure these are in settings.toml
18
+ # TWITCH_CLIENT_ID = "Your Developer APP ID Here"
19
+ # TWITCH_CLIENT_SECRET = "APP ID secret here"
20
+ # TWITCH_USER_ID = "Your Twitch UserID here"
25
21
26
22
# Get WiFi details, ensure these are setup in settings.toml
27
23
ssid = os .getenv ("CIRCUITPY_WIFI_SSID" )
28
24
password = os .getenv ("CIRCUITPY_WIFI_PASSWORD" )
29
- twitch_client_id = os .getenv ("Twitch_ClientID " )
30
- twitch_client_secret = os .getenv ("Twitch_Client_Secret " )
25
+ TWITCH_CID = os .getenv ("TWITCH_CLIENT_ID " )
26
+ TWITCH_CS = os .getenv ("TWITCH_CLIENT_SECRET " )
31
27
# For finding your Twitch User ID
32
28
# https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/
33
- twitch_user_id = os .getenv ("Twitch_UserID" ) # User ID you want endpoints from
29
+ TWITCH_UID = os .getenv ("TWITCH_USER_ID" )
34
30
35
- # Time between API refreshes
31
+ # API Polling Rate
36
32
# 900 = 15 mins, 1800 = 30 mins, 3600 = 1 hour
37
- sleep_time = 900
33
+ SLEEP_TIME = 900
34
+
35
+ # Set DEBUG to True for full JSON response.
36
+ # STREAMER WARNING: Credentials will be viewable
37
+ DEBUG = False
38
+
39
+ # Initalize Wifi, Socket Pool, Request Session
40
+ pool = adafruit_connection_manager .get_radio_socketpool (wifi .radio )
41
+ ssl_context = adafruit_connection_manager .get_radio_ssl_context (wifi .radio )
42
+ requests = adafruit_requests .Session (pool , ssl_context )
38
43
39
44
40
- # Converts seconds to minutes/hours/days
41
45
def time_calc (input_time ):
46
+ """Converts seconds to minutes/hours/days"""
42
47
if input_time < 60 :
43
48
return f"{ input_time :.0f} seconds"
44
49
if input_time < 3600 :
@@ -48,42 +53,44 @@ def time_calc(input_time):
48
53
return f"{ input_time / 60 / 60 / 24 :.1f} days"
49
54
50
55
56
+ def _format_datetime (datetime ):
57
+ """F-String formatted struct time conversion"""
58
+ return (
59
+ f"{ datetime .tm_mon :02} /"
60
+ + f"{ datetime .tm_mday :02} /"
61
+ + f"{ datetime .tm_year :02} "
62
+ + f"{ datetime .tm_hour :02} :"
63
+ + f"{ datetime .tm_min :02} :"
64
+ + f"{ datetime .tm_sec :02} "
65
+ )
66
+
67
+
51
68
# First we use Client ID & Client Secret to create a token with POST
52
69
# No user interaction is required for this type of scope (implicit grant flow)
53
70
twitch_0auth_header = {"Content-Type" : "application/x-www-form-urlencoded" }
54
71
TWITCH_0AUTH_TOKEN = "https://id.twitch.tv/oauth2/token"
55
72
56
- # Connect to Wi-Fi
57
- print ("\n ===============================" )
58
- print ("Connecting to WiFi..." )
59
- requests = adafruit_requests .Session (pool , ssl .create_default_context ())
60
- while not wifi .radio .connected :
61
- try :
62
- wifi .radio .connect (ssid , password )
63
- except ConnectionError as e :
64
- print ("Connection Error:" , e )
65
- print ("Retrying in 10 seconds" )
66
- time .sleep (10 )
67
- print ("Connected!\n " )
68
-
69
73
while True :
74
+ # Connect to Wi-Fi
75
+ print ("\n Connecting to WiFi..." )
76
+ while not wifi .radio .ipv4_address :
77
+ try :
78
+ wifi .radio .connect (ssid , password )
79
+ except ConnectionError as e :
80
+ print ("❌ Connection Error:" , e )
81
+ print ("Retrying in 10 seconds" )
82
+ print ("✅ Wifi!" )
83
+
70
84
try :
71
- # ----------------------------- POST FOR BEARER TOKEN -----------------------
72
- print (
73
- "Attempting Bearer Token Request!"
74
- ) # ---------------------------------------
75
- # Print Request to Serial
76
- debug_bearer_request = (
77
- False # STREAMER WARNING: your client secret will be viewable
78
- )
79
- if debug_bearer_request :
80
- print ("Full API GET URL: " , TWITCH_0AUTH_TOKEN )
81
- print ("===============================" )
85
+ # ------------- POST FOR BEARER TOKEN -----------------
86
+ print (" | Attempting Bearer Token Request!" )
87
+ if DEBUG :
88
+ print (f"Full API GET URL: { TWITCH_0AUTH_TOKEN } " )
82
89
twitch_0auth_data = (
83
90
"&client_id="
84
- + twitch_client_id
91
+ + TWITCH_CID
85
92
+ "&client_secret="
86
- + twitch_client_secret
93
+ + TWITCH_CS
87
94
+ "&grant_type=client_credentials"
88
95
)
89
96
@@ -95,70 +102,79 @@ def time_calc(input_time):
95
102
twitch_0auth_json = twitch_0auth_response .json ()
96
103
twitch_access_token = twitch_0auth_json ["access_token" ]
97
104
except ConnectionError as e :
98
- print ("Connection Error:" , e )
105
+ print (f "Connection Error: { e } " )
99
106
print ("Retrying in 10 seconds" )
107
+ print (" | 🔑 Token Authorized!" )
100
108
101
- # Print Response to Serial
102
- debug_bearer_response = (
103
- False # STREAMER WARNING: your client secret will be viewable
104
- )
105
- if debug_bearer_response :
106
- print ("JSON Dump: " , twitch_0auth_json )
107
- print ("Header: " , twitch_0auth_header )
108
- print ("Access Token: " , twitch_access_token )
109
+ # STREAMER WARNING: your client secret will be viewable
110
+ if DEBUG :
111
+ print (f"JSON Dump: { twitch_0auth_json } " )
112
+ print (f"Header: { twitch_0auth_header } " )
113
+ print (f"Access Token: { twitch_access_token } " )
109
114
twitch_token_type = twitch_0auth_json ["token_type" ]
110
- print ("Token Type: " , twitch_token_type )
115
+ print (f "Token Type: { twitch_token_type } " )
111
116
112
- print ("Board Uptime: " , time_calc (time .monotonic ()))
113
117
twitch_token_expiration = twitch_0auth_json ["expires_in" ]
114
- print (" Token Expires in: " , time_calc (twitch_token_expiration ))
118
+ print (f" | Token Expires in: { time_calc (twitch_token_expiration )} " )
115
119
116
- # ----------------------------- GET DATA -------------------------------------
120
+ # ----------------------------- GET DATA --------------------
117
121
# Bearer token is refreshed every time script runs :)
118
122
# Twitch sets token expiration to about 64 days
119
123
# Helix is the name of the current Twitch API
120
124
# Now that we have POST bearer token we can do a GET for data
121
- # ----------------------------------------------------------------------------
125
+ # -----------------------------------------------------------
122
126
twitch_header = {
123
127
"Authorization" : "Bearer " + twitch_access_token + "" ,
124
- "Client-Id" : "" + twitch_client_id + "" ,
128
+ "Client-Id" : "" + TWITCH_CID + "" ,
125
129
}
126
130
TWITCH_FOLLOWERS_SOURCE = (
127
131
"https://api.twitch.tv/helix/channels"
128
132
+ "/followers?"
129
133
+ "broadcaster_id="
130
- + twitch_user_id
134
+ + TWITCH_UID
131
135
)
132
- print (
133
- "\n Attempting to GET TWITCH Stats!"
134
- ) # ------------------------------------------------
135
- print ("===============================" )
136
- twitch_followers_response = requests .get (
136
+ print (" | Attempting to GET Twitch JSON!" )
137
+ twitch_response = requests .get (
137
138
url = TWITCH_FOLLOWERS_SOURCE , headers = twitch_header
138
139
)
139
140
try :
140
- twitch_followers_json = twitch_followers_response .json ()
141
+ twitch_json = twitch_response .json ()
141
142
except ConnectionError as e :
142
- print ("Connection Error:" , e )
143
+ print (f "Connection Error: { e } " )
143
144
print ("Retrying in 10 seconds" )
144
145
145
- # Print Response to Serial
146
- debug_bearer_response = (
147
- False # STREAMER WARNING: your bearer token will be viewable
148
- )
149
- if debug_bearer_response :
150
- print ("Full API GET URL: " , TWITCH_FOLLOWERS_SOURCE )
151
- print ("Header: " , twitch_header )
152
- print ("JSON Full Response: " , twitch_followers_json )
153
-
154
- twitch_followers = twitch_followers_json ["total" ]
155
- print ("Followers: " , twitch_followers )
156
- print ("Finished!" )
157
- print ("Next Update in: " , time_calc (sleep_time ))
146
+ if DEBUG :
147
+ print (f" | Full API GET URL: { TWITCH_FOLLOWERS_SOURCE } " )
148
+ print (f" | Header: { twitch_header } " )
149
+ print (f" | JSON Full Response: { twitch_json } " )
150
+
151
+ if "status" in twitch_json :
152
+ twitch_error_status = twitch_json ["status" ]
153
+ print (f"❌ Status: { twitch_error_status } " )
154
+
155
+ if "error" in twitch_json :
156
+ twitch_error = twitch_json ["error" ]
157
+ print (f"❌ Error: { twitch_error } " )
158
+
159
+ if "message" in twitch_json :
160
+ twitch_error_msg = twitch_json ["message" ]
161
+ print (f"❌ Message: { twitch_error_msg } " )
162
+
163
+ if "total" in twitch_json :
164
+ print (" | ✅ Twitch JSON!" )
165
+ twitch_followers = twitch_json ["total" ]
166
+ print (f" | | Followers: { twitch_followers } " )
167
+
168
+ twitch_response .close ()
169
+ print ("✂️ Disconnected from Twitch API" )
170
+
171
+ print ("\n Finished!" )
172
+ print (f"Board Uptime: { time_calc (time .monotonic ())} " )
173
+ print (f"Next Update: { time_calc (SLEEP_TIME )} " )
158
174
print ("===============================" )
159
175
160
176
except (ValueError , RuntimeError ) as e :
161
- print ("Failed to get data, retrying\n " , e )
177
+ print (f "Failed to get data, retrying\n { e } " )
162
178
time .sleep (60 )
163
- continue
164
- time .sleep (sleep_time )
179
+ break
180
+ time .sleep (SLEEP_TIME )
0 commit comments