import os from tempfile import TemporaryDirectory from time import sleep from PIL import Image from django.db import models from django import forms from django.forms import modelformset_factory from telegram import Update, UserProfilePhotos from telegram.ext import Dispatcher, CallbackContext, MessageHandler, Filters, CommandHandler from bots.models import TelegramBotModuleConfig class OverlayBotModuleConfig(TelegramBotModuleConfig): start_text = models.TextField(null=True, blank=True) type_error_text = models.TextField(null=True, blank=True) comment = models.TextField(blank=True, null=True) send_avatar_on_start = models.BooleanField(default=False) MODULE_NAME = 'Overlay' def start_handler(self, update: Update, ctx: CallbackContext): if self.send_avatar_on_start: with TemporaryDirectory() as d: src = os.path.join(d, 'src.jpg') photos = update.effective_user.get_profile_photos(limit=1) # type: UserProfilePhotos if photos.photos: q = photos.photos[0][-1].get_file().download(src) im = Image.open(q) self.create_image(update, im) elif self.type_error_text: update.effective_message.reply_text(self.type_error_text) elif self.start_text: update.effective_message.reply_text(self.start_text) def message_handler(self, update: Update, ctx: CallbackContext): if self.type_error_text: update.effective_message.reply_text(self.type_error_text) def photo_handler(self, update: Update, ctx: CallbackContext): with TemporaryDirectory() as d: src = os.path.join(d, 'src.jpg') q = update.effective_message.photo[-1].get_file().download(src) im = Image.open(q) self.create_image(update, im) def create_image(self, update: Update, im: Image.Image): with TemporaryDirectory() as d: out = os.path.join(d, 'out.png') im = im.convert('RGBA') # type: Image.Image overlay = Image.open(self.images.order_by('?').first().image.path).convert('RGBA') # type: Image.Image w, h = im.size min_side = min(w, h) overlay = overlay.resize((min_side, min_side), Image.LANCZOS) im.paste(overlay, ((w - min_side) // 2, (h - min_side) // 2), overlay) im.save(out) update.effective_message.reply_photo(open(out, 'rb'), caption=self.comment) def build_dispatcher(self, dispatcher: Dispatcher): dispatcher.add_handler(CommandHandler('start', self.start_handler)) dispatcher.add_handler(MessageHandler(Filters.photo, self.photo_handler)) dispatcher.add_handler(MessageHandler(Filters.all, self.message_handler)) return dispatcher @staticmethod def form_context_data(view, instance=None): ImageFormSet = modelformset_factory(OverlayImage, form=ImageForm, extra=3, can_delete=True) formset = ImageFormSet(queryset=instance.images.all() if instance else OverlayImage.objects.none()) return { 'formset': formset, } @staticmethod def form_valid(view, bots_form, config_form): ImageFormSet = modelformset_factory(OverlayImage, form=ImageForm, extra=3, can_delete=True) formset = ImageFormSet(view.request.POST, view.request.FILES, queryset=config_form.instance.images.all()) for form in formset.cleaned_data: if form: if form['DELETE']: form['id'].delete() elif form['image']: if form['id']: instance = form['id'] instance.image = form['image'] instance.save() else: OverlayImage.objects.create(config=config_form.instance, image=form['image']) class OverlayImage(models.Model): config = models.ForeignKey(OverlayBotModuleConfig, on_delete=models.CASCADE, related_name='images') image = models.ImageField() class ImageForm(forms.ModelForm): image = forms.ImageField(widget=forms.ClearableFileInput(attrs={'accept': 'image/png'}), required=False) class Meta: model = OverlayImage fields = 'image',