You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

78 lines
3.2 KiB

import datetime
import hashlib
import json
import os
import random
import string
import dateutil.parser
from requests_futures.sessions import FuturesSession
TOPIC_URLS = {
'streams': 'https://api.twitch.tv/helix/streams?user_id={0}',
'followers': 'https://api.twitch.tv/helix/users/follows?first=1&to_id={0}',
}
class Twitch(object):
@classmethod
def subscribe(cls, app, subscriptions, lease_time):
def read_leases(lease_file):
result = dict(
streams=dict(secret=None, valid_until=None, request_hash=None),
followers=dict(secret=None, valid_until=None, request_hash=None))
try:
with open(lease_file) as f:
leases = json.load(f)
except IOError:
return result
else:
result.update(leases)
return result
def write_leases(lease_file, leases):
with open(lease_file, 'w') as f:
json.dump(leases, f, indent=4, sort_keys=True)
def generate_secret(length):
pool = string.ascii_letters + string.digits
return ''.join(random.SystemRandom().choice(pool) for _ in range(length))
def sub(topic, secret):
client_id = os.getenv('TWITCH_CLIENT_ID')
channel_id = os.getenv('TWITCH_CHANNEL_ID')
callback_url = os.getenv('CALLBACK_URL')
session = FuturesSession()
url = 'https://api.twitch.tv/helix/webhooks/hub'
headers = {'Client-ID': client_id}
data = {
'hub.mode': 'subscribe',
'hub.topic': TOPIC_URLS[topic].format(channel_id),
'hub.callback': callback_url,
'hub.lease_seconds': lease_time,
'hub.secret': secret,
}
h = '{0[hub.mode]}|{0[hub.topic]}|{0[hub.lease_seconds]}'.format(data)
request_hash = hashlib.sha256(h.encode()).hexdigest()
return session.post(url, headers=headers, data=data), request_hash
with app.app_context():
app.logger.info('Refreshing Twitch subscriptions')
lease_file = os.getenv('LEASE_FILE')
leases = read_leases(lease_file)
for topic, lease in leases.items():
if not lease['secret'] or not lease['valid_until']:
remaining = 0
if lease['valid_until']:
valid_until = dateutil.parser.parse(lease['valid_until'])
remaining = (valid_until - datetime.datetime.utcnow()).total_seconds()
if remaining < 3600:
app.logger.info('Subscription "%s" expired, re-requesting', topic)
secret = generate_secret(32)
valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=lease_time)
request, request_hash = sub(topic, secret)
if request.result().ok:
lease['secret'] = secret
lease['valid_until'] = valid_until.isoformat()
lease['request_hash'] = request_hash
write_leases(lease_file, leases)
subscriptions.update(leases)