forked from foxo/printer_bot
Initial commit
This commit is contained in:
commit
bfceff8f10
|
@ -0,0 +1,72 @@
|
|||
# Telegram Printer Bot
|
||||
|
||||
This Python script implements a Telegram bot that can print images and stickers sent by users. The bot supports resizing images, converting them to grayscale, and applying gamma correction before printing to ensure maximum quality.
|
||||
|
||||
Currently, you can set a command to print your sticker (by default we used brother_ql to print to a Brother printer). You can use any external program you want to print to other brands and models of printers.
|
||||
|
||||
## Requirements
|
||||
|
||||
* Python 3.6+
|
||||
* telethon
|
||||
* PIL (Python Imaging Library) library (Pillow)
|
||||
* brother_ql
|
||||
|
||||
You can install the requirements by running this command:
|
||||
|
||||
`python3 -m pip install -r requirements.txt`
|
||||
|
||||
If this is the first time running the script and your printer uses the `lp` protocol, remember to add your user to the `lp` group using the following command:
|
||||
|
||||
`sudo usermod -a -G lp ${USER}`
|
||||
|
||||
## Configuration
|
||||
|
||||
Before running the script, you need to set up the configuration parameters. You can use "config.example.py" as a guide (rename it to config.py). The following parameters must be defined:
|
||||
|
||||
* API_ID: Your Telegram API ID. You can obtain it by creating a Telegram application
|
||||
* API_HASH: Your Telegram API hash. You can obtain it from the same page where you got the API ID.
|
||||
* BOT_TOKEN: The token for your Telegram bot. You can create a new bot and obtain the token by following the instructions here.
|
||||
* ADMIN_ID: Your user id. This is the user that will receive administrative rights and error reports.
|
||||
* PRINT_COMMAND: Adjust with your printer model and path.
|
||||
|
||||
## Usage
|
||||
|
||||
After setting up the configuration file, you can just run the bot by using the command
|
||||
|
||||
`python bot.py`
|
||||
|
||||
Once the bot is running, it will respond to specific commands:
|
||||
|
||||
* `/id`: Returns your Telegram user ID, which you need to add to the ADMIN_ID list in the config.py file to grant yourself privileges.
|
||||
* `/start`: Displays a welcome message and requests a password if set in the config.py file.
|
||||
When the user sends the correct password in a private message, the printer functionality will be unlocked for that user.
|
||||
|
||||
## Features
|
||||
|
||||
* Printer password (pin code) protection
|
||||
* Cooldown period for users
|
||||
* Caching of images and stickers
|
||||
* Resizing images to the correct printer resolution for maximum crispness
|
||||
* Conversion to greyscale with gamma adjustment (improves images a lot!)
|
||||
* Ratio limit to prevent excessively long stickers from being printed
|
||||
|
||||
## Important Notes
|
||||
|
||||
1. Make sure to set proper permissions for the cache directory to ensure the bot can write to it.
|
||||
2. The PRINT_COMMAND and PRINT_SUCCESS_COMMAND in the config.py file should be customized to match the print command on your system.
|
||||
3. Ensure you have a functioning printer setup before running the bot. You will find the output from the command in the console!
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the BEER-WARE License.
|
||||
|
||||
```/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
||||
* ----------------------------------------------------------------------------
|
||||
*/```
|
||||
|
||||
**This script is provided as-is, without any warranty or support. Use it at your own risk. The authors are not responsible for any misuse or damage caused by this script.**
|
|
@ -0,0 +1,111 @@
|
|||
from telethon import TelegramClient
|
||||
import logging, asyncio
|
||||
from telethon.tl.types import MessageMediaDocument, DocumentAttributeSticker, DocumentAttributeAnimated, MessageMediaPhoto
|
||||
from telethon import events
|
||||
from telethon.tl.custom import Button
|
||||
from os.path import isfile, join
|
||||
from os import system
|
||||
from time import time
|
||||
from PIL import Image
|
||||
from config import *
|
||||
from os import makedirs
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
client = TelegramClient('bot', API_ID, API_HASH).start(bot_token=BOT_TOKEN)
|
||||
client.flood_sleep_threshold = 120
|
||||
|
||||
print_log = {}
|
||||
|
||||
@client.on(events.NewMessage(pattern='^/id'))
|
||||
async def debug_id(ev):
|
||||
await ev.respond(f"Hello! Your id is `{ev.peer_id.user_id}` please add it to the ADMIN_ID to give youself privileges :)")
|
||||
|
||||
@client.on(events.NewMessage(pattern='^/start'))
|
||||
async def welcome(ev):
|
||||
await ev.respond(WELCOME_MSG)
|
||||
if (ev.peer_id.user_id not in print_log) and PASSWORD:
|
||||
await ev.respond(UNLOCK_MSG)
|
||||
|
||||
# This one triggers on a single message with the pin code written
|
||||
@client.on(events.NewMessage(pattern=PASSWORD, func=lambda e: e.is_private))
|
||||
async def unlock_printer(ev):
|
||||
if ev.peer_id.user_id not in print_log:
|
||||
print_log[ev.peer_id.user_id] = 0
|
||||
if PASSWORD:
|
||||
await ev.respond(UNLOCKED_MSG)
|
||||
|
||||
@client.on(events.NewMessage(incoming=True, func=lambda e: e.is_private and e.message.media))
|
||||
async def handler(ev):
|
||||
|
||||
msg = ev.message
|
||||
if ev.peer_id.user_id not in print_log:
|
||||
await ev.respond(UNLOCK_MSG)
|
||||
|
||||
# Check if the file is valid
|
||||
if msg.photo:
|
||||
fn = join(CACHE_DIR, f"{msg.photo.id}.jpg")
|
||||
elif msg.sticker:
|
||||
fn = join(CACHE_DIR, f"{msg.sticker.id}.webp")
|
||||
for att in msg.sticker.attributes:
|
||||
if isinstance(att, DocumentAttributeAnimated):
|
||||
fn = None
|
||||
break
|
||||
else:
|
||||
fn = None
|
||||
|
||||
if not fn:
|
||||
await ev.respond(FORMAT_ERR_MSG)
|
||||
return
|
||||
|
||||
# Check if the user is still in the cooldown period
|
||||
time_left = int((print_log[ev.peer_id.user_id] + BASE_COOLDOWN) - time())
|
||||
if time_left > 0:
|
||||
await ev.respond(RATELIMIT_MSG.format(time_left=time_left))
|
||||
return
|
||||
|
||||
# Download the file unless it's in the cache!
|
||||
if not isfile(fn):
|
||||
await client.download_media(msg, file=fn)
|
||||
|
||||
# Try opening the image, at least
|
||||
try:
|
||||
img = Image.open(fn)
|
||||
except:
|
||||
await ev.respond(FORMAT_ERR_MSG)
|
||||
return
|
||||
|
||||
# Limit stickers ratio (so people don't print incredibly long stickers)
|
||||
if img.size[1]/img.size[0] > MAX_ASPECT_RATIO:
|
||||
return ev.respond(RATIO_ERR_MSG)
|
||||
|
||||
# Remove transparency
|
||||
if img.mode == 'RGBA':
|
||||
bg_img = Image.new(img.mode, img.size, BACKGROUND_COLOR)
|
||||
img = Image.alpha_composite(bg_img, img)
|
||||
|
||||
# Resize the image
|
||||
img.thumbnail([WIDTH_PX, HEIGHT_PX], resample=Image.LANCZOS, reducing_gap=None)
|
||||
|
||||
# Convert to grayscale and apply a gamma of 1.8
|
||||
img = img.convert('L')
|
||||
|
||||
if GAMMA_CORRECTION != 1:
|
||||
img = Image.eval(img, lambda x: int(255*pow((x/255),(1/GAMMA_CORRECTION))))
|
||||
|
||||
img.save(IMAGE_PATH, 'PNG')
|
||||
|
||||
status_code = system(PRINT_COMMAND)
|
||||
if status_code == 0:
|
||||
print_log[ev.peer_id.user_id] = time()
|
||||
await ev.respond(PRINT_SUCCESS_MSG)
|
||||
else:
|
||||
await ev.respond(PRINT_FAIL_MSG)
|
||||
await client.send_message(ADMIN_ID, f'Printer is not working. Process returned status code {status_code}')
|
||||
|
||||
if PRINT_SUCCESS_COMMAND:
|
||||
system(PRINT_SUCCESS_COMMAND)
|
||||
|
||||
if __name__ == '__main__':
|
||||
makedirs(CACHE_DIR, exist_ok=True)
|
||||
client.run_until_disconnected()
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
# To get an API_ID and API_HASH, you need to sign up to be a Telegram Dev.
|
||||
# Do it here: https://core.telegram.org/api/obtaining_api_id
|
||||
API_ID = 11111
|
||||
API_HASH = '5d41402abc4b2a76b9719d911017c592'
|
||||
|
||||
# Get a bot token from Telegram by creating a bot with @BotFather
|
||||
BOT_TOKEN = '1222222222:b2YgZXdvaWZld29maHdlb2lmaA'
|
||||
|
||||
WELCOME_MSG = 'Hello!\nWelcome to **Foxo\'s label printer**! Send me any sticker or other media to print it!'
|
||||
UNLOCK_MSG = 'The printer is currently locked for you. Please enter the password!'
|
||||
PRINT_FAIL_MSG = 'I wasn\'t able to print your sticker.'
|
||||
RATIO_ERR_MSG = 'That image is too tall. It would waste a lot of paper. Please give me a shorter sticker.'
|
||||
PRINT_SUCCESS_MSG = 'Your sticker has finished printing now! Enjoy it :3'
|
||||
FORMAT_ERR_MSG = 'Cannot print this. Try with a (static) sticker or a picture!'
|
||||
RATELIMIT_MSG = 'Woo calm down fam!\n\nSend the sticker again in {time_left} seconds!'
|
||||
UNLOCKED_MSG = 'Printer has been unlocked. Have fun!'
|
||||
|
||||
# Limits to prevent abuse
|
||||
PASSWORD = '12345' # Set to None if no password required
|
||||
BASE_COOLDOWN = 10 # Seconds between stickers printing
|
||||
MAX_ASPECT_RATIO = 1.5 # Maximum ratio between height/width of sticker
|
||||
ADMIN_ID = 111111 # Find your own id with the /id command
|
||||
|
||||
# Folder settings
|
||||
IMAGE_PATH = '/tmp/image.png'
|
||||
CACHE_DIR = '/tmp/printercache'
|
||||
|
||||
# Remember to add your user to the "lp" group or this won't work!
|
||||
PRINT_COMMAND = f"brother_ql -m QL-700 -b linux_kernel -p file:///dev/usb/lp0 print -l 62 {IMAGE_PATH} -d"
|
||||
PRINT_SUCCESS_COMMAND = None # "mpv --no-video success.wav" - this was used to play audio
|
||||
|
||||
# Resize and process settings
|
||||
WIDTH_PX = 696
|
||||
HEIGHT_PX = 9999 # This means "do not care about height"
|
||||
GAMMA_CORRECTION = 1.8
|
||||
BACKGROUND_COLOR = 'white'
|
|
@ -0,0 +1,3 @@
|
|||
telethon
|
||||
Pillow
|
||||
brother_ql
|
Loading…
Reference in New Issue