aboutsummaryrefslogtreecommitdiffstats
path: root/cogs/qr.py
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2026-04-17 19:40:48 +0200
committersalmonik <raisersoft@proton.me>2026-04-17 19:40:48 +0200
commit0d1163d5e065c20467351d1e0e332eb40dae1133 (patch)
treec2129da1f6ce0641bb2a7a983a5434f2bf3bab3d /cogs/qr.py
parentadd cron functionality (diff)
downloadsenator-sperma-0d1163d5e065c20467351d1e0e332eb40dae1133.tar.gz
senator-sperma-0d1163d5e065c20467351d1e0e332eb40dae1133.zip
add qr generation and decoding
Signed-off-by: salmonik <raisersoft@proton.me>
Diffstat (limited to 'cogs/qr.py')
-rw-r--r--cogs/qr.py142
1 files changed, 142 insertions, 0 deletions
diff --git a/cogs/qr.py b/cogs/qr.py
new file mode 100644
index 0000000..058dac8
--- /dev/null
+++ b/cogs/qr.py
@@ -0,0 +1,142 @@
1# This file is part of Senator Sperma
2# Licensed under the GPL-3.0 License
3# Copyright (C) 2026 Salmonik @ salmonik@tuta.io
4# https://codeberg.org/salmonik/senator-sperma
5
6import asyncio
7import logging
8import os
9import tempfile
10
11import aiohttp
12import discord
13import qrcode
14from discord.ext import commands
15
16logger = logging.getLogger(__name__)
17
18try:
19 from PIL import Image
20 from pyzbar.pyzbar import decode as decode_qr
21
22 DECODE_AVAILABLE = True
23except ImportError:
24 DECODE_AVAILABLE = False
25 logger.warning("pyzbar or PIL not available, decode command will be disabled")
26
27
28class QR(commands.Cog):
29 def __init__(self, bot):
30 self.bot = bot
31
32 async def _download_image(self, url):
33 """Download image from URL to temporary file"""
34 async with aiohttp.ClientSession() as session:
35 async with session.get(url) as response:
36 if response.status == 200:
37 content = await response.read()
38 with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as f:
39 f.write(content)
40 return f.name
41 return None
42
43 @commands.slash_command(
44 name="qr_generuj", description="Generuje kod QR z podanego tekstu"
45 )
46 async def qr(
47 self,
48 ctx,
49 text: str = discord.Option(str, "Tekst do zakodowania", required=True),
50 ):
51 await ctx.defer()
52
53 temp_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "temp")
54 os.makedirs(temp_dir, exist_ok=True)
55 temp_path = os.path.join(
56 temp_dir, f"qr_{os.getpid()}_{asyncio.get_event_loop().time()}.png"
57 )
58
59 try:
60 loop = asyncio.get_event_loop()
61 await loop.run_in_executor(None, self._generate_qr, text, temp_path)
62 await ctx.respond(file=discord.File(temp_path, filename="qr.png"))
63 logger.info(f"Generated QR for text: {text}")
64 except Exception as e:
65 logger.error(f"QR generation error: {e}")
66 await ctx.respond("Error generating QR code", ephemeral=True)
67 finally:
68 try:
69 if os.path.exists(temp_path):
70 os.unlink(temp_path)
71 except Exception as e:
72 logger.error(f"Error cleaning up temp file: {e}")
73
74 def _generate_qr(self, text, output_path):
75 """Generate QR code (runs in executor)"""
76 qr = qrcode.QRCode(
77 version=1,
78 error_correction=qrcode.constants.ERROR_CORRECT_L,
79 box_size=10,
80 border=4,
81 )
82 qr.add_data(text)
83 qr.make(fit=True)
84 img = qr.make_image(fill_color="black", back_color="white")
85 img.save(output_path)
86
87 @commands.slash_command(name="qr_dekoduj", description="Dekoduje kod QR z obrazka")
88 async def decode(
89 self,
90 ctx,
91 image: discord.Attachment = discord.Option(
92 discord.Attachment, "Obrazek z kodem QR", required=True
93 ),
94 ):
95 if not DECODE_AVAILABLE:
96 await ctx.respond(
97 "Dekodowanie nie jest dostępne (brak biblioteki pyzbar)", ephemeral=True
98 )
99 return
100
101 await ctx.defer()
102
103 try:
104 temp_path = await self._download_image(image.url)
105 if not temp_path:
106 await ctx.respond("Nie udało się pobrać obrazka", ephemeral=True)
107 return
108
109 try:
110 loop = asyncio.get_event_loop()
111 decoded = await loop.run_in_executor(None, self._decode_qr, temp_path)
112
113 if decoded:
114 await ctx.respond(f"```\n{decoded}\n```")
115 logger.info(f"Decoded QR: {decoded}")
116 else:
117 await ctx.respond(
118 "Nie znaleziono kodu QR na obrazku", ephemeral=True
119 )
120 finally:
121 if os.path.exists(temp_path):
122 os.unlink(temp_path)
123 except Exception as e:
124 logger.error(f"QR decode error: {e}")
125 await ctx.respond("Error dekodowania QR", ephemeral=True)
126
127 def _decode_qr(self, image_path):
128 """Decode QR code from image (runs in executor)"""
129 try:
130 from PIL import Image
131
132 img = Image.open(image_path)
133 decoded_list = decode_qr(img)
134 if decoded_list:
135 return decoded_list[0].data.decode("utf-8")
136 except Exception as e:
137 logger.error(f"Error decoding QR: {e}")
138 return None
139
140
141def setup(bot):
142 bot.add_cog(QR(bot))