2024-06-21 21:28:05 -04:00
|
|
|
# modules/social/youtube_module.py
|
2024-06-22 08:55:26 -04:00
|
|
|
import asyncio
|
|
|
|
import logging
|
|
|
|
|
2024-06-21 21:28:05 -04:00
|
|
|
import discord
|
|
|
|
from discord import app_commands
|
|
|
|
from googleapiclient.discovery import build
|
2024-06-22 08:55:26 -04:00
|
|
|
|
2024-06-21 21:28:05 -04:00
|
|
|
import config
|
|
|
|
from modules.data.db import get_connection
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class YouTubeModule:
|
|
|
|
def __init__(self, bot):
|
|
|
|
self.bot = bot
|
2024-06-22 08:55:26 -04:00
|
|
|
self.youtube = build("youtube", "v3", developerKey=config.YOUTUBE_API_KEY)
|
2024-06-21 21:28:05 -04:00
|
|
|
self.bot.loop.create_task(self.check_youtube_channels())
|
|
|
|
self.add_commands()
|
|
|
|
|
|
|
|
async def check_youtube_channels(self):
|
|
|
|
while True:
|
|
|
|
conn = get_connection()
|
|
|
|
c = conn.cursor()
|
2024-06-22 08:55:26 -04:00
|
|
|
c.execute(
|
|
|
|
"SELECT youtube_channel_id, discord_channel_id FROM followed_youtube_channels"
|
|
|
|
)
|
2024-06-21 21:28:05 -04:00
|
|
|
followed_channels = c.fetchall()
|
|
|
|
conn.close()
|
|
|
|
|
|
|
|
for youtube_channel_id, discord_channel_id in followed_channels:
|
|
|
|
try:
|
|
|
|
request = self.youtube.channels().list(
|
2024-06-22 08:55:26 -04:00
|
|
|
part="contentDetails", id=youtube_channel_id
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
|
|
|
response = request.execute()
|
2024-06-22 08:55:26 -04:00
|
|
|
if "items" in response and len(response["items"]) > 0:
|
|
|
|
uploads_playlist_id = response["items"][0]["contentDetails"][
|
|
|
|
"relatedPlaylists"
|
|
|
|
]["uploads"]
|
|
|
|
|
2024-06-21 21:28:05 -04:00
|
|
|
request = self.youtube.playlistItems().list(
|
2024-06-22 08:55:26 -04:00
|
|
|
part="snippet", playlistId=uploads_playlist_id, maxResults=1
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
|
|
|
response = request.execute()
|
2024-06-22 08:55:26 -04:00
|
|
|
if "items" in response and len(response["items"]) > 0:
|
|
|
|
latest_video = response["items"][0]["snippet"]
|
|
|
|
video_id = latest_video["resourceId"]["videoId"]
|
|
|
|
title = latest_video["title"]
|
|
|
|
latest_video["publishedAt"]
|
|
|
|
thumbnail_url = latest_video["thumbnails"]["high"]["url"]
|
|
|
|
|
|
|
|
c.execute(
|
|
|
|
"SELECT last_video_id FROM youtube_status WHERE youtube_channel_id = ?",
|
|
|
|
(youtube_channel_id,),
|
|
|
|
)
|
2024-06-21 21:28:05 -04:00
|
|
|
row = c.fetchone()
|
|
|
|
last_video_id = row[0] if row else None
|
|
|
|
|
|
|
|
if video_id != last_video_id:
|
|
|
|
channel = self.bot.get_channel(discord_channel_id)
|
|
|
|
if channel:
|
|
|
|
embed = discord.Embed(
|
|
|
|
title=f"New Video from {youtube_channel_id}",
|
|
|
|
description=f"{title}\n[Watch now](https://www.youtube.com/watch?v={video_id})",
|
2024-06-22 08:55:26 -04:00
|
|
|
color=discord.Color.green(),
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
|
|
|
embed.set_thumbnail(url=thumbnail_url)
|
|
|
|
await channel.send(embed=embed)
|
|
|
|
|
2024-06-22 08:55:26 -04:00
|
|
|
c.execute(
|
|
|
|
"INSERT OR REPLACE INTO youtube_status (youtube_channel_id, last_video_id) VALUES (?, ?)",
|
|
|
|
(youtube_channel_id, video_id),
|
|
|
|
)
|
2024-06-21 21:28:05 -04:00
|
|
|
conn.commit()
|
|
|
|
except Exception as e:
|
2024-06-22 08:55:26 -04:00
|
|
|
logger.error(
|
|
|
|
f"Error checking YouTube channel {youtube_channel_id}: {e}",
|
|
|
|
exc_info=True,
|
|
|
|
)
|
2024-06-21 21:28:05 -04:00
|
|
|
|
|
|
|
conn.close()
|
|
|
|
await asyncio.sleep(300) # Check every 5 minutes
|
|
|
|
|
|
|
|
def add_commands(self):
|
|
|
|
@app_commands.command(
|
|
|
|
name="follow_youtube",
|
2024-06-22 08:55:26 -04:00
|
|
|
description="Follow a YouTube channel to get video updates",
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
2024-06-22 08:55:26 -04:00
|
|
|
async def follow_youtube(
|
|
|
|
interaction: discord.Interaction,
|
|
|
|
youtube_channel_id: str,
|
|
|
|
channel: discord.TextChannel = None,
|
|
|
|
):
|
2024-06-21 21:28:05 -04:00
|
|
|
channel = channel or interaction.channel
|
|
|
|
conn = get_connection()
|
|
|
|
c = conn.cursor()
|
|
|
|
c.execute(
|
2024-06-22 08:55:26 -04:00
|
|
|
"INSERT OR REPLACE INTO followed_youtube_channels (youtube_channel_id, discord_channel_id) VALUES (?, ?)",
|
|
|
|
(youtube_channel_id, channel.id),
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
|
|
|
conn.commit()
|
|
|
|
conn.close()
|
|
|
|
await interaction.response.send_message(
|
|
|
|
embed=discord.Embed(
|
|
|
|
title="Followed YouTube Channel",
|
|
|
|
description=f"Now following {youtube_channel_id}. Alerts will be sent to {channel.mention}.",
|
2024-06-22 08:55:26 -04:00
|
|
|
color=discord.Color.green(),
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
|
|
|
)
|
2024-06-22 08:55:26 -04:00
|
|
|
logger.info(
|
|
|
|
f"Now following {youtube_channel_id} for video updates in {channel.name}"
|
|
|
|
)
|
2024-06-21 21:28:05 -04:00
|
|
|
|
|
|
|
@app_commands.command(
|
2024-06-22 08:55:26 -04:00
|
|
|
name="unfollow_youtube", description="Unfollow a YouTube channel"
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
2024-06-22 08:55:26 -04:00
|
|
|
async def unfollow_youtube(
|
|
|
|
interaction: discord.Interaction, youtube_channel_id: str
|
|
|
|
):
|
2024-06-21 21:28:05 -04:00
|
|
|
conn = get_connection()
|
|
|
|
c = conn.cursor()
|
|
|
|
c.execute(
|
2024-06-22 08:55:26 -04:00
|
|
|
"DELETE FROM followed_youtube_channels WHERE youtube_channel_id = ?",
|
|
|
|
(youtube_channel_id,),
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
|
|
|
c.execute(
|
2024-06-22 08:55:26 -04:00
|
|
|
"DELETE FROM youtube_status WHERE youtube_channel_id = ?",
|
|
|
|
(youtube_channel_id,),
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
|
|
|
conn.commit()
|
|
|
|
conn.close()
|
|
|
|
await interaction.response.send_message(
|
|
|
|
embed=discord.Embed(
|
|
|
|
title="Unfollowed YouTube Channel",
|
|
|
|
description=f"No longer following {youtube_channel_id}.",
|
2024-06-22 08:55:26 -04:00
|
|
|
color=discord.Color.red(),
|
2024-06-21 21:28:05 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
logger.info(f"No longer following {youtube_channel_id}")
|
|
|
|
|
|
|
|
self.bot.tree.add_command(follow_youtube)
|
|
|
|
self.bot.tree.add_command(unfollow_youtube)
|
|
|
|
|
|
|
|
|
|
|
|
async def setup(bot):
|
|
|
|
YouTubeModule(bot)
|