discord-lnbits-bot/discord_lnbits_bot.py
2025-03-09 03:36:29 +00:00

138 lines
4.6 KiB
Python

import discord
import asyncio
import requests
import json
import io
import qrcode
from discord import File, Embed
from discord.ext import commands, tasks
with open("config.json", "r") as f:
config = json.load(f)
TOKEN = config["discord_token"]
GUILD_ID = int(config["guild_id"])
ROLE_ID = int(config["role_id"])
LNBITS_URL = config["lnbits_url"]
LNBITS_API_KEY = config["lnbits_api_key"]
PRICE = config["price"]
CHECK_INTERVAL = config["check_interval"]
MAX_CHECKS = config["max_checks"]
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents)
pending_invoices = {}
@bot.event
async def on_ready():
"""Called when the bot successfully logs in."""
print(f"✅ Logged in as {bot.user}")
print("Bot is in the following guilds:")
for g in bot.guilds:
print(f" - {g.name} (ID: {g.id})")
synced_cmds = await bot.tree.sync()
print("✅ Synced global commands:", synced_cmds)
print(f"🔄 Checking invoices every {CHECK_INTERVAL} seconds...")
check_invoices.start()
@bot.tree.command(name="support", description="Pay a Lightning invoice to get your role!")
async def support_command(interaction: discord.Interaction):
user_id = interaction.user.id
invoice_data = {
"out": False,
"amount": PRICE,
"memo": "Lightning Payment"
}
headers = {
"X-Api-Key": LNBITS_API_KEY,
"Content-Type": "application/json"
}
resp = requests.post(f"{LNBITS_URL}/api/v1/payments", json=invoice_data, headers=headers)
if resp.status_code == 201:
invoice_json = resp.json()
payment_request = invoice_json["payment_request"]
payment_hash = invoice_json["payment_hash"]
pending_invoices[payment_hash] = (user_id, 0)
qr_buffer = io.BytesIO()
qrcode.make(payment_request).save(qr_buffer, format="PNG")
qr_buffer.seek(0)
qr_file = File(fp=qr_buffer, filename="invoice_qr.png")
embed = Embed(
title="Payment Invoice",
description="Please pay the following Lightning invoice to complete your purchase."
)
embed.add_field(name="Invoice", value=f"```{payment_request}```", inline=False)
embed.add_field(name="Amount", value=f"{PRICE} sats", inline=True)
embed.add_field(name="Requesting User", value=f"{interaction.user.display_name}", inline=True)
embed.set_image(url="attachment://invoice_qr.png")
await interaction.user.send(
content=f"{interaction.user.display_name}, please pay **{PRICE} sats** using the Lightning Network.",
embed=embed,
file=qr_file
)
await interaction.response.send_message("✅ I've sent you a payment invoice via DM!", ephemeral=True)
else:
await interaction.response.send_message("❌ Failed to generate invoice. Try again later.", ephemeral=True)
print(f"❌ LNbits Error: {resp.text}")
@tasks.loop(seconds=CHECK_INTERVAL)
async def check_invoices():
if not pending_invoices:
return
guild = discord.utils.get(bot.guilds, id=GUILD_ID)
if guild is None:
print(f"⚠️ Bot not in server with ID {GUILD_ID}")
return
headers = {
"X-Api-Key": LNBITS_API_KEY,
"Content-Type": "application/json"
}
invoices_to_remove = []
for payment_hash, (user_id, attempts) in pending_invoices.items():
if attempts >= MAX_CHECKS:
invoices_to_remove.append(payment_hash)
continue
status_resp = requests.get(f"{LNBITS_URL}/api/v1/payments/{payment_hash}", headers=headers)
if status_resp.status_code == 200:
payment_status = status_resp.json()
if payment_status.get("paid", False):
member = guild.get_member(user_id)
if member:
role = guild.get_role(ROLE_ID)
if role:
await member.add_roles(role)
await member.send("✅ **Thank you! Your role has been assigned.**")
print(f"🎉 Role assigned to {member.name}")
invoices_to_remove.append(payment_hash)
else:
print(f"❌ Role ID {ROLE_ID} not found!")
else:
print(f"❌ Member {user_id} not found!")
pending_invoices[payment_hash] = (user_id, attempts + 1)
for done_hash in invoices_to_remove:
del pending_invoices[done_hash]
bot.run(TOKEN)