added /wot and /text, code cleanup
@@ -1,7 +1,9 @@
from PIL import Image, UnidentifiedImageError from io import BytesIO -import requests, random, time, logging +import requests, random, time, logging, time + +random.seed(time.time()) base_url = "https://danbooru.donmai.us/" base_url_test = "https://testbooru.donmai.us/"
@@ -1,5 +1,7 @@
from PIL import Image, ImageDraw, ImageFont, ImageEnhance -import textwrap, os +import textwrap, os, random, time + +random.seed(time.time()) BASE_WIDTH = 1200 IMPACT_FONT_FILE = os.path.join("fonts", "impact.ttf")@@ -85,17 +87,18 @@ MARGIN = 10
LINE_WIDTH = 20 lines = [x for x in text.split("\n") if x] - if len(lines) < 2: - return img + first_line = lines.pop(0) + text = "\n".join(lines) img = img.resize((BASE_WIDTH, int(img.size[1] * float(BASE_WIDTH / img.size[0])))) img = _darken_image(img) - text = textwrap.wrap(lines[1].upper(), width=LINE_WIDTH) + text = textwrap.wrap(text.upper(), width=LINE_WIDTH) if text == []: return - text.insert(0, lines[0]) + text.insert(0, first_line) + font_first = ImageFont.truetype(font=ARIAL_FONT_FILE, size=FONT_FIRST) font_base = ImageFont.truetype(font=ARIAL_FONT_FILE, size=FONT_BASE)@@ -134,6 +137,98 @@ img = img.convert("RGB")
return img +def wot_effect(text: str, img: Image): + LETTER_SPACING = 1 + LINE_SPACING = 3 + FILL = (255, 255, 255) + STROKE_WIDTH = 1 + STROKE_FILL = (0, 0, 0) + FONT_BASE = 50 + MARGIN = 10 + LINE_WIDTH = 44 + + img = img.resize((BASE_WIDTH, int(img.size[1] * float(BASE_WIDTH / img.size[0])))) + img = _darken_image(img) + + text = textwrap.wrap(text, width=LINE_WIDTH) + if text == []: + return + + font = ImageFont.truetype(font=ARIAL_FONT_FILE, size=FONT_BASE) + + img_width, img_height = img.size + d = ImageDraw.Draw(img) + + _, _, txt_width, txt_height = d.textbbox((0, 0), text[0], font=font) + + total_height = (txt_height + LINE_SPACING) * len(text) + y = (img_height - total_height) / 2 + + for i in range(len(text)): + txt_width = d.textbbox((0, 0), text[i], font=font)[2] + x = (img_width - txt_width - (len(text[i]) * LETTER_SPACING))/2 + + _draw_line(d=d, x=x, y=y, line=text[i], font=font, letter_spacing=LETTER_SPACING, fill=FILL, stroke_width=STROKE_WIDTH, stroke_fill=STROKE_FILL) + + y += txt_height + LINE_SPACING + + img = img.resize((int(BASE_WIDTH/2), int(float(img.size[1]) * (BASE_WIDTH/2) / img.size[0]))) + + if img.mode in ("RGBA", "P"): + img = img.convert("RGB") + + return img + +def text_effect(text: str, img: Image): + LETTER_SPACING = 1 + LINE_SPACING = 3 + STROKE_WIDTH = 1 + STROKE_FILL = (0, 0, 0) + FONT_BASE = 75 + MARGIN = 10 + LINE_WIDTH = 20 + + img = img.resize((BASE_WIDTH, int(img.size[1] * float(BASE_WIDTH / img.size[0])))) + + text = textwrap.wrap(text, width=LINE_WIDTH) + if text == []: + return + + font = ImageFont.truetype(font=ARIAL_FONT_FILE, size=FONT_BASE) + + img_width, img_height = img.size + d = ImageDraw.Draw(img) + + _, _, max_txt_width, txt_height = d.textbbox((0, 0), text[0], font=font) + + for line in text: + temp = int(font.getlength(line)) + if temp > max_txt_width: + max_txt_width = temp + + + total_height = (txt_height + LINE_SPACING) * len(text) + + y_inf = 0 + y_sup = img_height - total_height + x_inf = 0 + x_sup = img_width - max_txt_width - 5 + + fill = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) + x = random.randint(x_inf, x_sup) + y = random.randint(y_inf, y_sup) + for i in range(len(text)): + _draw_line(d=d, x=x, y=y, line=text[i], font=font, letter_spacing=LETTER_SPACING, fill=fill, stroke_width=STROKE_WIDTH, stroke_fill=STROKE_FILL) + + y += txt_height + LINE_SPACING + + img = img.resize((int(BASE_WIDTH/2), int(float(img.size[1]) * (BASE_WIDTH/2) / img.size[0]))) + + if img.mode in ("RGBA", "P"): + img = img.convert("RGB") + + return img + def test_multiple(text, effect, modifier=""): imgs = os.listdir("test") for i in range(len(imgs)):@@ -149,9 +244,9 @@
print("Image test successful") def main(): - #test("Autore\ntesto un po' più lungo ma non troppo eh\nquesto verrà scartato\npure questo", splash_effect) - test_multiple("top text\nbottom text", splash_effect) - test_multiple("top text top text top text top text top text\nbottom text bottom text bottom text bottom text bottom text", splash_effect, "_long") + test("Autore più lungo del solito per vedere se va a capo\ntesto un po' più lungo ma non troppo eh\nquesto verrà scartato\npure questo lorem ipsum prova ", text_effect) + #test_multiple("top text\nbottom text", splash_effect) + #test_multiple("top text top text top text top text top text\nbottom text bottom text bottom text bottom text bottom text", splash_effect, "_long") if __name__ == "__main__": main()
@@ -1,7 +1,6 @@
from PIL import Image from Api import get_random_image, rating_normal, rating_lewd -from Effects import tt_bt_effect, splash_effect -import Constants as C +from Effects import tt_bt_effect, splash_effect, wot_effect, text_effect from Constants import get_localized_string as l from dotenv import load_dotenv@@ -10,17 +9,19 @@ import os, logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) from io import BytesIO -from telegram.error import TelegramError, BadRequest +from telegram.error import TelegramError from telegram.ext import Updater, CallbackContext, CommandHandler, MessageHandler, Filters, PicklePersistence from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton lang = 'us' def _get_args(context): + logging.info(context.args) return ' '.join(context.args) def _img_to_bio(image): + bio = BytesIO() if image.mode in ("RGBA", "P"):@@ -30,17 +31,8 @@ image.save(bio, 'JPEG')
bio.seek(0) return bio -def _ttbt_general(context, text, image=None): - if text.strip() == "": - return None, l("no_caption", lang) +def _get_message_content(message): - markup = "" - if image is None: - image, markup = _get_image(context, bio=False) - image = _img_to_bio(tt_bt_effect(text, image)) - return image, markup - -def _get_message_content(message): image = None if len(message.photo) > 0: image = message.photo[-1].get_file()@@ -62,24 +54,28 @@ except IndexError:
pass lines[0] = " ".join(r) - return image, "\n".join(lines) + content = "\n".join(lines) + + return image, content, _get_author(message) def _get_reply(message, fallback=""): if message is None: - return None, fallback + return None, fallback, None - image, content = _get_message_content(message) + image, content, author = _get_message_content(message) - return image, content + return image, content, author def _get_lewd(context): + try: return context.chat_data["lewd"] except KeyError: return False def _get_image(context, tag="", bio=True): + if context is not None: if _get_lewd(context): image, url = get_random_image(rating_lewd, tag)@@ -97,34 +93,49 @@ return _img_to_bio(image), markup
return image, markup def _get_all(update, check_fn, context): - author = _get_author(update.message) - image_reply, reply = _get_reply(update.message.reply_to_message) - image_content, content = _get_message_content(update.message) + image_reply, text_reply, author_reply = _get_reply(update.message.reply_to_message) + image_content, text_content, author_content = _get_message_content(update.message) + + info_struct = { + "reply": { + "author": author_reply, + "text": text_reply, + "image": image_reply + }, + "content": { + "author": author_content, + "text": text_content, + "image": image_content + } + } + logging.info(f"User {update.message.from_user.username} typed: {str(update.message.text)}") - content = check_fn(author, reply, content) + content = check_fn(info_struct) if content is None: return None, None, None markup = "" image = None + if image_reply is not None: image = image_reply - + if image_content is not None: image = image_content if image is None: image, markup = _get_image(context, bio=False) - + return content, image, markup def start(update: Update, context: CallbackContext): context.bot.send_message(chat_id=update.effective_chat.id, text=l("welcome", lang)) def set_lewd(update: Update, context: CallbackContext): + try: output = False if context.chat_data["lewd"] else True except KeyError:@@ -136,6 +147,7 @@
context.bot.send_message(chat_id=update.effective_chat.id, text=message) def pic(update: Update, context: CallbackContext): + try: tag = " " + context.args[0] except IndexError:@@ -145,6 +157,7 @@ image, markup = _get_image(context, tag)
update.message.reply_photo(photo=image, parse_mode="markdown", reply_markup=markup) def raw(update: Update, context: CallbackContext): + tag = "" try: tag += " " + context.args[0]@@ -164,6 +177,7 @@
update.message.reply_photo(photo=image, parse_mode="markdown", reply_markup=markup) def pilu(update: Update, context: CallbackContext): + logging.warning(f"User {update.message.from_user.username} requested an explicit pic.") try: tag = " " + context.args[0]@@ -181,24 +195,29 @@
update.message.reply_photo(photo=image, parse_mode="markdown", reply_markup=markup) def _format_author(user): + if user.username is not None: return user.full_name + f" ({user.username})" return user.full_name def _get_author(message): - if message.reply_to_message is None: - return _format_author(message.from_user) + if message.forward_from is not None: + return _format_author(message.forward_from) - if message.reply_to_message.forward_from is not None: - return _format_author(message.reply_to_message.forward_from) + if message.forward_sender_name is not None: + return message.forward_sender_name - if message.reply_to_message.forward_sender_name is not None: - return message.reply_to_message.forward_sender_name + if message.forward_from_chat is not None: + return message.forward_from_chat.title + ("" if message.forward_from_chat.username is None else f" ({message.forward_from_chat.username})") - return _format_author(message.reply_to_message.from_user) + return _format_author(message.from_user) -def tt_check(author, content, reply): +def tt_check(info): + + reply = info['reply']['text'] + content = info['content']['text'] + input_text = f"{reply} {content}".replace("\n", " ") if input_text.strip() == "":@@ -206,7 +225,11 @@ return None
return input_text -def ttbt_check(author, content, reply): +def ttbt_check(info): + + reply = info['reply']['text'] + content = info['content']['text'] + input_text = f"{reply}\n{content}" if input_text.strip() == "":@@ -214,7 +237,16 @@ return None
return input_text -def splash_check(author, content, reply): +def splash_check(info): + + reply = info['reply']['text'] + content = info['content']['text'] + + if content.strip() == "": + author = info['reply']['author'] + else: + author = info['content']['author'] + input_text = f"{author}\n{content}\n{reply}" if len(input_text.strip().split("\n")) < 2:@@ -222,7 +254,20 @@ return None
return input_text +def wot_check(info): + + reply = info['reply']['text'] + content = info['content']['text'] + + input_text = f"{reply}\n{content}" + + if input_text.strip() == "": + return None + + return input_text + def ttbt(update: Update, context: CallbackContext): + content, image, markup = _get_all(update, ttbt_check, context) if image is None:@@ -234,6 +279,7 @@ update.message.reply_photo(photo=image, reply_markup=markup)
def tt(update: Update, context: CallbackContext): + content, image, markup = _get_all(update, tt_check, context) if image is None:@@ -244,6 +290,7 @@ image = _img_to_bio(tt_bt_effect(content, image))
update.message.reply_photo(photo=image, reply_markup=markup) def bt(update: Update, context: CallbackContext): + content, image, markup = _get_all(update, tt_check, context) if image is None:@@ -254,6 +301,7 @@ image = _img_to_bio(tt_bt_effect("\n" + content, image))
update.message.reply_photo(photo=image, reply_markup=markup) def splash(update: Update, context: CallbackContext): + content, image, markup = _get_all(update, splash_check, context) if image is None:@@ -262,9 +310,32 @@ return
image = _img_to_bio(splash_effect(content, image)) update.message.reply_photo(photo=image, reply_markup=markup) + +def wot(update: Update, context: CallbackContext): + + content, image, markup = _get_all(update, wot_check, context) + + if image is None: + update.message.reply_text(l("no_caption", lang)) + return + + image = _img_to_bio(wot_effect(content, image)) + update.message.reply_photo(photo=image, reply_markup=markup) + +def text(update: Update, context: CallbackContext): + + content, image, markup = _get_all(update, wot_check, context) + + if image is None: + update.message.reply_text(l("no_caption", lang)) + return + + image = _img_to_bio(text_effect(content, image)) + update.message.reply_photo(photo=image, reply_markup=markup) def caps(update: Update, context: CallbackContext): - _, reply = _get_reply(update.message.reply_to_message, _get_args(context)) + + _, reply, _ = _get_reply(update.message.reply_to_message, _get_args(context)) context.bot.send_message(chat_id=update.effective_chat.id, text=reply.upper()) def unknown(update: Update, context: CallbackContext):@@ -303,6 +374,8 @@ _add_effect_handler(dispatcher, 'ttbt', ttbt)
_add_effect_handler(dispatcher, 'tt', tt) _add_effect_handler(dispatcher, 'bt', bt) _add_effect_handler(dispatcher, 'splash', splash) + _add_effect_handler(dispatcher, 'wot', wot) + _add_effect_handler(dispatcher, 'text', text) dispatcher.add_handler(MessageHandler(Filters.command, unknown)) updater.start_polling()