commit 3fae24ba1ef243546e888475471bd2f0d72080ba Author: klemek Date: Sat Apr 11 12:40:19 2020 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..451fb35 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +.idea \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2fcdf5 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# meme-otron + +### WIP \ No newline at end of file diff --git a/discord/bot.py b/discord/bot.py new file mode 100644 index 0000000..76e3488 --- /dev/null +++ b/discord/bot.py @@ -0,0 +1,123 @@ +import os +import traceback +import logging +import discord +import re +import tempfile +from datetime import datetime +from dotenv import load_dotenv + +from meme_otron import img_factory as imgf +from meme_otron import meme_db as db +from meme_otron import utils +from meme_otron import main + +VERSION = "1.0-dev" +t0 = datetime.now() +logging.basicConfig(format="[%(asctime)s][%(levelname)s][%(module)s] %(message)s", level=logging.INFO) + +imgf.load_fonts() +db.load_memes() + +# Loading token +load_dotenv() +token = os.getenv('DISCORD_TOKEN') + +client = discord.Client() + + +def debug(message, txt): + """ + Print a log with the context of the current event + + :param (discord.Message) message: message that triggered the event + :param (str) txt: text of the log + """ + logging.info(f"{message.guild} > #{message.channel}: {txt}") + + +@client.event +async def on_ready(): + """ + Called when client is connected + """ + # Change status + await client.change_presence( + activity=discord.Game(f"v{VERSION}"), + status=discord.Status.online + ) + # Debug connected guilds + logging.info(f'{client.user} v{VERSION} has connected to Discord\nto the following guilds:') + for guild in client.guilds: + logging.info(f'- {guild.name}(id: {guild.id})') + + +@client.event +async def on_message(message): + """ + Called when a message is sent to any channel on any guild + + :param (discord.Message) message: message sent + """ + # Ignore self messages + if message.author == client.user: + return + direct = message.channel.type == discord.ChannelType.private + if direct or client.user in message.mentions: + message.content = re.sub(r'<@[^>]+>', '', message.content).strip() + args = utils.parse_arguments(message.content) + debug(message, str(args)) + if len(args) == 0 or args[0].lower().strip() == "help": + await message.channel.send(f"Hey {message.author.mention},\n" + f"You can generate a meme with the syntax\n" + f"```\n" + f"[template] \"text 1\" \"text 2\" ...\n" + f"```" + f"You can find a more detailed help and a list of templates at:\n" + f"") + return + async with message.channel.typing(): + left_wmark_text = None + if not direct and len(args) > 1: + f"By {message.author.display_name}" + img = main.compute(*args, left_wmark_text=left_wmark_text) + if img is None: + await message.channel.send(f"Template `{args[0]}` not found\n" + f"You can find a more detailed help and a list of templates at:\n" + f"") + return + with tempfile.NamedTemporaryFile() as output: + img.save(output, format="JPEG") + response = None + if len(args) == 1: + response = f"Template `{args[0]}`:" + elif not direct: + response = f"A meme by {message.author.mention}:" + await message.channel.send(response, + file=discord.File(filename="meme.jpg", fp=output.name)) + if not direct: + try: + await message.delete() + except discord.Forbidden: + pass + except discord.NotFound: + pass + + +# Launch client and rerun on errors +while True: + try: + client.run(token) + break # clean kill + except Exception as e: + t = datetime.now() + logging.error(f"Exception raised at {t:%Y-%m-%d %H:%M} : {repr(e)}") + fileName = f"error_{t:%Y-%m-%d_%H-%M-%S}.txt" + if os.path.exists(fileName): + logging.error("Two many errors, killing") + break + with open(fileName, 'w') as f: + f.write(f"Discord AI Dungeon 2 v{VERSION} started at {t0:%Y-%m-%d %H:%M}\r\n" + f"Exception raised at {t:%Y-%m-%d %H:%M}\r\n" + f"\r\n" + f"{traceback.format_exc()}") diff --git a/discord/requirements.txt b/discord/requirements.txt new file mode 100644 index 0000000..7838f85 --- /dev/null +++ b/discord/requirements.txt @@ -0,0 +1,3 @@ +discord +python-dotenv +requests diff --git a/docs/build_docs.py b/docs/build_docs.py new file mode 100644 index 0000000..92a17c7 --- /dev/null +++ b/docs/build_docs.py @@ -0,0 +1,25 @@ +import os +import logging +from os import path +from meme_otron import img_factory as imgf +from meme_otron import meme_db + +logging.basicConfig(format="[%(asctime)s][%(levelname)s][%(module)s] %(message)s", level=logging.DEBUG) + +imgf.load_fonts() +meme_db.load_memes() + +dst_dir = path.abspath("templates") + +for f in os.listdir(dst_dir): + if path.isfile(path.join(dst_dir, f)): + os.unlink(path.join(dst_dir, f)) + + +for meme_id in meme_db.DATA: + meme = meme_db.get_meme(meme_id) + if meme is not None: + img = imgf.make(meme.template, meme.texts, debug=True) + img.save(path.join(dst_dir, meme.template)) + print(meme_id) + diff --git a/docs/templates/brain3.jpg b/docs/templates/brain3.jpg new file mode 100644 index 0000000..824fd4c Binary files /dev/null and b/docs/templates/brain3.jpg differ diff --git a/docs/templates/brain4.jpg b/docs/templates/brain4.jpg new file mode 100644 index 0000000..9eeff5a Binary files /dev/null and b/docs/templates/brain4.jpg differ diff --git a/docs/templates/brain5.jpg b/docs/templates/brain5.jpg new file mode 100644 index 0000000..8bcc234 Binary files /dev/null and b/docs/templates/brain5.jpg differ diff --git a/docs/templates/disappointed.jpg b/docs/templates/disappointed.jpg new file mode 100644 index 0000000..d51959a Binary files /dev/null and b/docs/templates/disappointed.jpg differ diff --git a/docs/templates/drake.jpg b/docs/templates/drake.jpg new file mode 100644 index 0000000..6f62d32 Binary files /dev/null and b/docs/templates/drake.jpg differ diff --git a/docs/templates/nope.jpg b/docs/templates/nope.jpg new file mode 100644 index 0000000..45db123 Binary files /dev/null and b/docs/templates/nope.jpg differ diff --git a/docs/templates/pleasure3.jpg b/docs/templates/pleasure3.jpg new file mode 100644 index 0000000..ff5743c Binary files /dev/null and b/docs/templates/pleasure3.jpg differ diff --git a/docs/templates/pleasure4.jpg b/docs/templates/pleasure4.jpg new file mode 100644 index 0000000..f6ba669 Binary files /dev/null and b/docs/templates/pleasure4.jpg differ diff --git a/docs/templates/tough2.jpg b/docs/templates/tough2.jpg new file mode 100644 index 0000000..87352c4 Binary files /dev/null and b/docs/templates/tough2.jpg differ diff --git a/docs/templates/tough2bis.jpg b/docs/templates/tough2bis.jpg new file mode 100644 index 0000000..fe1193e Binary files /dev/null and b/docs/templates/tough2bis.jpg differ diff --git a/docs/templates/tough3.jpg b/docs/templates/tough3.jpg new file mode 100644 index 0000000..868708d Binary files /dev/null and b/docs/templates/tough3.jpg differ diff --git a/docs/templates/winnie2.jpg b/docs/templates/winnie2.jpg new file mode 100644 index 0000000..983f73c Binary files /dev/null and b/docs/templates/winnie2.jpg differ diff --git a/docs/templates/winnie3.jpg b/docs/templates/winnie3.jpg new file mode 100644 index 0000000..c0c2fdc Binary files /dev/null and b/docs/templates/winnie3.jpg differ diff --git a/fonts/arial.ttf b/fonts/arial.ttf new file mode 100644 index 0000000..7ff88f2 Binary files /dev/null and b/fonts/arial.ttf differ diff --git a/fonts/arial_black.ttf b/fonts/arial_black.ttf new file mode 100644 index 0000000..b51c8c2 Binary files /dev/null and b/fonts/arial_black.ttf differ diff --git a/fonts/impact.ttf b/fonts/impact.ttf new file mode 100644 index 0000000..114e6c1 Binary files /dev/null and b/fonts/impact.ttf differ diff --git a/meme_otron/__init__.py b/meme_otron/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/meme_otron/__pycache__/__init__.cpython-37.pyc b/meme_otron/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000..6b44e0b Binary files /dev/null and b/meme_otron/__pycache__/__init__.cpython-37.pyc differ diff --git a/meme_otron/__pycache__/img_factory.cpython-37.pyc b/meme_otron/__pycache__/img_factory.cpython-37.pyc new file mode 100644 index 0000000..ad8d471 Binary files /dev/null and b/meme_otron/__pycache__/img_factory.cpython-37.pyc differ diff --git a/meme_otron/__pycache__/main.cpython-37.pyc b/meme_otron/__pycache__/main.cpython-37.pyc new file mode 100644 index 0000000..99ae78e Binary files /dev/null and b/meme_otron/__pycache__/main.cpython-37.pyc differ diff --git a/meme_otron/__pycache__/meme_db.cpython-37.pyc b/meme_otron/__pycache__/meme_db.cpython-37.pyc new file mode 100644 index 0000000..37874fd Binary files /dev/null and b/meme_otron/__pycache__/meme_db.cpython-37.pyc differ diff --git a/meme_otron/__pycache__/types.cpython-37.pyc b/meme_otron/__pycache__/types.cpython-37.pyc new file mode 100644 index 0000000..8d0f6e1 Binary files /dev/null and b/meme_otron/__pycache__/types.cpython-37.pyc differ diff --git a/meme_otron/__pycache__/utils.cpython-37.pyc b/meme_otron/__pycache__/utils.cpython-37.pyc new file mode 100644 index 0000000..495f80b Binary files /dev/null and b/meme_otron/__pycache__/utils.cpython-37.pyc differ diff --git a/meme_otron/img_factory.py b/meme_otron/img_factory.py new file mode 100644 index 0000000..893b607 --- /dev/null +++ b/meme_otron/img_factory.py @@ -0,0 +1,146 @@ +from PIL import Image, ImageFont, ImageDraw +import os +import os.path as path +import logging + +DEFAULT_FONT = "arial" +DEFAULT_FONT_SIZE = 0.05 + +FONT_DIR = "../fonts" +TEMPLATES_DIR = "../templates" + +FONTS = {} + +logger = logging.getLogger("img_factory") + + +def load_fonts(): + """ + TODO + """ + for file in [f for f in os.listdir(FONT_DIR) if path.isfile(path.join(FONT_DIR, f))]: + split = path.splitext(file) + if split[-1] == ".ttf": + try: + FONTS[split[0]] = ImageFont.truetype(path.join(FONT_DIR, file)) + logger.info(f"Loaded font '{split[0]}'") + except OSError: + logger.error(f"Could not load font '{split[0]}'") + + +def make(template, texts, debug=False): + """ + TODO + + :param (str) template: + :param (list of Text) texts: + :param (bool) debug: + :rtype: PIL.Image.Image + :return: + """ + try: + img = Image.open(path.join(TEMPLATES_DIR, template)) + except OSError as e: + logger.error(f"Could not read template file '{template}': {e}") + return None + draw = ImageDraw.Draw(img) + + for text in texts: + draw_text(draw, img.size, text, debug=debug) + + return img + + +def draw_text(draw, size, text, debug=False): + """ + TODO + + :param (PIL.ImageDraw.ImageDraw) draw: source image canvas + :param (int,int) size: source image size + :param (Text) text: + :param (bool) debug: + """ + # TODO rotation + # https://stackoverflow.com/questions/245447/how-do-i-draw-text-at-an-angle-using-pythons-pil + if text.text is not None and len(text.text.strip()) > 0: + if text.font is None: + text.font = DEFAULT_FONT + if text.font in FONTS: + text.text, font = fit_text(size, text) + draw.text(get_pos(size, text, font), text.text, fill=text.fill, align=text.align, font=font, + stroke_width=round(text.stroke_width * font.size), stroke_fill=text.stroke_fill) + if debug: + draw.rectangle([(text.x_range[0] * size[0], text.y_range[0] * size[1]), + (text.x_range[1] * size[0], text.y_range[1] * size[1])], + None, + (128, 128, 128)) + else: + logger.warning(f"Invalid font '{text.font}'") + + +def fit_text(size, text): + """ + :param (int,int) size: source image size + :param (Text) text: + :rtype: (str, PIL.ImageFont.FreeTypeFont) + :return: + """ + max_width = round(size[0] * (text.x_range[1] - text.x_range[0])) + max_height = round(size[1] * (text.y_range[1] - text.y_range[0])) + text_size = None + if text.font_size is None: + text.font_size = DEFAULT_FONT_SIZE + font_size = round(text.font_size * min(size)) + 1 + font = FONTS[text.font] + t = "" + while (text_size is None or text_size[1] >= max_height) and font_size > 1: + font_size -= 1 + font = font.font_variant(size=font_size) + words = text.text.split(" ") + t = "" + for word in words: + spacer = " " + if len(t) == 0: + spacer = "" + text_size = font.getsize_multiline(t + spacer + word, stroke_width=text.stroke_width * font_size) + if text_size[0] >= max_width: + t += "\n" + word + else: + t += spacer + word + text_size = font.getsize_multiline(t, stroke_width=text.stroke_width * font_size) + return t, font + + +def get_pos(size, text, font): + """ + TODO + + :param (int,int) size: source image size + :param (Text) text: + :param (PIL.ImageFont.FreeTypeFont) font: + :rtype (int,int) + :return: + """ + min_x = round(text.x_range[0] * size[0]) + max_x = round(text.x_range[1] * size[0]) + min_y = round(text.y_range[0] * size[1]) + max_y = round(text.y_range[1] * size[1]) + pos_x = 0 + pos_y = 0 + text_size = font.getsize_multiline(text.text, stroke_width=text.stroke_width * font.size) + + if text.position.value[0] == "S": + pos_y = min_y + elif text.position.value[0] == "C": + pos_y = round((min_y + max_y) / 2 - text_size[1] / 2) + elif text.position.value[0] == "N": + pos_y = max_y - text_size[1] + + if text.position.value[1] == "W": + pos_x = min_x + elif text.position.value[1] == "C": + pos_x = round((min_x + max_x) / 2 - text_size[0] / 2) + elif text.position.value[1] == "E": + pos_x = max_x - text_size[0] + + return pos_x, pos_y diff --git a/meme_otron/main.py b/meme_otron/main.py new file mode 100644 index 0000000..f201bbf --- /dev/null +++ b/meme_otron/main.py @@ -0,0 +1,63 @@ +import logging +import sys +import os + +from .types import Text, Pos +from . import img_factory as imgf +from . import meme_db as db + +logger = logging.getLogger("meme_otron") + +right_wmark = Text("Made with meme-otron") +right_wmark.position = Pos.SE +right_wmark.fill = (128, 128, 128, 128) +right_wmark.font_size = 0.02 +right_wmark.x_range = [0.005, 0.995] +right_wmark.y_range = [0.005, 0.995] + +left_wmark = Text() +left_wmark.position = Pos.SW +left_wmark.fill = (128, 128, 128, 128) +left_wmark.font_size = 0.02 +left_wmark.x_range = [0.005, 0.995] +left_wmark.y_range = [0.005, 0.995] + + +def compute(*args, left_wmark_text=None, debug=False): + """ + TODO + + :param (str) left_wmark_text: + :param (bool) debug: + :param (str) args: + :rtype: PIL.Image.Image + :return: + """ + if len(args) < 1: + logger.warning("python3 meme_otron.py (meme_id) \"[text 1]\" \"[text 2]\" ... > file.jpg") + return None + meme_id = args[0] + meme = db.get_meme(meme_id) + if meme is None: + logger.warning(f"Meme template '{meme_id}' not found") + return None + if len(args) > 1: + for i in range(len(meme.texts)): + if i < len(args) - 1: + meme.texts[i].text = args[i + 1] + else: + meme.texts[i].text = "" + meme.texts += [right_wmark] + if left_wmark_text is not None: + left_wmark.text = left_wmark_text + meme.texts += [left_wmark] + return imgf.make(meme.template, meme.texts, debug=debug) + + +if __name__ == "__main__": + logging.basicConfig(format="[%(asctime)s][%(levelname)s][%(module)s] %(message)s", level=logging.DEBUG) + db.load_memes() + imgf.load_fonts() + img = compute(*sys.argv[1:]) + with os.fdopen(os.dup(sys.stdout.fileno())) as output: + img.save(output, format="jpeg") diff --git a/meme_otron/meme_db.py b/meme_otron/meme_db.py new file mode 100644 index 0000000..90da643 --- /dev/null +++ b/meme_otron/meme_db.py @@ -0,0 +1,173 @@ +import json +import logging + +from .types import Pos, Text, Meme +from . import utils + +DATA_FILE = "../memes.json" + +DATA = {} +ALIASES = {} + +logger = logging.getLogger("meme_db") + + +def load_memes(): + """ + TODO + """ + try: + with open(DATA_FILE) as f: + content = "".join(f.readlines()) + raw_data = json.loads(content) + if not (isinstance(raw_data, list)): + raise TypeError(f"Root is not a list") + for i in range(len(raw_data)): + load_item(i, raw_data[i]) + except OSError as e: + logger.error(f"Could not read data file: {e}") + except json.decoder.JSONDecodeError as e: + logger.error(f"Wrong JSON syntax '{DATA_FILE}': {e}") + except TypeError as e: + logger.error(f"Invalid data file: {e}") + + +def load_item(i, item): + """ + TODO + + :param (int) i: + :param (dict) item: + """ + item_id = "" + try: + if not (isinstance(item, dict)): + raise TypeError(f"root is not a dict") + item_id = utils.read_key(item, "id") + if item_id in DATA: + raise NameError(f"id '{item_id}' already existing") + based_on = utils.read_key_safe(item, "based_on") + abstract = utils.read_key_safe(item, "abstract", False) + aliases = utils.read_key_safe(item, "aliases", []) + if not utils.is_list_of(aliases, [str]): + raise TypeError(f"'aliases' is not a list of str") + template = None + font = None + font_size = None + texts = None + if based_on is not None: + if based_on in DATA: + template = DATA[based_on].template + font = DATA[based_on].font + font_size = DATA[based_on].font_size + texts = DATA[based_on].clone_texts() + else: + raise NameError(f"Reference '{based_on}' not found in data, make sur it's placed before this one") + if not abstract: + template = utils.read_key(item, "template", template) + font = utils.read_key_safe(item, "font", font) + font_size = utils.read_key_safe(item, "font_size", font_size) + raw_texts = utils.read_key(item, "texts", texts) + if texts is None: + if not (isinstance(raw_texts, list)): + raise TypeError(f"'texts' is not a list") + texts = [] + for j in range(len(raw_texts)): + raw_text = raw_texts[j] + try: + texts += [load_text(j, raw_text)] + except TypeError as e: + logger.warning(f"Item '{item_id}'({i}) / Text {j}: {e}") + if font is not None: + if not (isinstance(font, str)): + raise TypeError(f"'font' is not a str") + for text in texts: + if text.font is None: + text.font = font + if font_size is not None: + if not (isinstance(font_size, float)): + raise TypeError(f"'font_size' is not a float") + for text in texts: + if text.font_size is None: + text.font_size = font_size + if len(texts) == 0: + logger.warning(f"Item '{item_id}'({i}): no texts loaded") + else: + DATA[item_id] = Meme(item_id, aliases, abstract, template, font, font_size, texts) + for alias in aliases: + ALIASES[alias] = item_id + logger.info(f"Loaded meme '{item_id}' with {len(texts)} texts") + except KeyError as e: + logger.warning(f"Item '{item_id}'({i}): key {e} not found") + except TypeError as e: + logger.warning(f"Item '{item_id}'({i}): {e}") + except NameError as e: + logger.warning(f"Item '{item_id}'({i}): {e}") + + +def load_text(j, raw_text): + """ + TODO + + :param (int) j: + :param (dict) raw_text: + :raises TypeError: + :rtype: Text + :return: + """ + if not (isinstance(raw_text, dict)): + raise TypeError(f"root is not a dict") + text = Text(f"text {j+1}") + if "font" in raw_text: + if not (isinstance(raw_text["font"], str)): + raise TypeError(f"'font' is not a str") + text.font = raw_text["font"] + if "x_range" in raw_text: + if not (utils.is_list_of(raw_text["x_range"], [int, float], 2)): + raise TypeError(f"'x_range' is not a list of 2 float") + text.x_range = raw_text["x_range"] + if "y_range" in raw_text: + if not (utils.is_list_of(raw_text["y_range"], [int, float], 2)): + raise TypeError(f"'y_range' is not a list of 2 float") + text.y_range = raw_text["y_range"] + if "position" in raw_text: + if raw_text["position"] not in [p.name for p in Pos]: + raise TypeError(f"'position' is not a valid position (ex: NW, E, SE, ...)") + text.position = [p for p in Pos if p.name == raw_text["position"]][0] + if "font_size" in raw_text: + if not (isinstance(raw_text["font_size"], float)): + raise TypeError(f"'font_size' is not a float") + text.font_size = raw_text["font_size"] + if "fill" in raw_text: + if not (utils.is_list_of(raw_text["fill"], [int], 3)): + raise TypeError(f"'fill' is not a list of 3 int") + text.fill = raw_text["fill"] + if "stroke_width" in raw_text: + if not (isinstance(raw_text["stroke_width"], float)): + raise TypeError(f"'stroke_width' is not a float") + text.stroke_width = raw_text["stroke_width"] + if "stroke_fill" in raw_text: + if not (utils.is_list_of(raw_text["stroke_fill"], [int], 3)): + raise TypeError(f"'stroke_fill' is not a list of 3 int") + text.stroke_fill = raw_text["stroke_fill"] + if "align" in raw_text: + if raw_text["align"] not in ["left", "center", "right"]: + raise TypeError(f"'align' is not 'left', 'center' or 'right'") + text.align = raw_text["align"] + return text + + +def get_meme(name): + """ + TODO + + :param (str) name: + :rtype: Meme|None + :return: + """ + if name in DATA and not DATA[name].abstract: + return DATA[name].clone() + elif name in ALIASES: + return DATA[ALIASES[name]].clone() + else: + return None diff --git a/meme_otron/types.py b/meme_otron/types.py new file mode 100644 index 0000000..002dbe5 --- /dev/null +++ b/meme_otron/types.py @@ -0,0 +1,62 @@ +from enum import Enum +import copy + + +class Pos(Enum): + """ + TODO + """ + NW = "NW" + N = "NC" + NE = "NE" + W = "CW" + CENTER = "CC" + E = "CE" + SW = "NW" + S = "NC" + SE = "NE" + + +class Meme: + """ + TODO + """ + + def __init__(self, meme_id, aliases, abstract, template, font, font_size, texts): + self.id = meme_id + self.aliases = aliases + self.abstract = abstract + self.template = template + self.font = font + self.font_size = font_size + self.texts = texts + + def clone_texts(self): + return copy.deepcopy(self.texts) + + def clone(self): + return Meme(self.id, + self.aliases, + self.abstract, + self.template, + self.font, + self.font_size, + self.clone_texts()) + + +class Text: + """ + TODO + """ + + def __init__(self, text=None): + self.text = text + self.x_range = (0, 1) + self.y_range = (0, 1) + self.position = Pos.CENTER + self.font_size = None + self.fill = (0, 0, 0) + self.stroke_width = 0 + self.stroke_fill = (0, 0, 0) + self.font = None + self.align = "center" diff --git a/meme_otron/utils.py b/meme_otron/utils.py new file mode 100644 index 0000000..edace2a --- /dev/null +++ b/meme_otron/utils.py @@ -0,0 +1,83 @@ +import re + + +def read_key_safe(d, k, default=None): + """ + TODO + + :param (dict) d: source dict + :param (str) k: key to read + :param default: default value + :return: + """ + if k in d: + return d[k] + else: + return default + + +def read_key(d, k, default=None): + """ + TODO + + :param (dict) d: source dict + :param (str) k: key to read + :param default: default value + :return: + """ + if k in d: + return d[k] + elif default is not None: + return default + else: + raise KeyError(k) + + +def is_list_of(obj, types, length=None): + """ + TODO + + :param obj: + :param (list of type) types: + :param (int) length: + :rtype: bool + :return: + """ + if not (isinstance(obj, list)): + return False + for item in obj: + found = False + for t in types: + if isinstance(item, t): + found = True + break + if not found: + return False + if length is not None and len(obj) != length: + return False + return True + + +def is_url(s): + """ + TODO + + :param (str) s: + :rtype: bool + :return: + """ + return False # TODO + + +args_regex = re.compile('"([^"]*)"|\'([^\']*)\'|([^ ]+)') + + +def parse_arguments(s): + """ + TODO + + :param (str) s: + :rtype: list of str + :return: + """ + return [[g for g in m if len(g) > 0][0] for m in args_regex.findall(s)] diff --git a/memes.json b/memes.json new file mode 100644 index 0000000..2ffa41e --- /dev/null +++ b/memes.json @@ -0,0 +1,183 @@ +[{ + "id": "2_panel_right", + "abstract": true, + "font": "arial", + "texts": [{ + "x_range": [0.52, 0.98], + "y_range": [0.00, 0.50] + }, { + "x_range": [0.52, 0.98], + "y_range": [0.50, 1.00] + }] +},{ + "id": "3_panel_right", + "abstract": true, + "font": "arial", + "texts": [{ + "x_range": [0.52, 0.98], + "y_range": [0.00, 0.33] + },{ + "x_range": [0.52, 0.98], + "y_range": [0.33, 0.67] + }, { + "x_range": [0.52, 0.98], + "y_range": [0.67, 1.00] + }] +},{ + "id": "4_panel_right", + "abstract": true, + "font": "arial", + "texts": [{ + "x_range": [0.52, 0.98], + "y_range": [0.00, 0.25] + },{ + "x_range": [0.52, 0.98], + "y_range": [0.25, 0.50] + },{ + "x_range": [0.52, 0.98], + "y_range": [0.50, 0.75] + },{ + "x_range": [0.52, 0.98], + "y_range": [0.75, 1.00] + }] +},{ + "id": "5_panel_right", + "abstract": true, + "font": "arial", + "texts": [{ + "x_range": [0.52, 0.98], + "y_range": [0.00, 0.20] + },{ + "x_range": [0.52, 0.98], + "y_range": [0.20, 0.40] + },{ + "x_range": [0.52, 0.98], + "y_range": [0.40, 0.60] + },{ + "x_range": [0.52, 0.98], + "y_range": [0.60, 0.80] + },{ + "x_range": [0.52, 0.98], + "y_range": [0.80, 1.00] + }] +},{ + "id": "2_panel_left", + "abstract": true, + "font": "arial", + "texts": [{ + "x_range": [0.02, 0.48], + "y_range": [0.00, 0.50] + }, { + "x_range": [0.02, 0.48], + "y_range": [0.50, 1.00] + }] +},{ + "id": "3_panel_left", + "abstract": true, + "font": "arial", + "texts": [{ + "x_range": [0.02, 0.48], + "y_range": [0.00, 0.33] + },{ + "x_range": [0.02, 0.48], + "y_range": [0.33, 0.67] + }, { + "x_range": [0.02, 0.48], + "y_range": [0.67, 1.00] + }] +},{ + "id": "4_panel_left", + "abstract": true, + "font": "arial", + "texts": [{ + "x_range": [0.02, 0.48], + "y_range": [0.00, 0.25] + },{ + "x_range": [0.02, 0.48], + "y_range": [0.25, 0.50] + },{ + "x_range": [0.02, 0.48], + "y_range": [0.50, 0.75] + },{ + "x_range": [0.02, 0.48], + "y_range": [0.75, 1.00] + }] +},{ + "id": "5_panel_left", + "abstract": true, + "font": "arial", + "texts": [{ + "x_range": [0.02, 0.48], + "y_range": [0.00, 0.20] + },{ + "x_range": [0.02, 0.48], + "y_range": [0.20, 0.40] + },{ + "x_range": [0.02, 0.48], + "y_range": [0.40, 0.60] + },{ + "x_range": [0.02, 0.48], + "y_range": [0.60, 0.80] + },{ + "x_range": [0.02, 0.48], + "y_range": [0.80, 1.00] + }] +},{ + "id": "drake", + "template": "drake.jpg", + "based_on": "2_panel_right" +},{ + "id": "brain3", + "template": "brain3.jpg", + "based_on": "3_panel_left" +},{ + "id": "brain4", + "aliases": ["brains"], + "template": "brain4.jpg", + "based_on": "4_panel_left" +},{ + "id": "brain5", + "template": "brain5.jpg", + "based_on": "5_panel_left" +},{ + "id": "disappointed", + "template": "disappointed.jpg", + "based_on": "2_panel_left" +},{ + "id": "nope", + "template": "nope.jpg", + "based_on": "2_panel_right" +},{ + "id": "pleasure3", + "aliases": ["satisfied3"], + "template": "pleasure3.jpg", + "based_on": "3_panel_left" +},{ + "id": "pleasure4", + "aliases": ["pleasure","satisfied","satisfied4"], + "template": "pleasure4.jpg", + "based_on": "4_panel_left" +},{ + "id": "tough2", + "aliases": ["tough", "fight"], + "template": "tough2.jpg", + "based_on": "2_panel_right" +},{ + "id": "tough2bis", + "aliases": ["soft"], + "template": "tough2bis.jpg", + "based_on": "2_panel_right" +},{ + "id": "tough3", + "template": "tough3.jpg", + "based_on": "3_panel_right" +},{ + "id": "winnie2", + "aliases": ["winnie"], + "template": "winnie2.jpg", + "based_on": "2_panel_right" +},{ + "id": "winnie3", + "template": "winnie3.jpg", + "based_on": "3_panel_right" +}] \ No newline at end of file diff --git a/templates/aliens.jpg b/templates/aliens.jpg new file mode 100644 index 0000000..502f1b8 Binary files /dev/null and b/templates/aliens.jpg differ diff --git a/templates/alive.jpg b/templates/alive.jpg new file mode 100644 index 0000000..c11d8d6 Binary files /dev/null and b/templates/alive.jpg differ diff --git a/templates/argument.jpg b/templates/argument.jpg new file mode 100644 index 0000000..2d10cea Binary files /dev/null and b/templates/argument.jpg differ diff --git a/templates/bender.jpg b/templates/bender.jpg new file mode 100644 index 0000000..c5b4e12 Binary files /dev/null and b/templates/bender.jpg differ diff --git a/templates/brain3.jpg b/templates/brain3.jpg new file mode 100644 index 0000000..ee7f04e Binary files /dev/null and b/templates/brain3.jpg differ diff --git a/templates/brain4.jpg b/templates/brain4.jpg new file mode 100644 index 0000000..4bf8cb4 Binary files /dev/null and b/templates/brain4.jpg differ diff --git a/templates/brain5.jpg b/templates/brain5.jpg new file mode 100644 index 0000000..567cd0a Binary files /dev/null and b/templates/brain5.jpg differ diff --git a/templates/buff.jpg b/templates/buff.jpg new file mode 100644 index 0000000..74950e2 Binary files /dev/null and b/templates/buff.jpg differ diff --git a/templates/burn.jpg b/templates/burn.jpg new file mode 100644 index 0000000..6b6a40f Binary files /dev/null and b/templates/burn.jpg differ diff --git a/templates/button.jpg b/templates/button.jpg new file mode 100644 index 0000000..2e88096 Binary files /dev/null and b/templates/button.jpg differ diff --git a/templates/bye_mom.jpg b/templates/bye_mom.jpg new file mode 100644 index 0000000..adafc95 Binary files /dev/null and b/templates/bye_mom.jpg differ diff --git a/templates/clock.jpg b/templates/clock.jpg new file mode 100644 index 0000000..4619043 Binary files /dev/null and b/templates/clock.jpg differ diff --git a/templates/culture.jpg b/templates/culture.jpg new file mode 100644 index 0000000..fa04313 Binary files /dev/null and b/templates/culture.jpg differ diff --git a/templates/damngina.jpg b/templates/damngina.jpg new file mode 100644 index 0000000..871af7b Binary files /dev/null and b/templates/damngina.jpg differ diff --git a/templates/disappointed.jpg b/templates/disappointed.jpg new file mode 100644 index 0000000..831ce34 Binary files /dev/null and b/templates/disappointed.jpg differ diff --git a/templates/dont_look.jpg b/templates/dont_look.jpg new file mode 100644 index 0000000..c565b50 Binary files /dev/null and b/templates/dont_look.jpg differ diff --git a/templates/drake.jpg b/templates/drake.jpg new file mode 100644 index 0000000..2f69d4f Binary files /dev/null and b/templates/drake.jpg differ diff --git a/templates/drift.jpg b/templates/drift.jpg new file mode 100644 index 0000000..edbcdd7 Binary files /dev/null and b/templates/drift.jpg differ diff --git a/templates/everywhere.jpg b/templates/everywhere.jpg new file mode 100644 index 0000000..e4db63a Binary files /dev/null and b/templates/everywhere.jpg differ diff --git a/templates/everywhere2.jpg b/templates/everywhere2.jpg new file mode 100644 index 0000000..86be9d2 Binary files /dev/null and b/templates/everywhere2.jpg differ diff --git a/templates/fight.jpg b/templates/fight.jpg new file mode 100644 index 0000000..5ab1aff Binary files /dev/null and b/templates/fight.jpg differ diff --git a/templates/fine.jpg b/templates/fine.jpg new file mode 100644 index 0000000..489166c Binary files /dev/null and b/templates/fine.jpg differ diff --git a/templates/flex_tape.jpg b/templates/flex_tape.jpg new file mode 100644 index 0000000..7ad1ebe Binary files /dev/null and b/templates/flex_tape.jpg differ diff --git a/templates/girl_cat.jpg b/templates/girl_cat.jpg new file mode 100644 index 0000000..4428c93 Binary files /dev/null and b/templates/girl_cat.jpg differ diff --git a/templates/grandma.jpg b/templates/grandma.jpg new file mode 100644 index 0000000..a626273 Binary files /dev/null and b/templates/grandma.jpg differ diff --git a/templates/gru.jpg b/templates/gru.jpg new file mode 100644 index 0000000..6ca77e4 Binary files /dev/null and b/templates/gru.jpg differ diff --git a/templates/handshake.jpg b/templates/handshake.jpg new file mode 100644 index 0000000..c125e19 Binary files /dev/null and b/templates/handshake.jpg differ diff --git a/templates/handshake2.jpg b/templates/handshake2.jpg new file mode 100644 index 0000000..39d3b84 Binary files /dev/null and b/templates/handshake2.jpg differ diff --git a/templates/idea.jpg b/templates/idea.jpg new file mode 100644 index 0000000..56469c2 Binary files /dev/null and b/templates/idea.jpg differ diff --git a/templates/mini.jpg b/templates/mini.jpg new file mode 100644 index 0000000..c724f29 Binary files /dev/null and b/templates/mini.jpg differ diff --git a/templates/nobody_cares.jpg b/templates/nobody_cares.jpg new file mode 100644 index 0000000..2ae0b83 Binary files /dev/null and b/templates/nobody_cares.jpg differ diff --git a/templates/nope.jpg b/templates/nope.jpg new file mode 100644 index 0000000..6fd8ded Binary files /dev/null and b/templates/nope.jpg differ diff --git a/templates/overconfident.jpg b/templates/overconfident.jpg new file mode 100644 index 0000000..531f2f2 Binary files /dev/null and b/templates/overconfident.jpg differ diff --git a/templates/patrick.jpg b/templates/patrick.jpg new file mode 100644 index 0000000..a1df505 Binary files /dev/null and b/templates/patrick.jpg differ diff --git a/templates/pigeon.jpg b/templates/pigeon.jpg new file mode 100644 index 0000000..1c7dc37 Binary files /dev/null and b/templates/pigeon.jpg differ diff --git a/templates/pills.jpg b/templates/pills.jpg new file mode 100644 index 0000000..3995aff Binary files /dev/null and b/templates/pills.jpg differ diff --git a/templates/pleasure3.jpg b/templates/pleasure3.jpg new file mode 100644 index 0000000..f321943 Binary files /dev/null and b/templates/pleasure3.jpg differ diff --git a/templates/pleasure4.jpg b/templates/pleasure4.jpg new file mode 100644 index 0000000..454a234 Binary files /dev/null and b/templates/pleasure4.jpg differ diff --git a/templates/salt_bae.jpg b/templates/salt_bae.jpg new file mode 100644 index 0000000..0b778d3 Binary files /dev/null and b/templates/salt_bae.jpg differ diff --git a/templates/scary.jpg b/templates/scary.jpg new file mode 100644 index 0000000..1c90ced Binary files /dev/null and b/templates/scary.jpg differ diff --git a/templates/scroll_of_truth.jpg b/templates/scroll_of_truth.jpg new file mode 100644 index 0000000..22510bf Binary files /dev/null and b/templates/scroll_of_truth.jpg differ diff --git a/templates/seagull.jpg b/templates/seagull.jpg new file mode 100644 index 0000000..2dcc389 Binary files /dev/null and b/templates/seagull.jpg differ diff --git a/templates/see_that_guy.jpg b/templates/see_that_guy.jpg new file mode 100644 index 0000000..991bb32 Binary files /dev/null and b/templates/see_that_guy.jpg differ diff --git a/templates/spiderman.jpg b/templates/spiderman.jpg new file mode 100644 index 0000000..11d4f51 Binary files /dev/null and b/templates/spiderman.jpg differ diff --git a/templates/struggle.jpg b/templates/struggle.jpg new file mode 100644 index 0000000..d5434f1 Binary files /dev/null and b/templates/struggle.jpg differ diff --git a/templates/suggestion.jpg b/templates/suggestion.jpg new file mode 100644 index 0000000..56b126f Binary files /dev/null and b/templates/suggestion.jpg differ diff --git a/templates/t_pose.jpg b/templates/t_pose.jpg new file mode 100644 index 0000000..d152c89 Binary files /dev/null and b/templates/t_pose.jpg differ diff --git a/templates/the_gate.jpg b/templates/the_gate.jpg new file mode 100644 index 0000000..40ac098 Binary files /dev/null and b/templates/the_gate.jpg differ diff --git a/templates/time_travellers.jpg b/templates/time_travellers.jpg new file mode 100644 index 0000000..4f20056 Binary files /dev/null and b/templates/time_travellers.jpg differ diff --git a/templates/tom_cousins.jpg b/templates/tom_cousins.jpg new file mode 100644 index 0000000..44be0bc Binary files /dev/null and b/templates/tom_cousins.jpg differ diff --git a/templates/tough2.jpg b/templates/tough2.jpg new file mode 100644 index 0000000..6bbc5ad Binary files /dev/null and b/templates/tough2.jpg differ diff --git a/templates/tough2bis.jpg b/templates/tough2bis.jpg new file mode 100644 index 0000000..7676759 Binary files /dev/null and b/templates/tough2bis.jpg differ diff --git a/templates/tough3.jpg b/templates/tough3.jpg new file mode 100644 index 0000000..697f24f Binary files /dev/null and b/templates/tough3.jpg differ diff --git a/templates/trump.jpg b/templates/trump.jpg new file mode 100644 index 0000000..27dff4d Binary files /dev/null and b/templates/trump.jpg differ diff --git a/templates/trust_nobody.jpg b/templates/trust_nobody.jpg new file mode 100644 index 0000000..bdf8304 Binary files /dev/null and b/templates/trust_nobody.jpg differ diff --git a/templates/wet.jpg b/templates/wet.jpg new file mode 100644 index 0000000..c9ba100 Binary files /dev/null and b/templates/wet.jpg differ diff --git a/templates/winnie2.jpg b/templates/winnie2.jpg new file mode 100644 index 0000000..9ecf644 Binary files /dev/null and b/templates/winnie2.jpg differ diff --git a/templates/winnie3.jpg b/templates/winnie3.jpg new file mode 100644 index 0000000..7bfca3d Binary files /dev/null and b/templates/winnie3.jpg differ diff --git a/templates/worthless.jpg b/templates/worthless.jpg new file mode 100644 index 0000000..80a3415 Binary files /dev/null and b/templates/worthless.jpg differ