Update calendar registration to use TV and Limited Input Device flow

This commit is contained in:
ChuckBuilds
2025-04-21 09:24:42 -05:00
parent f4b37d012b
commit c02f80ead7

View File

@@ -5,8 +5,7 @@ from google_auth_oauthlib.flow import InstalledAppFlow
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
import pickle
import urllib.parse
import socket
import requests
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
@@ -20,6 +19,28 @@ def save_credentials(creds, token_path):
with open(token_path, 'wb') as token:
pickle.dump(creds, token)
def get_device_code(client_id, client_secret):
"""Get device code for TV and Limited Input Device flow."""
url = 'https://oauth2.googleapis.com/device/code'
data = {
'client_id': client_id,
'scope': ' '.join(SCOPES)
}
response = requests.post(url, data=data)
return response.json()
def poll_for_token(client_id, client_secret, device_code):
"""Poll for token using device code."""
url = 'https://oauth2.googleapis.com/token'
data = {
'client_id': client_id,
'client_secret': client_secret,
'device_code': device_code,
'grant_type': 'urn:ietf:params:oauth:grant-type:device_code'
}
response = requests.post(url, data=data)
return response.json()
def main():
config = load_config()
calendar_config = config.get('calendar', {})
@@ -43,34 +64,54 @@ def main():
print("1. Go to https://console.cloud.google.com")
print("2. Create a project or select existing project")
print("3. Enable the Google Calendar API")
print("4. Configure the OAuth consent screen")
print("5. Create OAuth 2.0 credentials (Desktop application)")
print("4. Configure the OAuth consent screen (select TV and Limited Input Device)")
print("5. Create OAuth 2.0 credentials (TV and Limited Input Device)")
print("6. Download the credentials and save as credentials.json")
return
# Create the flow using the client secrets file from the Google API Console
flow = InstalledAppFlow.from_client_secrets_file(
creds_file, SCOPES,
redirect_uri='urn:ietf:wg:oauth:2.0:oob' # Use out-of-band flow for headless environment
# Load client credentials
with open(creds_file, 'r') as f:
client_config = json.load(f)
client_id = client_config['installed']['client_id']
client_secret = client_config['installed']['client_secret']
# Get device code
device_info = get_device_code(client_id, client_secret)
print("\nTo authorize this application, visit:")
print(device_info['verification_url'])
print("\nAnd enter the code:")
print(device_info['user_code'])
print("\nWaiting for authorization...")
# Poll for token
while True:
token_info = poll_for_token(client_id, client_secret, device_info['device_code'])
if 'access_token' in token_info:
# Create credentials object
creds = Credentials(
token=token_info['access_token'],
refresh_token=token_info.get('refresh_token'),
token_uri="https://oauth2.googleapis.com/token",
client_id=client_id,
client_secret=client_secret,
scopes=SCOPES
)
# Generate URL for authorization
auth_url, _ = flow.authorization_url(prompt='consent')
print("\nPlease visit this URL to authorize this application:")
print(auth_url)
print("\nAfter authorizing, you will receive a code. Enter that code below:")
code = input("Enter the authorization code: ")
# Exchange the authorization code for credentials
flow.fetch_token(code=code)
creds = flow.credentials
# Save the credentials
save_credentials(creds, token_file)
print(f"\nCredentials saved successfully to {token_file}")
print("You can now run the LED Matrix display with calendar integration!")
break
elif token_info.get('error') == 'authorization_pending':
import time
time.sleep(device_info['interval'])
else:
print(f"\nError during authorization: {token_info.get('error')}")
print("Please try again.")
return
if __name__ == '__main__':
main()