Let anyone Deltaify an image.
authorCMDR furrycat <elite@furrycat.net>
Mon, 26 Sep 2016 13:11:58 +0000 (14:11 +0100)
committerCMDR furrycat <elite@furrycat.net>
Mon, 26 Sep 2016 13:11:58 +0000 (14:11 +0100)
bot.py

diff --git a/bot.py b/bot.py
index d71cefd..603b6bf 100755 (executable)
--- a/bot.py
+++ b/bot.py
@@ -5,12 +5,15 @@ import bs4
 import discord
 import feedparser
 import hashlib
+import io
 import logging
+import math
 import os
 import pexpect
 import random
 import re
 import sys
+from PIL import Image
 
 dryrun = os.getenv('DRYRUN') is not None
 
@@ -110,14 +113,71 @@ def is_admin(server, member):
       return True
   return False
 
+def delta_avatar(url):
+  # Get Delta images.
+  bg = Image.open('DELTA-BG.png')
+  fg = Image.open('DELTA-FURRYTEMPLATE.png')
+  if not bg or not fg:
+    log.warning("Can't open Delta foreground and/or background image!")
+    return None
+  cutoff = bg.width / 2
+
+  # Get provided image.
+  fd = open_url(url)
+  if fd is None:
+    log.debug('Failed to open URL {} for avatar creation'.format(url))
+    return None
+  try:
+    image = Image.open(fd)
+  except:
+    log.warning('Failed to get image from {}'.format(url))
+    return None
+  fd.close()
+  if image is None:
+    return None
+
+  # Crop square.
+  box = None
+  if image.height > image.width:
+    top = math.floor((image.height - image.width) / 2)
+    box = 0, top, image.width - 1, top + image.width - 1
+  elif image.height < image.width:
+    left = math.floor((image.width - image.height) / 2)
+    box = left, 0, left + image.height - 1, image.height - 1
+  if box is not None:
+    cropped = image.crop(box)
+    image = cropped.copy()
+
+  # Scale leaving space for background.
+  if image.height > cutoff:
+    image.thumbnail((cutoff, cutoff))
+  elif image.height < cutoff:
+    width = image.width * 2
+    height = image.height * 2
+    bg.thumbnail((width, height))
+    fg.thumbnail((width, height))
+
+  # Pad with blank pixels.
+  padded = Image.new(image.mode, fg.size)
+  left = math.floor((padded.width - image.width) / 2)
+  top = math.floor((padded.height - image.height) / 2)
+  padded.paste(image, (left, top, left + image.width, top + image.height))
+
+  # Merge them.
+  result = Image.alpha_composite(Image.alpha_composite(bg, padded), fg)
+  b = io.BytesIO()
+  result.save(b, 'PNG')
+  return b.getvalue()
+
 @asyncio.coroutine
-def do_admin(message, command, raw):
-  result = yield from is_admin(message.server, message.author)
-  if not result:
-    yield from not_admin(message)
-    return
+def do_commands(message, command, raw, non_admin):
+  if not non_admin:
+    result = yield from is_admin(message.server, message.author)
+    if not result:
+      yield from not_admin(message)
+      return
 
-  log.debug('Admin command: {}'.format(raw))
+  log.debug('Command: {}'.format(raw))
 
   if command == 'avatar':
     # avatar
@@ -139,6 +199,25 @@ def do_admin(message, command, raw):
     yield from client.edit_profile(avatar = fd.read())
     fd.close()
 
+  elif command == 'bling':
+    # bling
+    url = None
+    m = re.match(r'\bbling\s+(\S+)', raw.lower())
+    if m is not None:
+      url = m.group(1)
+    elif len(message.attachments):
+      url = message.attachments[0]['url']
+    if url is None:
+      log.debug('No URL for avatar to Deltaify')
+      yield from say(message.channel, 'zzz')
+      return
+    yield from client.send_typing(message.channel)
+    data = delta_avatar(url)
+    if data is None:
+      yield from say(message.channel, 'yelp!')
+      return
+    yield from client.send_file(message.channel, data, filename = message.author.name + '.png', content = message.author.mention if not message.channel.is_private else 'purr')
+
   elif command == 'debug':
     # debug
     m = re.match(r'\bdebug\s+(o(?:ff|n))\b', raw.lower())
@@ -326,10 +405,15 @@ wait_for_prompt(p)
 
 modules = {
   'admin': {
-    'fn': do_admin,
+    'fn': do_commands,
     'args': [],
     'commands': ['avatar', 'debug', 'delete', 'rss']
   },
+  'any': {
+    'fn': do_commands,
+    'args': [True],
+    'commands': ['bling']
+  },
   'edi': {
     'fn': do_edi,
     'args': [p],