128 lines
5.5 KiB
Python
128 lines
5.5 KiB
Python
|
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))
|