102 lines
3.9 KiB
Python
102 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
import json
|
|
import os
|
|
import requests
|
|
|
|
# The target Twitch streamer username
|
|
TWITCH_USERNAME = "SumGuyV5"
|
|
|
|
def load_secrets(filepath="twitch_secrets.json"):
|
|
"""Loads client credentials and potential manual token from JSON file."""
|
|
if not os.path.exists(filepath):
|
|
raise FileNotFoundError(f"Missing credential file: '{filepath}'")
|
|
|
|
with open(filepath, "r") as file:
|
|
secrets = json.load(file)
|
|
|
|
if "client_id" not in secrets or "client_secret" not in secrets:
|
|
raise KeyError("JSON file must contain 'client_id' and 'client_secret'.")
|
|
|
|
return secrets["client_id"], secrets["client_secret"], secrets.get("manual_token")
|
|
|
|
def get_app_access_token(client_id, client_secret):
|
|
"""Generates an App Access Token using the correct Twitch ID server."""
|
|
auth_url = "https://twitch.tv" # FIXED: Correct auth endpoint
|
|
payload = {
|
|
"client_id": client_id,
|
|
"client_secret": client_secret,
|
|
"grant_type": "client_credentials"
|
|
}
|
|
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
|
|
|
response = requests.post(auth_url, data=payload, headers=headers)
|
|
response.raise_for_status()
|
|
return response.json()["access_token"]
|
|
|
|
def get_user_id(username, headers):
|
|
"""Retrieves the unique numerical Twitch User ID from Helix."""
|
|
url = f"https://twitch.tv{username}" # FIXED: Endpoint & parameter
|
|
response = requests.get(url, headers=headers)
|
|
response.raise_for_status()
|
|
data = response.json().get("data")
|
|
if data and len(data) > 0:
|
|
return data[0]["id"] # FIXED: Helix data array returns user dictionaries
|
|
else:
|
|
raise ValueError(f"Twitch user '{username}' not found.")
|
|
|
|
def get_channel_vods(user_id, headers, limit=10):
|
|
"""Fetches past broadcasts (VODs) using valid Helix syntax."""
|
|
# FIXED: Restructured URL to use correct endpoint and standard query parameters
|
|
url = f"https://twitch.tv{user_id}&type=archive&first={limit}"
|
|
response = requests.get(url, headers=headers)
|
|
response.raise_for_status()
|
|
return response.json().get("data", [])
|
|
|
|
def main():
|
|
try:
|
|
# 1. Load credentials from external JSON file
|
|
client_id, client_secret, manual_token = load_secrets("twitch_secrets.json")
|
|
|
|
# 2. Assign or generate OAuth Access Token
|
|
if manual_token:
|
|
print("Using manual access token from JSON config file...")
|
|
access_token = manual_token
|
|
else:
|
|
print("No manual token found. Attempting to contact Twitch Auth Server...")
|
|
access_token = get_app_access_token(client_id, client_secret)
|
|
|
|
# 3. Setup Headers required by Twitch Helix API
|
|
headers = {
|
|
"Client-ID": client_id,
|
|
"Authorization": f"Bearer {access_token}"
|
|
}
|
|
|
|
# 4. Translate Username to User ID
|
|
user_id = get_user_id(TWITCH_USERNAME, headers)
|
|
print(f"Successfully retrieved ID for {TWITCH_USERNAME}: {user_id}\n")
|
|
|
|
# 5. Fetch and Print VOD details
|
|
vods = get_channel_vods(user_id, headers, limit=5)
|
|
|
|
if not vods:
|
|
print(f"No VODs found for {TWITCH_USERNAME}.")
|
|
return
|
|
|
|
print(f"--- Latest VODs for {TWITCH_USERNAME} ---")
|
|
for vod in vods:
|
|
print(f"Title: {vod['title']}")
|
|
print(f"URL: {vod['url']}")
|
|
print(f"Published At: {vod['published_at']}")
|
|
print(f"Duration: {vod['duration']}")
|
|
print(f"Views: {vod['view_count']}")
|
|
print("-" * 40)
|
|
|
|
except (FileNotFoundError, KeyError) as config_err:
|
|
print(f"Configuration Error: {config_err}")
|
|
except requests.exceptions.HTTPError as err:
|
|
print(f"HTTP Error detail: {err.response.text if err.response else err}")
|
|
except Exception as e:
|
|
print(f"An error occurred: {e}")
|
|
|
|
if __name__ == "__main__":
|
|
main() |