9 Commits

Author SHA1 Message Date
Michelle 7b09d1a348 update version to 0.6.1
Build and publish ich_iel bot / build (push) Has been cancelled
Build and publish ich_iel bot / build (release) Successful in 6m3s
2026-05-08 20:53:12 +02:00
Michelle 01e5208cba add bnuy command
Build and publish ich_iel bot / build (push) Successful in 6m2s
2026-05-08 20:46:10 +02:00
Michelle 9d97b10c20 update version to 0.6.0
Build and publish ich_iel bot / build (push) Successful in 5m57s
Build and publish ich_iel bot / build (release) Successful in 5m56s
2026-05-02 16:35:58 +02:00
Michelle 8739f889d3 try using RSS feed instead of json, since RSS doesn't seem to block server ips
Build and publish ich_iel bot / build (push) Successful in 6m31s
2026-05-02 16:12:24 +02:00
Michelle 0e368ade2f ok now it should work
Build and publish ich_iel bot / build (push) Successful in 5m53s
2026-04-30 17:13:01 +02:00
Michelle 9acb6b04eb forgor adding GUILD_VOICE_STATES oopsie
Build and publish ich_iel bot / build (push) Successful in 6m0s
2026-04-30 16:59:31 +02:00
Michelle 2a33bc70b7 fix play command (hopefully)
Build and publish ich_iel bot / build (push) Successful in 5m56s
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 16:46:55 +02:00
Michelle a775a55291 update Dockerfile with ffmpeg
Build and publish ich_iel bot / build (push) Successful in 6m4s
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 16:18:26 +02:00
Michelle c365cd1ff2 try adding youtube player support
Build and publish ich_iel bot / build (push) Successful in 2m47s
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 16:17:39 +02:00
4 changed files with 97 additions and 29 deletions
+2 -1
View File
@@ -1,8 +1,9 @@
FROM python:3.13.12-slim-trixie FROM python:3.13.13-slim-trixie
ENV PATH=/usr/local/bin:$PATH ENV PATH=/usr/local/bin:$PATH
WORKDIR /app WORKDIR /app
COPY requirements.txt . COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg && rm -rf /var/lib/apt/lists/*
COPY . . COPY . .
CMD ["python", "-u", "main.py"] CMD ["python", "-u", "main.py"]
+48 -25
View File
@@ -10,13 +10,16 @@ import os
import re import re
import logging import logging
import random import random
import yt_player
import xml.etree.ElementTree as ET
# this is a bot which posts the latest image post from ich_iel # 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 # the code probably sucks, but it works, so I don't care
load_dotenv() load_dotenv()
prefix = os.getenv("COMMAND_PREFIX", "/") 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 task = None
@@ -51,32 +54,30 @@ async def post_reddit_periodically():
async def get_latest_post(subreddit): async def get_latest_post(subreddit):
post_limit = os.getenv("POST_LIMIT", 20) post_limit = os.getenv("POST_LIMIT", 20)
url = f"https://www.reddit.com/r/{subreddit}/hot.json?limit={post_limit}" url = f"https://www.reddit.com/r/{subreddit}/hot.rss?limit={post_limit}"
headers = {"User-Agent": "Mozilla/5.0 (compatible; ich_iel-Bot/0.3)"} headers = {"User-Agent": "Mozilla/5.0 (compatible; ich_iel-Bot/0.6.1)"}
response = requests.get(url, headers=headers) response = requests.get(url, headers=headers)
if response.status_code == 200: if response.status_code != 200:
if response.headers.get("Content-Type", "").startswith("application/json"): logging.error(f"Failed to fetch RSS feed: {response.status_code}")
try: return []
data = response.json()
logging.debug(f"Fetched data from Reddit: {data}")
posts = [] posts = []
if data["data"]["children"]: try:
for child in data["data"]["children"]: root = ET.fromstring(response.text)
post = child["data"] ns = {"atom": "http://www.w3.org/2005/Atom"}
if post.get("post_hint") == "image" and post.get("url", "").endswith((".jpg", ".png", ".jpeg", ".gif")): for entry in root.findall("atom:entry", ns):
logging.debug(f"Found image post: {post['title']} - {post['url']}") post_title = entry.find("atom:title", ns)
posts.append((post["title"], post["url"])) 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 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}")
return []
async def init_db(): async def init_db():
try: try:
@@ -120,7 +121,7 @@ async def setChannel(message):
@bot.command() @bot.command()
async def version(message): async def version(message):
await message.channel.send("Version 0.5.1 is running\nSource code: https://github.com/michelleDeko/ich_iel-bot") await message.channel.send("Version 0.6.1 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 # the cat bot died, so i wanted to add this command to this bot
@bot.command() @bot.command()
@@ -175,6 +176,28 @@ async def racoon(message):
return return
await message.channel.send(file=fluxer.File(image_bytes, filename="racoon.jpg")) await message.channel.send(file=fluxer.File(image_bytes, filename="racoon.jpg"))
# i just watched beastars and i realised that this bot needs a bnuy command
# maybe I will switch the API later since this one seems to only have gifs
@bot.command()
async def bnuy(message):
async with aiohttp.ClientSession() as session:
async with session.get("https://api.bunnies.io/v2/loop/random/?media=gif,png") as response:
data = await response.json()
if response.status != 200 or not data or "media" not in data:
await message.channel.send("Failed to fetch image of a bunny")
return
image_url = data["media"].get("gif")
if not image_url:
await message.channel.send("Failed to fetch image of a bunny")
return
file_ext = "gif" if image_url.lower().endswith(".gif") else "png"
async with session.get(image_url) as image_response:
if image_response.status != 200:
await message.channel.send("Failed to fetch image of a bunny")
return
image_bytes = await image_response.read()
await message.channel.send(file=fluxer.File(image_bytes, filename=f"bnuy.{file_ext}"))
async def post_reddit(): async def post_reddit():
subreddit = os.getenv("SUBREDDIT", "ich_iel") subreddit = os.getenv("SUBREDDIT", "ich_iel")
posts = await get_latest_post(subreddit) posts = await get_latest_post(subreddit)
+2 -1
View File
@@ -1,5 +1,6 @@
fluxer.py fluxer.py[voice]
requests requests
asyncio asyncio
dotenv dotenv
aiohttp aiohttp
yt-dlp
+43
View File
@@ -0,0 +1,43 @@
# at this point this bot isn't just a reddit bot anymore, maybe i should start renaming it lol
import yt_dlp
import logging
import os
AUDIO_DIR = "data/audio"
_bot = None
def setup(bot):
global _bot
_bot = bot
os.makedirs(AUDIO_DIR, exist_ok=True)
bot.command()(play)
async def play(ctx, *, url: str):
guild_id = ctx._guild.id
voice_state = _bot.get_voice_state(guild_id, ctx.author.id)
if voice_state is None or voice_state.channel_id is None:
await ctx.reply("You're not in a voice channel!")
return
channel = await _bot.fetch_channel(str(voice_state.channel_id))
logging.info(f"Playing {url}")
ydl_opts = {
'format': 'm4a/bestaudio/best',
'outtmpl': f'{AUDIO_DIR}/%(id)s.%(ext)s',
'postprocessors': [{ # Extract audio using ffmpeg
'key': 'FFmpegExtractAudio',
'preferredcodec': 'm4a',
}]
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=True)
filename = ydl.prepare_filename(info).rsplit('.', 1)[0] + '.m4a'
title = info.get('title', 'Unknown Title')
logging.info(f"Downloaded to {filename}")
await ctx.reply(f"Playing {title} in {channel.mention}")
async with await channel.connect(_bot) as vc:
await vc.play_file(filename)