selena/modules/social/twitch.py

128 lines
5.5 KiB
Python
Raw Normal View History

import discord
from discord import app_commands
import sqlite3
import aiohttp
import asyncio
from config import config
from datetime import datetime, timedelta
class Twitch:
def __init__(self, bot):
self.bot = bot
self.db_path = 'data/selena.db'
self.client_id = config['TWITCH_CLIENT_ID']
self.client_secret = config['TWITCH_CLIENT_SECRET']
self._init_db()
self.live_channels = set()
self.token = None
self.token_expiry = datetime.utcnow()
def _init_db(self):
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS twitch_channels (
channel_name TEXT PRIMARY KEY
)
''')
conn.commit()
async def fetch_twitch_token(self):
if self.token and datetime.utcnow() < self.token_expiry:
return self.token
async with aiohttp.ClientSession() as session:
async with session.post('https://id.twitch.tv/oauth2/token', params={
'client_id': self.client_id,
'client_secret': self.client_secret,
'grant_type': 'client_credentials'
}) as response:
data = await response.json()
self.token = data['access_token']
self.token_expiry = datetime.utcnow() + timedelta(seconds=data['expires_in'])
return self.token
async def fetch_twitch_channel(self, channel_name):
token = await self.fetch_titch_token()
async with aiohttp.ClientSession() as session:
async with session.get('https://api.twitch.tv/helix/users', headers={
'Client-ID': self.client_id,
'Authorization': f'Bearer {token}'
}, params={'login': channel_name}) as response:
data = await response.json()
if data['data']:
return data['data'][0]
return None
async def fetch_stream_status(self, user_id):
token = await self.fetch_twitch_token()
async with aiohttp.ClientSession() as session:
async with session.get('https://api.twitch.tv/helix/streams', headers={
'Client-ID': self.client_id,
'Authorization': f'Bearer {token}'
}, params={'user_id': user_id}) as response:
data = await response.json()
if data['data']:
return data['data'][0]
return None
async def check_live_status(self):
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute('SELECT channel_name FROM twitch_channels')
channels = cursor.fetchall()
for (channel_name,) in channels:
channel = await self.fetch_twitch_channel(channel_name)
if channel:
stream = await self.fetch_stream_status(channel['id'])
if stream and channel_name not in self.live_channels:
self.live_channels.add(channel_name)
discord_channel = self.bot.get_channel(config['DISCORD_CHANNEL_ID'])
await discord_channel.send(f'{channel_name} is now live on Twitch!')
elif not stream and channel_name in self.live_channels:
self.live_channels.remove(channel_name)
@app_commands.command(name='add_twitch_channel', description='Follow a new Twitch channel')
async def add_twitch_channel(self, interaction: discord.Interaction, channel_name: str):
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute('INSERT OR IGNORE INTO twitch_channels (channel_name) VALUES (?)', (channel_name,))
conn.commit()
await interaction.response.send_message(f'Added {channel_name} to the followed Twitch channels.')
@app_commands.command(name='remove_twitch_channel', description='Unfollow a Twitch channel')
async def remove_twitch_channel(self, interaction: discord.Interaction, channel_name: str):
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute('DELETE FROM twitch_channels WHERE channel_name = ?', (channel_name,))
conn.commit()
await interaction.response.send_message(f'Removed {channel_name} from the followed Twitch channels.')
@app_commands.command(name='check_twitch_channel', description='Check if a Twitch channel is live')
async def check_twitch_channel(self, interaction: discord.Interaction, channel_name: str):
channel = await self.fetch_twitch_channel(channel_name)
if channel:
stream = await self.fetch_stream_status(channel['id'])
if stream:
await interaction.response.send_message(f'{channel_name} is currently live on Twitch!')
else:
await interaction.response.send_message(f'{channel_name} is not live on Twitch.')
else:
await interaction.response.send_message(f'Could not find Twitch channel: {channel_name}')
async def start_checking_live_status(self):
while True:
await self.check_live_status()
await asyncio.sleep(60)
def setup(self, tree):
tree.add_command(self.add_twitch_channel)
tree.add_command(self.remove_twitch_channel)
tree.add_command(self.check_twitch_channel)
def setup(bot):
bot.tree.add_cog(Twitch(bot))