138 lines
4.6 KiB
Python
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)
|