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
78 lines
3.2 KiB
5 years ago
|
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)
|