|
|
|
@@ -1,20 +1,25 @@
|
|
|
|
|
import aiohttp
|
|
|
|
|
import fluxer
|
|
|
|
|
import requests
|
|
|
|
|
import json
|
|
|
|
|
import asyncio
|
|
|
|
|
import base64
|
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
import sqlite3
|
|
|
|
|
import os
|
|
|
|
|
import re
|
|
|
|
|
import logging
|
|
|
|
|
import random
|
|
|
|
|
import yt_player
|
|
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
|
|
|
|
|
|
# this is a bot which posts the latest image post from ich_iel
|
|
|
|
|
# the code probably sucks, but it works, so I don't care
|
|
|
|
|
|
|
|
|
|
load_dotenv()
|
|
|
|
|
prefix = os.getenv("COMMAND_PREFIX", "/")
|
|
|
|
|
bot = fluxer.Bot(command_prefix=prefix, intents=fluxer.Intents.GUILD_MESSAGES | fluxer.Intents.GUILDS | fluxer.Intents.MESSAGE_CONTENT)
|
|
|
|
|
bot = fluxer.Bot(command_prefix=prefix, intents=fluxer.Intents.GUILD_MESSAGES | fluxer.Intents.GUILDS | fluxer.Intents.MESSAGE_CONTENT | fluxer.Intents.GUILD_VOICE_STATES)
|
|
|
|
|
yt_player.setup(bot)
|
|
|
|
|
|
|
|
|
|
task = None
|
|
|
|
|
|
|
|
|
@@ -49,32 +54,30 @@ async def post_reddit_periodically():
|
|
|
|
|
|
|
|
|
|
async def get_latest_post(subreddit):
|
|
|
|
|
post_limit = os.getenv("POST_LIMIT", 20)
|
|
|
|
|
url = f"https://www.reddit.com/r/{subreddit}/hot.json?limit={post_limit}"
|
|
|
|
|
headers = {"User-Agent": "Mozilla/5.0 (compatible; ich_iel-Bot/0.3)"}
|
|
|
|
|
url = f"https://www.reddit.com/r/{subreddit}/hot.rss?limit={post_limit}"
|
|
|
|
|
headers = {"User-Agent": "Mozilla/5.0 (compatible; ich_iel-Bot/0.6.0)"}
|
|
|
|
|
response = requests.get(url, headers=headers)
|
|
|
|
|
if response.status_code == 200:
|
|
|
|
|
if response.headers.get("Content-Type", "").startswith("application/json"):
|
|
|
|
|
try:
|
|
|
|
|
data = response.json()
|
|
|
|
|
logging.debug(f"Fetched data from Reddit: {data}")
|
|
|
|
|
posts = []
|
|
|
|
|
if data["data"]["children"]:
|
|
|
|
|
for child in data["data"]["children"]:
|
|
|
|
|
post = child["data"]
|
|
|
|
|
if post.get("post_hint") == "image" and post.get("url", "").endswith((".jpg", ".png", ".jpeg", ".gif")):
|
|
|
|
|
logging.debug(f"Found image post: {post['title']} - {post['url']}")
|
|
|
|
|
posts.append((post["title"], post["url"]))
|
|
|
|
|
return posts
|
|
|
|
|
except (KeyError, json.JSONDecodeError):
|
|
|
|
|
logging.error(f"Error parsing Reddit response: {response.text}")
|
|
|
|
|
return []
|
|
|
|
|
else:
|
|
|
|
|
logging.warning(f"Unexpected content type from Reddit: {response.headers.get('Content-Type')}")
|
|
|
|
|
logging.warning(f"Response content: {response.text}")
|
|
|
|
|
return []
|
|
|
|
|
else:
|
|
|
|
|
logging.error(f"Failed to fetch Reddit data (maybe a block?): {response.status_code}")
|
|
|
|
|
if response.status_code != 200:
|
|
|
|
|
logging.error(f"Failed to fetch RSS feed: {response.status_code}")
|
|
|
|
|
return []
|
|
|
|
|
posts = []
|
|
|
|
|
try:
|
|
|
|
|
root = ET.fromstring(response.text)
|
|
|
|
|
ns = {"atom": "http://www.w3.org/2005/Atom"}
|
|
|
|
|
for entry in root.findall("atom:entry", ns):
|
|
|
|
|
post_title = entry.find("atom:title", ns)
|
|
|
|
|
content = entry.find("atom:content", ns)
|
|
|
|
|
if post_title is None or content is None or content.text is None:
|
|
|
|
|
continue
|
|
|
|
|
link_match = re.search(r'<a href="([^"]+)">\[link\]</a>', content.text)
|
|
|
|
|
if link_match and link_match.group(1).lower().endswith(('.jpg', '.jpeg', '.png', '.gif')):
|
|
|
|
|
logging.debug(f"Found image post: {post_title.text} - {link_match.group(1)}")
|
|
|
|
|
posts.append((post_title.text, link_match.group(1)))
|
|
|
|
|
except ET.ParseError as e:
|
|
|
|
|
logging.error(f"Error parsing RSS feed: {e}")
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
return posts
|
|
|
|
|
|
|
|
|
|
async def init_db():
|
|
|
|
|
try:
|
|
|
|
@@ -118,7 +121,7 @@ async def setChannel(message):
|
|
|
|
|
|
|
|
|
|
@bot.command()
|
|
|
|
|
async def version(message):
|
|
|
|
|
await message.channel.send("Version 0.4.1 is running\nSource code: https://github.com/michelleDeko/ich_iel-bot")
|
|
|
|
|
await message.channel.send("Version 0.6.0 is running\nSource code: https://github.com/michelleDeko/ich_iel-bot")
|
|
|
|
|
|
|
|
|
|
# the cat bot died, so i wanted to add this command to this bot
|
|
|
|
|
@bot.command()
|
|
|
|
@@ -133,6 +136,46 @@ async def cat(message):
|
|
|
|
|
else:
|
|
|
|
|
await message.channel.send("Failed to fetch cat image")
|
|
|
|
|
|
|
|
|
|
# i thought dogs and foxes would be nice to have too
|
|
|
|
|
@bot.command()
|
|
|
|
|
async def dog(message):
|
|
|
|
|
response = requests.get("https://dog.ceo/api/breeds/image/random")
|
|
|
|
|
if response.status_code == 200:
|
|
|
|
|
data = response.json()
|
|
|
|
|
if data and isinstance(data, dict) and "message" in data:
|
|
|
|
|
await message.channel.send(data["message"])
|
|
|
|
|
else:
|
|
|
|
|
await message.channel.send("Could not fetch dog image")
|
|
|
|
|
else:
|
|
|
|
|
await message.channel.send("Failed to fetch dog image")
|
|
|
|
|
|
|
|
|
|
@bot.command()
|
|
|
|
|
async def fox(message):
|
|
|
|
|
response = requests.get("https://randomfox.ca/floof/")
|
|
|
|
|
if response.status_code == 200:
|
|
|
|
|
data = response.json()
|
|
|
|
|
if data and isinstance(data, dict) and "image" in data:
|
|
|
|
|
await message.channel.send(data["image"])
|
|
|
|
|
else:
|
|
|
|
|
await message.channel.send("Could not fetch fox image")
|
|
|
|
|
else:
|
|
|
|
|
await message.channel.send("Failed to fetch fox image")
|
|
|
|
|
|
|
|
|
|
# time for racoons
|
|
|
|
|
@bot.command()
|
|
|
|
|
async def racoon(message):
|
|
|
|
|
urls = random.choice([
|
|
|
|
|
"https://api.mapach.es/v1/meme",
|
|
|
|
|
"https://api.mapach.es/v1/coon"
|
|
|
|
|
])
|
|
|
|
|
async with aiohttp.ClientSession() as session:
|
|
|
|
|
async with session.get(urls) as response:
|
|
|
|
|
image_bytes = await response.read()
|
|
|
|
|
if response.status != 200:
|
|
|
|
|
await message.channel.send("Failed to fetch racoon image")
|
|
|
|
|
return
|
|
|
|
|
await message.channel.send(file=fluxer.File(image_bytes, filename="racoon.jpg"))
|
|
|
|
|
|
|
|
|
|
async def post_reddit():
|
|
|
|
|
subreddit = os.getenv("SUBREDDIT", "ich_iel")
|
|
|
|
|
posts = await get_latest_post(subreddit)
|
|
|
|
@@ -170,6 +213,7 @@ async def post_reddit():
|
|
|
|
|
else:
|
|
|
|
|
logging.warning(f"Bot is not in guild {guild_id}, removing guild from database")
|
|
|
|
|
cur.execute("DELETE FROM channels WHERE guild_id = ?", (guild_id,))
|
|
|
|
|
cur.execute("DELETE FROM posted WHERE guild_id = ?", (guild_id,))
|
|
|
|
|
con.commit()
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
@@ -201,27 +245,6 @@ async def check_guild(guild_id):
|
|
|
|
|
logging.warning(f"Bot doesn't have access to guild {guild_id}")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
@bot.event
|
|
|
|
|
async def on_guild_remove(guild):
|
|
|
|
|
if isinstance(guild, fluxer.Guild):
|
|
|
|
|
guild_id = guild.id
|
|
|
|
|
logging.info(f"Removed from guild: {guild.name} (ID: {guild_id}), removing from database")
|
|
|
|
|
else:
|
|
|
|
|
if guild.get("unavailable"):
|
|
|
|
|
logging.info(f"Guild {guild.get('id')} is temporarily unavailable, ignoring")
|
|
|
|
|
return
|
|
|
|
|
guild_id = int(guild["id"])
|
|
|
|
|
logging.info(f"Removed from guild {guild_id}, removing from database")
|
|
|
|
|
try:
|
|
|
|
|
con = sqlite3.connect('data/ich_iel-bot.db')
|
|
|
|
|
cur = con.cursor()
|
|
|
|
|
cur.execute("DELETE FROM channels WHERE guild_id = ?", (guild_id,))
|
|
|
|
|
cur.execute("DELETE FROM posted WHERE guild_id = ?", (guild_id,))
|
|
|
|
|
con.commit()
|
|
|
|
|
logging.info(f"Guild {guild_id} removed from database successfully")
|
|
|
|
|
except sqlite3.Error as e:
|
|
|
|
|
logging.error(f"Database error while removing guild {guild_id}: {e}")
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
logging.info("Starting bot...")
|
|
|
|
|
asyncio.run(init_db())
|
|
|
|
|