68 Commits

Author SHA1 Message Date
CircleCI fc2dc0e4ed Automated README [ci skip] 2020-05-01 22:01:05 +00:00
Klemek b47a395b47 Merge pull request #3 from Klemek/dev
v1.3
2020-05-02 00:00:24 +02:00
klemek 839aff11f7 removed timeout test 2020-05-01 23:59:35 +02:00
klemek e4e61f866d v1.3 2020-05-01 23:57:46 +02:00
klemek d6503b9209 small formating 2020-05-01 23:57:16 +02:00
klemek 801edb3e20 final example for docs 2020-05-01 23:54:26 +02:00
klemek 534837d1d1 docs don't re-generate reaction + fixed tables 2020-05-01 23:46:27 +02:00
Klemek 84b6fd6ad2 first reactions 2020-05-01 23:37:07 +02:00
Klemek 0ef694fbc9 new templates 2020-05-01 23:16:31 +02:00
Klemek 84da593397 fixed db purge 2020-05-01 23:02:33 +02:00
Klemek 2070307c9d making levenstein lib optional 2020-05-01 22:59:40 +02:00
Klemek dca12b5d32 min width of 800 for templates 2020-05-01 22:53:01 +02:00
klemek 79ec20f0a4 Updated README.md 2020-05-01 22:41:05 +02:00
klemek 642338b69d damn you reformat 2020-05-01 22:40:26 +02:00
klemek 1aa26c06ef update of docs 2020-05-01 22:24:41 +02:00
klemek 6444a6e58d new unit tests 2020-05-01 21:02:25 +02:00
klemek 62afce22a6 more unit tests 2020-05-01 13:25:44 +02:00
klemek 6748073048 new docs separating templates / reactions 2020-05-01 13:05:17 +02:00
klemek 6cfd623685 fixed font size on most wide memes 2020-05-01 12:55:40 +02:00
klemek 28cd3f59d9 fixed db purge 2020-05-01 12:48:55 +02:00
klemek b2749898a5 changed some db loading features 2020-05-01 12:10:33 +02:00
klemek 6f38686513 better use of BytesIO 2020-04-30 09:12:05 +02:00
klemek 59a8530cbe checking image file size beforehand 2020-04-30 08:55:12 +02:00
klemek 671f6fd595 handling of errors on read_web 2020-04-30 08:50:38 +02:00
klemek 7c076b896f reading image data from input URL 2020-04-29 13:00:34 +02:00
klemek 7c0e292c91 fixed block on stdin empty 2020-04-29 13:00:14 +02:00
klemek f44e32fbf8 new url validate util + web file reading 2020-04-29 12:49:35 +02:00
klemek 9f46e8b8f9 prevent images from being too big for discord 2020-04-29 12:36:10 +02:00
klemek f99bfff3ed image data from message attachment 2020-04-29 12:31:48 +02:00
klemek f83ae349d6 reworked CLI + accept --input or piping 2020-04-29 12:25:40 +02:00
klemek 01afa3f16d wip meme part + can skip watermark 2020-04-29 12:25:21 +02:00
klemek 8caa7efb94 new stream util + non valued arg -> True/False 2020-04-29 12:24:52 +02:00
klemek b6d063e1e5 image mode from raw bytes 2020-04-29 12:23:49 +02:00
klemek 08c938719a error system: main -> CLI/bot instead of redoing it 2 times 2020-04-29 11:33:19 +02:00
klemek a7610c2f01 text part in meme pipeline 2020-04-28 18:11:09 +02:00
klemek dffdf656dc fixed final height not being accurate 2020-04-28 17:10:19 +02:00
klemek 27b1d422a6 simple memes piping 2020-04-28 17:07:22 +02:00
klemek 208a10c61e new arg util + code cleaning 2020-04-28 16:38:06 +02:00
klemek 462ec21a53 code cleaning 2020-04-28 16:28:29 +02:00
klemek 9e2d2fcce7 more unit tests 2020-04-28 16:17:12 +02:00
klemek 7e269c1ab5 1.3: new dev version 2020-04-28 16:17:05 +02:00
Klemek 9edff02dc0 Merge pull request #2 from Klemek/dev
v1.2
2020-04-27 21:06:15 +02:00
klemek f7759a93d0 updated docs 2020-04-27 21:04:53 +02:00
klemek 910a3abe6d v1.2 2020-04-27 21:03:24 +02:00
klemek 03fa2540e3 improved argument reading 2020-04-27 21:02:55 +02:00
klemek 4bb9bbb23a code cleaning 2020-04-27 19:14:28 +02:00
klemek 2223770fb8 bot: more input sanitization 2020-04-27 18:48:31 +02:00
klemek bb0d8853bb fixing circle-ci 2020-04-27 16:34:12 +02:00
klemek 19cfa1fb2f fixing circle-ci 2020-04-27 16:33:16 +02:00
klemek 1c44357bad fixed nearest word giving weird results 2020-04-27 16:27:07 +02:00
klemek 459b87a020 unit tests 2020-04-27 16:26:27 +02:00
klemek 1d05f87a5f fixed circle-ci 2020-04-27 15:13:03 +02:00
klemek 4c140461d0 test branch 2020-04-27 15:10:44 +02:00
klemek 1519e93d2e test branch 2020-04-27 15:09:44 +02:00
klemek b9a8300f3a fixed sending input unsafe 2020-04-27 15:07:00 +02:00
klemek fd8e0a6836 updated .gitignore 2020-04-27 14:40:00 +02:00
klemek 0e118871c1 docstring -> typing 2020-04-27 14:34:15 +02:00
klemek a533b64975 docstring -> typing 2020-04-27 14:34:01 +02:00
klemek f7ac7bc5ee docstring -> typing 2020-04-27 14:32:54 +02:00
klemek de22001504 code cleaning 2020-04-27 14:10:59 +02:00
klemek 8861f002ec reworked line breaks 2020-04-27 13:57:25 +02:00
klemek 2ff0309235 readme history 2020-04-27 11:50:00 +02:00
klemek b14793618d code cleaning 2020-04-27 11:49:47 +02:00
klemek a341fd517f utils: docstrings and unit tests 2020-04-27 00:36:38 +02:00
klemek 9739566e1b utils: docstrings and unit tests 2020-04-27 00:36:16 +02:00
klemek c87eb81e36 new dev version 2020-04-26 23:40:40 +02:00
klemek ff337ecea7 1.1 fixed arguments parsing 2020-04-26 23:38:01 +02:00
klemek cd329a9001 new dev version 2020-04-26 23:30:33 +02:00
191 changed files with 1501 additions and 454 deletions
+21 -5
View File
@@ -1,5 +1,15 @@
version: 2.1 version: 2.1
workflows:
main:
jobs:
- unit-tests
- build-docs:
filters:
branches:
only:
- master
jobs: jobs:
build-docs: build-docs:
docker: docker:
@@ -19,8 +29,14 @@ jobs:
git diff-index --quiet HEAD || git commit -m 'Automated README [ci skip]' git diff-index --quiet HEAD || git commit -m 'Automated README [ci skip]'
git push origin master git push origin master
name: Building docs name: Building docs
unit-tests:
workflows: docker:
main: - image: circleci/python:latest
jobs: steps:
- build-docs - checkout
- run:
command: |
sudo pip install -r requirements.txt
sudo pip install pytest
python -m pytest ./tests/unit
name: Unit tests
+2
View File
@@ -4,3 +4,5 @@ __pycache__
error_*.txt error_*.txt
tmp tmp
.key* .key*
*.pyc
.pytest_cache
+23
View File
@@ -42,3 +42,26 @@ It includes:
## Discord bot ## Discord bot
You can invite the bot on your server with [this link](https://discordapp.com/api/oauth2/authorize?client_id=704073533776723988&permissions=43072&scope=bot). You can invite the bot on your server with [this link](https://discordapp.com/api/oauth2/authorize?client_id=704073533776723988&permissions=43072&scope=bot).
## History
* 1.3
* **Complex memes syntax**
* Examples in docs
* "Reaction" templates
* Reworked CLI arguments
* More unit testing
* More docs
* Bug fix
* 1.2
* Reworked text fitting
* Unit testing
* More docs
* Bug fix
* 1.1
* More docs
* Bug fix
* Empty string fix
* 1.0
* Initial release
+53 -56
View File
@@ -3,17 +3,17 @@ import traceback
import logging import logging
import discord import discord
import re import re
import tempfile from io import BytesIO
import sys import sys
from datetime import datetime from datetime import datetime
from dotenv import load_dotenv from dotenv import load_dotenv
from meme_otron import img_factory as imgf from meme_otron import img_factory
from meme_otron import meme_db as db from meme_otron import meme_db
from meme_otron import utils from meme_otron import utils
from meme_otron import meme_otron from meme_otron import meme_otron
from meme_otron import VERSION
VERSION = "1.1"
DOC_URL = "https://github.com/klemek/meme-otron/tree/master/docs/README.md" DOC_URL = "https://github.com/klemek/meme-otron/tree/master/docs/README.md"
t0 = datetime.now() t0 = datetime.now()
logging.basicConfig(format="[%(asctime)s][%(levelname)s][%(module)s] %(message)s", level=logging.INFO) logging.basicConfig(format="[%(asctime)s][%(levelname)s][%(module)s] %(message)s", level=logging.INFO)
@@ -26,20 +26,17 @@ if token is None:
logging.error("No token was loaded, please verify your .env file") logging.error("No token was loaded, please verify your .env file")
sys.exit(1) sys.exit(1)
imgf.load_fonts() img_factory.load_fonts()
db.load_memes() meme_db.load_memes()
client = discord.Client() client = discord.Client()
SENT = {} SENT = {}
def debug(message, txt): def debug(message: discord.Message, txt: str):
""" """
Print a log with the context of the current event 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}") logging.info(f"{message.guild} > #{message.channel}: {txt}")
@@ -60,13 +57,7 @@ async def on_ready():
logging.info(f'- {guild.name}(id: {guild.id})') logging.info(f'- {guild.name}(id: {guild.id})')
async def delete(message): async def delete(message: discord.Message) -> bool:
"""
TODO
:param (discord.Message) message:
:rtype: bool
"""
try: try:
await message.delete() await message.delete()
return True return True
@@ -78,24 +69,22 @@ async def delete(message):
@client.event @client.event
async def on_message(message): async def on_message(message: discord.Message):
""" """
Called when a message is sent to any channel on any guild Called when a message is sent to any channel on any guild
:param (discord.Message) message: message sent
""" """
# Ignore self messages # Ignore self messages
if message.author == client.user: if message.author == client.user:
return return
direct = message.channel.type == discord.ChannelType.private is_direct = message.channel.type == discord.ChannelType.private
if not direct: if not is_direct:
mid = f'{message.guild.id}/{message.channel.id}/{message.author.id}' message_id = f'{message.guild.id}/{message.channel.id}/{message.author.id}'
else: else:
mid = message.author.id message_id = message.author.id
if direct or client.user in message.mentions: if is_direct or client.user in message.mentions:
message.content = re.sub(r'<@[^>]+>', '', message.content).strip() message.content = re.sub(r'<@[^>]+>', '', message.content).strip()
args = utils.parse_arguments(message.content) args = utils.parse_arguments(message.content)
debug(message, str(args)) debug(message, str(args))
@@ -113,11 +102,11 @@ async def on_message(message):
return return
if len(args) > 0 and args[0].lower().strip() == "list": if len(args) > 0 and args[0].lower().strip() == "list":
await message.channel.send(f"Here is a list of all known templates:\n" await message.channel.send(f"Here is a list of all known templates:\n"
f"```{', '.join(db.LIST)}```") f"```{', '.join(meme_db.LIST)}```")
return return
if len(args) > 0 and args[0].lower().strip() == "delete": if len(args) > 0 and args[0].lower().strip() == "delete":
if mid in SENT and len(SENT[mid]) > 0 and await delete(SENT[mid][-1]): if message_id in SENT and len(SENT[message_id]) > 0 and await delete(SENT[message_id][-1]):
if not direct: if not is_direct:
await delete(message) await delete(message)
else: else:
await message.add_reaction("") await message.add_reaction("")
@@ -126,21 +115,34 @@ async def on_message(message):
left_wmark_text = None left_wmark_text = None
if len(args) > 1 and message.author.display_name is not None: if len(args) > 1 and message.author.display_name is not None:
left_wmark_text = f"By {message.author.display_name}" left_wmark_text = f"By {message.author.display_name}"
img = meme_otron.compute(*args, left_wmark_text=left_wmark_text) logging.info(args[0])
if img is None:
hint = db.find_nearest(args[0]) input_data = None
response = f":warning: Template `{args[0]}` not found\n" if len(message.attachments) > 0:
if hint is not None: input_data = await message.attachments[0].read()
response += f"Did you mean `{hint}`?\n"
response += f"You can find a more detailed help and a list of templates at:\n" \ img, errors = meme_otron.compute(*args, left_wmark_text=left_wmark_text,
input_data=input_data, max_file_size=8 * 1024 * 1024)
if len(errors) > 0:
response = ":warning:"
for err in errors:
response += "\n" + err.replace("'", "`").replace("`` ", "")
response += f"\nYou can find a more detailed help and a list of templates at:\n" \
f"<{DOC_URL}>" f"<{DOC_URL}>"
if len(response) >= 2000:
await message.channel.send(f"{message.author.mention} ... really?")
else:
await message.channel.send(response) await message.channel.send(response)
else: else:
with tempfile.NamedTemporaryFile(delete=False) as output: with BytesIO() as output_file:
img.save(output, format="JPEG") img.save(output_file, format="JPEG")
output_file.flush()
output_file.seek(0)
response = None response = None
if len(args) == 1: meme_id = utils.sanitize_input(args[0])
meme = db.get_meme(args[0]) if len(args) == 1 and meme_id not in ["image", "text"]:
meme = meme_db.get_meme(meme_id)
response = f"Template `{meme.id}`:" response = f"Template `{meme.id}`:"
if len(meme.aliases) > 0: if len(meme.aliases) > 0:
response += f"\n- Aliases: `{'`, `'.join(meme.aliases)}`" response += f"\n- Aliases: `{'`, `'.join(meme.aliases)}`"
@@ -150,18 +152,13 @@ async def on_message(message):
f"\n```{meme.id} \"" + \ f"\n```{meme.id} \"" + \
"\" \"".join([f"text {i + 1}" for i in range(meme.texts_len)]) + \ "\" \"".join([f"text {i + 1}" for i in range(meme.texts_len)]) + \
"\"```" "\"```"
elif not direct: elif not is_direct:
response = f"A meme by {message.author.mention}:" response = f"A meme by {message.author.mention}:"
if mid not in SENT: if message_id not in SENT:
SENT[mid] = [] SENT[message_id] = []
response = await message.channel.send(response, response = await message.channel.send(response, file=discord.File(output_file, "meme.jpg"))
file=discord.File(filename="meme.jpg", fp=output.name)) SENT[message_id] += [response]
SENT[mid] += [response] if not is_direct:
try:
os.remove(output.name)
except PermissionError:
pass
if not direct:
await delete(message) await delete(message)
@@ -171,14 +168,14 @@ while True:
client.run(token) client.run(token)
break # clean kill break # clean kill
except Exception as e: except Exception as e:
t = datetime.now() exception_time = datetime.now()
logging.error(f"Exception raised at {t:%Y-%m-%d %H:%M} : {repr(e)}") logging.error(f"Exception raised at {exception_time:%Y-%m-%d %H:%M} : {repr(e)}")
fileName = f"error_{t:%Y-%m-%d_%H-%M-%S}.txt" fileName = f"error_{exception_time:%Y-%m-%d_%H-%M-%S}.txt"
if os.path.exists(fileName): if os.path.exists(fileName):
logging.error("Two many errors, killing") logging.error("Two many errors, killing")
break break
with open(fileName, 'w') as f: with open(fileName, 'w') as exception_file:
f.write(f"Discord AI Dungeon 2 v{VERSION} started at {t0:%Y-%m-%d %H:%M}\r\n" exception_file.write(f"Meme-Otron 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"Exception raised at {exception_time:%Y-%m-%d %H:%M}\r\n"
f"\r\n" f"\r\n"
f"{traceback.format_exc()}") f"{traceback.format_exc()}")
+164
View File
@@ -0,0 +1,164 @@
# Meme-Otron guide
* [Commands](#commands)
* [Simple use](#simple-use)
* [Advanced use](#advanced-use)
* [Discord features](#discord-features)
* [CLI features](#cli-features)
* [List of templates](#list-of-templates)
* [Standard Templates](#standard-templates)
* [Reactions (no text)](#reactions-no-text)
* [Examples](#examples)
* [Example 1: Simple template](#example-1-simple-template)
* [Example 2: Use of empty texts](#example-2-use-of-empty-texts)
* [Example 3: Text + Template](#example-3-text--template)
* [Example 4: Complex composition](#example-4-complex-composition)
## Commands
### Simple use
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
You can generate memes by using the following arguments:
```
[meme id] "text1" "text2" ...
```
Depending of the number of `"text"` arguments, several behavior occurs:
* **None**: you get the template that gives you the locations of texts. (see below)
* **Less than the template's**: the remaining texts are blank on the output
* **More than the template's**: the extra arguments are ignored
> Notes
> * You don't have to use all texts shown on the templates
> * You can use an empty text argument ( `""` ) to skip a text and keep it blank
See [Examples](#examples) to get an idea of how to use it.
### Advanced use
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
Since version 1.3, Meme-Otron allows you to "pipe" parts in order to compose more advanced memes. The syntax is as follows:
```
[part1] - [part2] - ...
```
Each `part` can be one of the following:
* A template: as described in [Simple use](#simple-use)
* Texts: ```text "text 1" "text 2" ...```
* Black Arial texts on white background
* Each text is it's own paragraph
* Images: ```image <URL>```
* Takes an image from input or an URL (optional)
* Input depends on the system:
* the Discord bot takes the attachment
* the CLI takes stdin or `--input` argument.
> Notes
> * Input of `image` is always the same, don't expect multiple instances of `image` to get different results if you don't indicate an URL
See [Examples](#examples) to get an idea of how to use it.
### Discord features
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
Tag the bot and use the above syntax to get started. In addition, you can use the following commands:
* Use `help` to get a simple help message
* Use `list` to get a list of all meme ids
* Use `delete` to delete the last message sent by the bot (directed to you)
To get the template info, just send the meme id without texts.
> Tip : You can use `\\n` in your texts to add a line break
Enjoy the full experience of this bot by using direct messages to keep your server free of spam.
### CLI features
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
In this project directory, you can simply call:
```
python -m meme_otron [meme id] "text1" "text2" ... > output.jpg
```
Without pipe redirection with `-o [output]`:
```
python -m meme_otron -o output.png [meme id] "text1" "text2" ...
```
You can even pipe input images like this:
```
python -m meme_otron [arguments] < input.jpg > output.jpg
```
Available arguments:
* `--help` / `-h`
* Show a simple guide
* `--output [file]` / `-o [file]`
* Output file, you are free to choose the format
* `--input [file]` / `-i [file]`
* Input file used for `image`
* `-nw` / `--no-watermark`
* Removes the watermark
* `-d` / `--debug`
* Add more info to output like a box show the texts boundaries
* `-v` / `--verbose`
* Add more logging
## List of templates
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
You can find here the full list of templates.
Each one has extra info and an image showing how texts are placed.
Click on an image to enlarge it.
### Standard Templates
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--LIST1-START-->
<!--LIST1-END-->
### Reactions (no text)
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--LIST2-START-->
<!--LIST2-END-->
## Examples
### Example 1: Simple template
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--EXAMPLE1-START-->
<!--EXAMPLE1-END-->
### Example 2: Use of empty texts
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--EXAMPLE2-START-->
<!--EXAMPLE2-END-->
### Example 3: Text + Template
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--EXAMPLE3-START-->
<!--EXAMPLE3-END-->
### Example 4: Complex composition
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--EXAMPLE4-START-->
<!--EXAMPLE4-END-->
+198 -31
View File
@@ -1,5 +1,25 @@
# Meme-Otron guide
* [Commands](#commands)
* [Simple use](#simple-use)
* [Advanced use](#advanced-use)
* [Discord features](#discord-features)
* [CLI features](#cli-features)
* [List of templates](#list-of-templates)
* [Standard Templates](#standard-templates)
* [Reactions (no text)](#reactions-no-text)
* [Examples](#examples)
* [Example 1: Simple template](#example-1-simple-template)
* [Example 2: Use of empty texts](#example-2-use-of-empty-texts)
* [Example 3: Text + Template](#example-3-text--template)
* [Example 4: Complex composition](#example-4-complex-composition)
## Commands ## Commands
### Simple use
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
You can generate memes by using the following arguments: You can generate memes by using the following arguments:
``` ```
@@ -15,7 +35,36 @@ Depending of the number of `"text"` arguments, several behavior occurs:
> * You don't have to use all texts shown on the templates > * You don't have to use all texts shown on the templates
> * You can use an empty text argument ( `""` ) to skip a text and keep it blank > * You can use an empty text argument ( `""` ) to skip a text and keep it blank
## Discord features See [Examples](#examples) to get an idea of how to use it.
### Advanced use
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
Since version 1.3, Meme-Otron allows you to "pipe" parts in order to compose more advanced memes. The syntax is as follows:
```
[part1] - [part2] - ...
```
Each `part` can be one of the following:
* A template: as described in [Simple use](#simple-use)
* Texts: ```text "text 1" "text 2" ...```
* Black Arial texts on white background
* Each text is it's own paragraph
* Images: ```image <URL>```
* Takes an image from input or an URL (optional)
* Input depends on the system:
* the Discord bot takes the attachment
* the CLI takes stdin or `--input` argument.
> Notes
> * Input of `image` is always the same, don't expect multiple instances of `image` to get different results if you don't indicate an URL
See [Examples](#examples) to get an idea of how to use it.
### Discord features
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
Tag the bot and use the above syntax to get started. In addition, you can use the following commands: Tag the bot and use the above syntax to get started. In addition, you can use the following commands:
@@ -25,9 +74,12 @@ Tag the bot and use the above syntax to get started. In addition, you can use th
To get the template info, just send the meme id without texts. To get the template info, just send the meme id without texts.
> Tip : You can use `\\n` in your texts to add a line break
Enjoy the full experience of this bot by using direct messages to keep your server free of spam. Enjoy the full experience of this bot by using direct messages to keep your server free of spam.
## CLI features ### CLI features
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
In this project directory, you can simply call: In this project directory, you can simply call:
``` ```
@@ -38,16 +90,37 @@ Without pipe redirection with `-o [output]`:
python -m meme_otron -o output.png [meme id] "text1" "text2" ... python -m meme_otron -o output.png [meme id] "text1" "text2" ...
``` ```
> Note: with `-o`, you are free to choose the output format You can even pipe input images like this:
```
python -m meme_otron [arguments] < input.jpg > output.jpg
```
Available arguments:
* `--help` / `-h`
* Show a simple guide
* `--output [file]` / `-o [file]`
* Output file, you are free to choose the format
* `--input [file]` / `-i [file]`
* Input file used for `image`
* `-nw` / `--no-watermark`
* Removes the watermark
* `-d` / `--debug`
* Add more info to output like a box show the texts boundaries
* `-v` / `--verbose`
* Add more logging
## List of templates ## List of templates
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
You can find here the full list of templates. You can find here the full list of templates.
Each one has extra info and an image showing how texts are placed. Each one has extra info and an image showing how texts are placed.
Click on an image to enlarge it. Click on an image to enlarge it.
### Standard Templates
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--START--> <!--LIST1-START-->
|||| ||||
|:---:|:---:|:---:| |:---:|:---:|:---:|
|**aliens**<br><a href='https://knowyourmeme.com/memes/ancient-aliens' target='_blank'>more info</a>|**alive**<br>alt: no_brain<br><a href='https://knowyourmeme.com/memes/oh-fuck-i-forgot-to-give-you-a-brain' target='_blank'>more info</a>|**argument**<br>alt: wrestlers<br><a href='https://knowyourmeme.com/memes/american-chopper-argument' target='_blank'>more info</a>| |**aliens**<br><a href='https://knowyourmeme.com/memes/ancient-aliens' target='_blank'>more info</a>|**alive**<br>alt: no_brain<br><a href='https://knowyourmeme.com/memes/oh-fuck-i-forgot-to-give-you-a-brain' target='_blank'>more info</a>|**argument**<br>alt: wrestlers<br><a href='https://knowyourmeme.com/memes/american-chopper-argument' target='_blank'>more info</a>|
@@ -64,30 +137,124 @@ Click on an image to enlarge it.
|<a href='./templates/distracted.jpg' target='_blank'><img alt='enlarge' src='./preview/distracted.jpg'/></a>|<a href='./templates/dont_look.jpg' target='_blank'><img alt='enlarge' src='./preview/dont_look.jpg'/></a>|<a href='./templates/drake.jpg' target='_blank'><img alt='enlarge' src='./preview/drake.jpg'/></a>| |<a href='./templates/distracted.jpg' target='_blank'><img alt='enlarge' src='./preview/distracted.jpg'/></a>|<a href='./templates/dont_look.jpg' target='_blank'><img alt='enlarge' src='./preview/dont_look.jpg'/></a>|<a href='./templates/drake.jpg' target='_blank'><img alt='enlarge' src='./preview/drake.jpg'/></a>|
|**drift**<br>alt: exit<br><a href='https://knowyourmeme.com/memes/left-exit-12-off-ramp' target='_blank'>more info</a>|**everywhere**<br>alt: buzz, woody<br><a href='https://knowyourmeme.com/memes/x-x-everywhere' target='_blank'>more info</a>|**everywhere2**<br>alt: angry, diapers<br><a href='https://knowyourmeme.com/memes/how-many-diapers-could-he-possibly-use' target='_blank'>more info</a>| |**drift**<br>alt: exit<br><a href='https://knowyourmeme.com/memes/left-exit-12-off-ramp' target='_blank'>more info</a>|**everywhere**<br>alt: buzz, woody<br><a href='https://knowyourmeme.com/memes/x-x-everywhere' target='_blank'>more info</a>|**everywhere2**<br>alt: angry, diapers<br><a href='https://knowyourmeme.com/memes/how-many-diapers-could-he-possibly-use' target='_blank'>more info</a>|
|<a href='./templates/drift.jpg' target='_blank'><img alt='enlarge' src='./preview/drift.jpg'/></a>|<a href='./templates/everywhere.jpg' target='_blank'><img alt='enlarge' src='./preview/everywhere.jpg'/></a>|<a href='./templates/everywhere2.jpg' target='_blank'><img alt='enlarge' src='./preview/everywhere2.jpg'/></a>| |<a href='./templates/drift.jpg' target='_blank'><img alt='enlarge' src='./preview/drift.jpg'/></a>|<a href='./templates/everywhere.jpg' target='_blank'><img alt='enlarge' src='./preview/everywhere.jpg'/></a>|<a href='./templates/everywhere2.jpg' target='_blank'><img alt='enlarge' src='./preview/everywhere2.jpg'/></a>|
|**fight**<br>alt: vaping<br><a href='https://knowyourmeme.com/memes/dabbing-dude' target='_blank'>more info</a>|**fine**<br>alt: fire, dog<br><a href='https://knowyourmeme.com/memes/this-is-fine' target='_blank'>more info</a>|**flex_tape**<br>alt: flex, tape<br><a href='https://knowyourmeme.com/memes/flex-tape' target='_blank'>more info</a>| |**favorite**<br><a href='https://knowyourmeme.com/memes/this-is-my-favorite-subreddit' target='_blank'>more info</a>|**fight**<br>alt: vaping<br><a href='https://knowyourmeme.com/memes/dabbing-dude' target='_blank'>more info</a>|**fine**<br>alt: fire, dog<br><a href='https://knowyourmeme.com/memes/this-is-fine' target='_blank'>more info</a>|
|<a href='./templates/fight.jpg' target='_blank'><img alt='enlarge' src='./preview/fight.jpg'/></a>|<a href='./templates/fine.jpg' target='_blank'><img alt='enlarge' src='./preview/fine.jpg'/></a>|<a href='./templates/flex_tape.jpg' target='_blank'><img alt='enlarge' src='./preview/flex_tape.jpg'/></a>| |<a href='./templates/favorite.jpg' target='_blank'><img alt='enlarge' src='./preview/favorite.jpg'/></a>|<a href='./templates/fight.jpg' target='_blank'><img alt='enlarge' src='./preview/fight.jpg'/></a>|<a href='./templates/fine.jpg' target='_blank'><img alt='enlarge' src='./preview/fine.jpg'/></a>|
|**gate**<br><a href='https://knowyourmeme.com/memes/open-the-gate' target='_blank'>more info</a>|**girl_cat**<br><a href='https://knowyourmeme.com/memes/woman-yelling-at-a-cat' target='_blank'>more info</a>|**grandma**<br><a href='https://knowyourmeme.com/memes/grandma-finds-the-internet' target='_blank'>more info</a>| |**flex_tape**<br>alt: flex, tape<br><a href='https://knowyourmeme.com/memes/flex-tape' target='_blank'>more info</a>|**gate**<br><a href='https://knowyourmeme.com/memes/open-the-gate' target='_blank'>more info</a>|**girl_cat**<br><a href='https://knowyourmeme.com/memes/woman-yelling-at-a-cat' target='_blank'>more info</a>|
|<a href='./templates/gate.jpg' target='_blank'><img alt='enlarge' src='./preview/gate.jpg'/></a>|<a href='./templates/girl_cat.jpg' target='_blank'><img alt='enlarge' src='./preview/girl_cat.jpg'/></a>|<a href='./templates/grandma.jpg' target='_blank'><img alt='enlarge' src='./preview/grandma.jpg'/></a>| |<a href='./templates/flex_tape.jpg' target='_blank'><img alt='enlarge' src='./preview/flex_tape.jpg'/></a>|<a href='./templates/gate.jpg' target='_blank'><img alt='enlarge' src='./preview/gate.jpg'/></a>|<a href='./templates/girl_cat.jpg' target='_blank'><img alt='enlarge' src='./preview/girl_cat.jpg'/></a>|
|**gru**<br>alt: plan<br><a href='https://knowyourmeme.com/memes/grus-plan' target='_blank'>more info</a>|**guys**<br>alt: explain, paid<br><a href='https://knowyourmeme.com/memes/you-guys-are-getting-paid' target='_blank'>more info</a>|**handshake**<br><a href='https://knowyourmeme.com/memes/epic-handshake' target='_blank'>more info</a>| |**grandma**<br><a href='https://knowyourmeme.com/memes/grandma-finds-the-internet' target='_blank'>more info</a>|**gru**<br>alt: plan<br><a href='https://knowyourmeme.com/memes/grus-plan' target='_blank'>more info</a>|**guys**<br>alt: explain, paid<br><a href='https://knowyourmeme.com/memes/you-guys-are-getting-paid' target='_blank'>more info</a>|
|<a href='./templates/gru.jpg' target='_blank'><img alt='enlarge' src='./preview/gru.jpg'/></a>|<a href='./templates/guys.jpg' target='_blank'><img alt='enlarge' src='./preview/guys.jpg'/></a>|<a href='./templates/handshake.jpg' target='_blank'><img alt='enlarge' src='./preview/handshake.jpg'/></a>| |<a href='./templates/grandma.jpg' target='_blank'><img alt='enlarge' src='./preview/grandma.jpg'/></a>|<a href='./templates/gru.jpg' target='_blank'><img alt='enlarge' src='./preview/gru.jpg'/></a>|<a href='./templates/guys.jpg' target='_blank'><img alt='enlarge' src='./preview/guys.jpg'/></a>|
|**handshake2**<br>alt: scott<br><a href='https://knowyourmeme.com/memes/young-michael-scott-shaking-ed-trucks-hand' target='_blank'>more info</a>|**idea**<br>alt: gentlemen<br><a href='https://knowyourmeme.com/memes/all-right-gentlemen' target='_blank'>more info</a>|**lion**<br>alt: shadowy, king, light<br><a href='https://knowyourmeme.com/memes/simba-everything-the-light-touches-is' target='_blank'>more info</a>| |**handshake**<br><a href='https://knowyourmeme.com/memes/epic-handshake' target='_blank'>more info</a>|**handshake2**<br>alt: scott<br><a href='https://knowyourmeme.com/memes/young-michael-scott-shaking-ed-trucks-hand' target='_blank'>more info</a>|**idea**<br>alt: gentlemen<br><a href='https://knowyourmeme.com/memes/all-right-gentlemen' target='_blank'>more info</a>|
|<a href='./templates/handshake2.jpg' target='_blank'><img alt='enlarge' src='./preview/handshake2.jpg'/></a>|<a href='./templates/idea.jpg' target='_blank'><img alt='enlarge' src='./preview/idea.jpg'/></a>|<a href='./templates/lion.jpg' target='_blank'><img alt='enlarge' src='./preview/lion.jpg'/></a>| |<a href='./templates/handshake.jpg' target='_blank'><img alt='enlarge' src='./preview/handshake.jpg'/></a>|<a href='./templates/handshake2.jpg' target='_blank'><img alt='enlarge' src='./preview/handshake2.jpg'/></a>|<a href='./templates/idea.jpg' target='_blank'><img alt='enlarge' src='./preview/idea.jpg'/></a>|
|**meeting**<br>alt: boardroom, suggestion<br><a href='https://knowyourmeme.com/memes/boardroom-suggestion' target='_blank'>more info</a>|**mini**<br>alt: joker<br><a href='https://knowyourmeme.com/memes/mini-joker' target='_blank'>more info</a>|**nobody_cares**<br>alt: nobody, jurassic, park, jurassic_park<br><a href='https://knowyourmeme.com/memes/see-nobody-cares' target='_blank'>more info</a>| |**lion**<br>alt: shadowy, king, light<br><a href='https://knowyourmeme.com/memes/simba-everything-the-light-touches-is' target='_blank'>more info</a>|**meeting**<br>alt: boardroom, suggestion<br><a href='https://knowyourmeme.com/memes/boardroom-suggestion' target='_blank'>more info</a>|**mini**<br>alt: joker<br><a href='https://knowyourmeme.com/memes/mini-joker' target='_blank'>more info</a>|
|<a href='./templates/meeting.jpg' target='_blank'><img alt='enlarge' src='./preview/meeting.jpg'/></a>|<a href='./templates/mini.jpg' target='_blank'><img alt='enlarge' src='./preview/mini.jpg'/></a>|<a href='./templates/nobody_cares.jpg' target='_blank'><img alt='enlarge' src='./preview/nobody_cares.jpg'/></a>| |<a href='./templates/lion.jpg' target='_blank'><img alt='enlarge' src='./preview/lion.jpg'/></a>|<a href='./templates/meeting.jpg' target='_blank'><img alt='enlarge' src='./preview/meeting.jpg'/></a>|<a href='./templates/mini.jpg' target='_blank'><img alt='enlarge' src='./preview/mini.jpg'/></a>|
|**nope**<br><a href='https://knowyourmeme.com/memes/disappointed-black-guy' target='_blank'>more info</a>|**overconfident**<br>alt: alcohol, depressed<br><a href='https://knowyourmeme.com/memes/overconfident-alcoholic' target='_blank'>more info</a>|**patrick**<br>alt: wallet, id<br><a href='https://knowyourmeme.com/memes/patrick-stars-wallet' target='_blank'>more info</a>| |**nobody_cares**<br>alt: nobody, jurassic, park, jurassic_park<br><a href='https://knowyourmeme.com/memes/see-nobody-cares' target='_blank'>more info</a>|**nope**<br><a href='https://knowyourmeme.com/memes/disappointed-black-guy' target='_blank'>more info</a>|**overconfident**<br>alt: alcohol, depressed<br><a href='https://knowyourmeme.com/memes/overconfident-alcoholic' target='_blank'>more info</a>|
|<a href='./templates/nope.jpg' target='_blank'><img alt='enlarge' src='./preview/nope.jpg'/></a>|<a href='./templates/overconfident.jpg' target='_blank'><img alt='enlarge' src='./preview/overconfident.jpg'/></a>|<a href='./templates/patrick.jpg' target='_blank'><img alt='enlarge' src='./preview/patrick.jpg'/></a>| |<a href='./templates/nobody_cares.jpg' target='_blank'><img alt='enlarge' src='./preview/nobody_cares.jpg'/></a>|<a href='./templates/nope.jpg' target='_blank'><img alt='enlarge' src='./preview/nope.jpg'/></a>|<a href='./templates/overconfident.jpg' target='_blank'><img alt='enlarge' src='./preview/overconfident.jpg'/></a>|
|**pigeon**<br>alt: butterfly<br><a href='https://knowyourmeme.com/memes/is-this-a-pigeon' target='_blank'>more info</a>|**pills**<br>alt: swallow<br><a href='https://knowyourmeme.com/memes/hard-to-swallow-pills' target='_blank'>more info</a>|**pleasure3**<br>alt: satisfied3| |**patrick**<br>alt: wallet, id<br><a href='https://knowyourmeme.com/memes/patrick-stars-wallet' target='_blank'>more info</a>|**pigeon**<br>alt: butterfly<br><a href='https://knowyourmeme.com/memes/is-this-a-pigeon' target='_blank'>more info</a>|**pills**<br>alt: swallow<br><a href='https://knowyourmeme.com/memes/hard-to-swallow-pills' target='_blank'>more info</a>|
|<a href='./templates/pigeon.jpg' target='_blank'><img alt='enlarge' src='./preview/pigeon.jpg'/></a>|<a href='./templates/pills.jpg' target='_blank'><img alt='enlarge' src='./preview/pills.jpg'/></a>|<a href='./templates/pleasure3.jpg' target='_blank'><img alt='enlarge' src='./preview/pleasure3.jpg'/></a>| |<a href='./templates/patrick.jpg' target='_blank'><img alt='enlarge' src='./preview/patrick.jpg'/></a>|<a href='./templates/pigeon.jpg' target='_blank'><img alt='enlarge' src='./preview/pigeon.jpg'/></a>|<a href='./templates/pills.jpg' target='_blank'><img alt='enlarge' src='./preview/pills.jpg'/></a>|
|**pleasure4**<br>alt: pleasure, satisfied, satisfied4<br><a href='https://knowyourmeme.com/memes/vince-mcmahon-reaction' target='_blank'>more info</a>|**salt_bae**<br>alt: salt<br><a href='https://knowyourmeme.com/memes/salt-bae' target='_blank'>more info</a>|**scary**<br>alt: spongebob, fearless<br><a href='https://knowyourmeme.com/memes/spongebob-sees-flying-dutchman' target='_blank'>more info</a>| |**pleasure3**<br>alt: satisfied3|**pleasure4**<br>alt: pleasure, satisfied, satisfied4<br><a href='https://knowyourmeme.com/memes/vince-mcmahon-reaction' target='_blank'>more info</a>|**quality**<br>alt: competition<br><a href='https://knowyourmeme.com/memes/king-neptune-vs-spongebob-squarepants' target='_blank'>more info</a>|
|<a href='./templates/pleasure4.jpg' target='_blank'><img alt='enlarge' src='./preview/pleasure4.jpg'/></a>|<a href='./templates/salt_bae.jpg' target='_blank'><img alt='enlarge' src='./preview/salt_bae.jpg'/></a>|<a href='./templates/scary.jpg' target='_blank'><img alt='enlarge' src='./preview/scary.jpg'/></a>| |<a href='./templates/pleasure3.jpg' target='_blank'><img alt='enlarge' src='./preview/pleasure3.jpg'/></a>|<a href='./templates/pleasure4.jpg' target='_blank'><img alt='enlarge' src='./preview/pleasure4.jpg'/></a>|<a href='./templates/quality.jpg' target='_blank'><img alt='enlarge' src='./preview/quality.jpg'/></a>|
|**seagull2**<br>alt: seagull, screaming<br><a href='https://knowyourmeme.com/memes/inhaling-seagull' target='_blank'>more info</a>|**seagull4**|**see_that_guy**<br><a href='https://knowyourmeme.com/memes/hey-man-you-see-that-guy-over-there' target='_blank'>more info</a>| |**salt_bae**<br>alt: salt<br><a href='https://knowyourmeme.com/memes/salt-bae' target='_blank'>more info</a>|**scary**<br>alt: spongebob, fearless<br><a href='https://knowyourmeme.com/memes/spongebob-sees-flying-dutchman' target='_blank'>more info</a>|**seagull2**<br>alt: seagull, screaming<br><a href='https://knowyourmeme.com/memes/inhaling-seagull' target='_blank'>more info</a>|
|<a href='./templates/seagull2.jpg' target='_blank'><img alt='enlarge' src='./preview/seagull2.jpg'/></a>|<a href='./templates/seagull4.jpg' target='_blank'><img alt='enlarge' src='./preview/seagull4.jpg'/></a>|<a href='./templates/see_that_guy.jpg' target='_blank'><img alt='enlarge' src='./preview/see_that_guy.jpg'/></a>| |<a href='./templates/salt_bae.jpg' target='_blank'><img alt='enlarge' src='./preview/salt_bae.jpg'/></a>|<a href='./templates/scary.jpg' target='_blank'><img alt='enlarge' src='./preview/scary.jpg'/></a>|<a href='./templates/seagull2.jpg' target='_blank'><img alt='enlarge' src='./preview/seagull2.jpg'/></a>|
|**sleeping**<br>alt: brain<br><a href='https://knowyourmeme.com/memes/are-you-going-to-sleep' target='_blank'>more info</a>|**spiderman**<br>alt: same<br><a href='https://knowyourmeme.com/memes/spider-man-pointing-at-spider-man' target='_blank'>more info</a>|**struggle**<br>alt: choice, hero<br><a href='https://knowyourmeme.com/memes/daily-struggle' target='_blank'>more info</a>| |**seagull4**|**see_that_guy**<br><a href='https://knowyourmeme.com/memes/hey-man-you-see-that-guy-over-there' target='_blank'>more info</a>|**sleeping**<br>alt: brain<br><a href='https://knowyourmeme.com/memes/are-you-going-to-sleep' target='_blank'>more info</a>|
|<a href='./templates/sleeping.jpg' target='_blank'><img alt='enlarge' src='./preview/sleeping.jpg'/></a>|<a href='./templates/spiderman.jpg' target='_blank'><img alt='enlarge' src='./preview/spiderman.jpg'/></a>|<a href='./templates/struggle.jpg' target='_blank'><img alt='enlarge' src='./preview/struggle.jpg'/></a>| |<a href='./templates/seagull4.jpg' target='_blank'><img alt='enlarge' src='./preview/seagull4.jpg'/></a>|<a href='./templates/see_that_guy.jpg' target='_blank'><img alt='enlarge' src='./preview/see_that_guy.jpg'/></a>|<a href='./templates/sleeping.jpg' target='_blank'><img alt='enlarge' src='./preview/sleeping.jpg'/></a>|
|**t_pose**<br>alt: dominance, monika<br><a href='https://knowyourmeme.com/memes/monika-t-posing-over-sans' target='_blank'>more info</a>|**tom_cousins**<br>alt: cousins, backup, goons<br><a href='https://knowyourmeme.com/memes/tom-and-jerry-hired-goons' target='_blank'>more info</a>|**tough2**<br>alt: tough, fight<br><a href='https://knowyourmeme.com/memes/increasingly-buff-spongebob' target='_blank'>more info</a>| |**spiderman**<br>alt: same<br><a href='https://knowyourmeme.com/memes/spider-man-pointing-at-spider-man' target='_blank'>more info</a>|**struggle**<br>alt: choice, hero<br><a href='https://knowyourmeme.com/memes/daily-struggle' target='_blank'>more info</a>|**t_pose**<br>alt: dominance, monika<br><a href='https://knowyourmeme.com/memes/monika-t-posing-over-sans' target='_blank'>more info</a>|
|<a href='./templates/t_pose.jpg' target='_blank'><img alt='enlarge' src='./preview/t_pose.jpg'/></a>|<a href='./templates/tom_cousins.jpg' target='_blank'><img alt='enlarge' src='./preview/tom_cousins.jpg'/></a>|<a href='./templates/tough2.jpg' target='_blank'><img alt='enlarge' src='./preview/tough2.jpg'/></a>| |<a href='./templates/spiderman.jpg' target='_blank'><img alt='enlarge' src='./preview/spiderman.jpg'/></a>|<a href='./templates/struggle.jpg' target='_blank'><img alt='enlarge' src='./preview/struggle.jpg'/></a>|<a href='./templates/t_pose.jpg' target='_blank'><img alt='enlarge' src='./preview/t_pose.jpg'/></a>|
|**tough2bis**|**tough3**|**trump**<br>alt: law<br><a href='https://knowyourmeme.com/memes/trumps-first-order-of-business' target='_blank'>more info</a>| |**tom_cousins**<br>alt: cousins, backup, goons<br><a href='https://knowyourmeme.com/memes/tom-and-jerry-hired-goons' target='_blank'>more info</a>|**tough2**<br>alt: tough, fight<br><a href='https://knowyourmeme.com/memes/increasingly-buff-spongebob' target='_blank'>more info</a>|**tough2bis**<br>alt: soft|
|<a href='./templates/tough2bis.jpg' target='_blank'><img alt='enlarge' src='./preview/tough2bis.jpg'/></a>|<a href='./templates/tough3.jpg' target='_blank'><img alt='enlarge' src='./preview/tough3.jpg'/></a>|<a href='./templates/trump.jpg' target='_blank'><img alt='enlarge' src='./preview/trump.jpg'/></a>| |<a href='./templates/tom_cousins.jpg' target='_blank'><img alt='enlarge' src='./preview/tom_cousins.jpg'/></a>|<a href='./templates/tough2.jpg' target='_blank'><img alt='enlarge' src='./preview/tough2.jpg'/></a>|<a href='./templates/tough2bis.jpg' target='_blank'><img alt='enlarge' src='./preview/tough2bis.jpg'/></a>|
|**trust_nobody**<br>alt: yourself, gun<br><a href='https://knowyourmeme.com/memes/trust-nobody-not-even-yourself' target='_blank'>more info</a>|**truth**<br>alt: scroll<br><a href='https://knowyourmeme.com/memes/the-scroll-of-truth' target='_blank'>more info</a>|**winnie2**<br>alt: winnie<br><a href='https://knowyourmeme.com/memes/tuxedo-winnie-the-pooh' target='_blank'>more info</a>| |**tough3**|**trump**<br>alt: law<br><a href='https://knowyourmeme.com/memes/trumps-first-order-of-business' target='_blank'>more info</a>|**trust_nobody**<br>alt: yourself, gun<br><a href='https://knowyourmeme.com/memes/trust-nobody-not-even-yourself' target='_blank'>more info</a>|
|<a href='./templates/trust_nobody.jpg' target='_blank'><img alt='enlarge' src='./preview/trust_nobody.jpg'/></a>|<a href='./templates/truth.jpg' target='_blank'><img alt='enlarge' src='./preview/truth.jpg'/></a>|<a href='./templates/winnie2.jpg' target='_blank'><img alt='enlarge' src='./preview/winnie2.jpg'/></a>||| |<a href='./templates/tough3.jpg' target='_blank'><img alt='enlarge' src='./preview/tough3.jpg'/></a>|<a href='./templates/trump.jpg' target='_blank'><img alt='enlarge' src='./preview/trump.jpg'/></a>|<a href='./templates/trust_nobody.jpg' target='_blank'><img alt='enlarge' src='./preview/trust_nobody.jpg'/></a>|
<!--END--> |**truth**<br>alt: scroll<br><a href='https://knowyourmeme.com/memes/the-scroll-of-truth' target='_blank'>more info</a>|**winnie2**<br>alt: winnie<br><a href='https://knowyourmeme.com/memes/tuxedo-winnie-the-pooh' target='_blank'>more info</a>|**winnie3**|
|<a href='./templates/truth.jpg' target='_blank'><img alt='enlarge' src='./preview/truth.jpg'/></a>|<a href='./templates/winnie2.jpg' target='_blank'><img alt='enlarge' src='./preview/winnie2.jpg'/></a>|<a href='./templates/winnie3.jpg' target='_blank'><img alt='enlarge' src='./preview/winnie3.jpg'/></a>|
|**worthless**<br>alt: gravity_falls, dipper<br><a href='https://knowyourmeme.com/memes/whoa-this-is-worthless' target='_blank'>more info</a>||||
|<a href='./templates/worthless.jpg' target='_blank'><img alt='enlarge' src='./preview/worthless.jpg'/></a>||||
<!--LIST1-END-->
### Reactions (no text)
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--LIST2-START-->
||||
|:---:|:---:|:---:|
|**doubt**<br>alt: press_x<br><a href='https://knowyourmeme.com/memes/la-noire-doubt-press-x-to-doubt' target='_blank'>more info</a>|**head_out**<br>alt: ight<br><a href='https://knowyourmeme.com/memes/ight-imma-head-out' target='_blank'>more info</a>|**holup**<br>alt: hold_up<br><a href='https://knowyourmeme.com/memes/vault-boy-hold-up' target='_blank'>more info</a>|
|<a href='../templates/doubt.jpg' target='_blank'><img alt='enlarge' src='./preview/doubt.jpg'/></a>|<a href='../templates/head_out.jpg' target='_blank'><img alt='enlarge' src='./preview/head_out.jpg'/></a>|<a href='../templates/holup.jpg' target='_blank'><img alt='enlarge' src='./preview/holup.jpg'/></a>|
|**listen**<br>alt: chicken, little_shit<br><a href='https://knowyourmeme.com/memes/listen-here-you-little-shit' target='_blank'>more info</a>|**money**<br>alt: fry<br><a href='https://knowyourmeme.com/memes/shut-up-and-take-my-money' target='_blank'>more info</a>|**pasta**<br>alt: vista, italian<br><a href='https://knowyourmeme.com/photos/1272835-how-italians-do-things' target='_blank'>more info</a>|
|<a href='../templates/listen.jpg' target='_blank'><img alt='enlarge' src='./preview/listen.jpg'/></a>|<a href='../templates/money.jpg' target='_blank'><img alt='enlarge' src='./preview/money.jpg'/></a>|<a href='../templates/pasta.jpg' target='_blank'><img alt='enlarge' src='./preview/pasta.jpg'/></a>|
|**stonks**<br><a href='https://knowyourmeme.com/memes/stonks' target='_blank'>more info</a>|**white**<br>alt: magazine<br><a href='https://knowyourmeme.com/memes/dave-chappelle-reading-white-people-magazine' target='_blank'>more info</a>|**wtf**<br>alt: excuse_me<br><a href='https://knowyourmeme.com/memes/excuse-me-what-the-fuck' target='_blank'>more info</a>||
|<a href='../templates/stonks.jpg' target='_blank'><img alt='enlarge' src='./preview/stonks.jpg'/></a>|<a href='../templates/white.jpg' target='_blank'><img alt='enlarge' src='./preview/white.jpg'/></a>|<a href='../templates/wtf.jpg' target='_blank'><img alt='enlarge' src='./preview/wtf.jpg'/></a>||
<!--LIST2-END-->
## Examples
### Example 1: Simple template
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--EXAMPLE1-START-->
>
```
brain3
"Making memes using an image editor"
"Making memes using a Python script"
"Making memes using a Discord bot"
```
![](example1.jpg)
<!--EXAMPLE1-END-->
### Example 2: Use of empty texts
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--EXAMPLE2-START-->
> The 5th text is not set and the 3rd is explicitly set to empty
```
see_that_guy
"See that guy over there?"
"He uses an image editor to make memes"
""
"meme-otron's dev"
```
![](example2.jpg)
<!--EXAMPLE2-END-->
### Example 3: Text + Template
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--EXAMPLE3-START-->
> Note how texts make paragraphs
```
text
"*Meme has a 'made with meme-otron' watermark*"
"reddit: ..."
"9gag: ..."
"meme-otron's dev:"
-
culture
"meme otron"
```
![](example3.jpg)
<!--EXAMPLE3-END-->
### Example 4: Complex composition
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
<!--EXAMPLE4-START-->
>
```
image
https://i.imgur.com/DNLFUuK.png
-
text
"meme-otron's dev close to finishing the idea"
-
holup
```
![](example4.jpg)
<!--EXAMPLE4-END-->
+104 -33
View File
@@ -1,53 +1,109 @@
import os import os
import logging import logging
from typing import List
import PIL import PIL
from os import path from os import path
from meme_otron import img_factory as imgf from meme_otron import img_factory
from meme_otron import meme_db from meme_otron import meme_db
from meme_otron import utils from meme_otron import utils
from meme_otron import meme_otron
logging.basicConfig(format="[%(asctime)s][%(levelname)s][%(module)s] %(message)s", level=logging.WARNING) logging.basicConfig(format="[%(asctime)s][%(levelname)s][%(module)s] %(message)s", level=logging.WARNING)
imgf.load_fonts() img_factory.load_fonts()
meme_db.load_memes() meme_db.load_memes()
dst_dir = utils.relative_path(__file__, "templates") templates_dir = utils.relative_path(__file__, "templates")
prev_dir = utils.relative_path(__file__, "preview") preview_dir = utils.relative_path(__file__, "preview")
doc_template_file = utils.relative_path(__file__, "README-template.md")
doc_file = utils.relative_path(__file__, "README.md") doc_file = utils.relative_path(__file__, "README.md")
COLUMNS = 3 COLUMNS = 3
IMG_HEIGHT = 400 IMG_HEIGHT = 400
def make_empty(target_dir): def main():
make_empty(templates_dir)
make_empty(preview_dir)
with open(doc_template_file, mode='r') as f:
content = "".join(f.readlines())
full_list = sorted(meme_db.LIST)
template_list = [meme_id for meme_id in full_list if len(meme_db.get_meme(meme_id).texts) > 0]
reaction_list = [meme_id for meme_id in full_list if meme_id not in template_list]
content = produce_template_list(content, "LIST1", template_list)
content = produce_template_list(content, "LIST2", reaction_list)
content = produce_example(content, "EXAMPLE1", "example1.jpg", "",
"brain3",
"Making memes using an image editor",
"Making memes using a Python script",
"Making memes using a Discord bot")
content = produce_example(content, "EXAMPLE2", "example2.jpg",
"The 5th text is not set and the 3rd is explicitly set to empty",
"see_that_guy",
"See that guy over there?",
"He uses an image editor to make memes",
"",
"meme-otron's dev")
content = produce_example(content, "EXAMPLE3", "example3.jpg",
"Note how texts make paragraphs",
"text",
"*Meme has a 'made with meme-otron' watermark*",
"reddit: ...",
"9gag: ...",
"meme-otron's dev:",
"-",
"culture",
"meme otron")
content = produce_example(content, "EXAMPLE4", "example4.jpg",
"",
"image",
"https://i.imgur.com/DNLFUuK.png",
"-",
"text",
"meme-otron's dev close to finishing the idea",
"-",
"holup")
with open(doc_file, mode='w') as f:
f.write(content)
def make_empty(target_dir: str):
if path.exists(target_dir): if path.exists(target_dir):
for f in os.listdir(target_dir): for file in os.listdir(target_dir):
if path.isfile(path.join(target_dir, f)): if path.isfile(path.join(target_dir, file)):
os.unlink(path.join(target_dir, f)) os.unlink(path.join(target_dir, file))
else: else:
os.mkdir(target_dir) os.mkdir(target_dir)
make_empty(dst_dir) def produce_template_list(content: str, tag: str, id_list: List[str]):
make_empty(prev_dir) if len(id_list) == 0:
return content
ids = sorted(meme_db.LIST)
doc_content = "|" * (COLUMNS + 1) \ doc_content = "|" * (COLUMNS + 1) \
+ "\n|" + ":---:|" * COLUMNS + "\n|" + ":---:|" * COLUMNS
info_line = None info_line = None
img_line = None img_line = None
i = None i = None
for i, meme_id in enumerate(ids): for i, meme_id in enumerate(id_list):
meme = meme_db.get_meme(meme_id) meme = meme_db.get_meme(meme_id)
img = imgf.make(meme.template, meme.texts, debug=True) img = img_factory.build_from_template(meme.template, meme.texts, debug=True)
if img is not None: if img is not None:
img.save(path.join(dst_dir, meme.template)) base = True
if len(meme.texts) > 0:
base = False
image_path = path.join(templates_dir, meme.template)
img.save(image_path)
size = (round(img.size[0] * IMG_HEIGHT / img.size[1]), IMG_HEIGHT) size = (round(img.size[0] * IMG_HEIGHT / img.size[1]), IMG_HEIGHT)
img2 = img.resize(size, resample=PIL.Image.LANCZOS) img2 = img.resize(size, resample=PIL.Image.LANCZOS)
img2.save(path.join(prev_dir, meme.template)) img2.save(path.join(preview_dir, meme.template))
if i % COLUMNS == 0: if i % COLUMNS == 0:
if info_line is not None and img_line is not None: if info_line is not None and img_line is not None:
doc_content += info_line + img_line doc_content += info_line + img_line
@@ -59,23 +115,38 @@ for i, meme_id in enumerate(ids):
if meme.info is not None: if meme.info is not None:
info_line += f"<br><a href='{meme.info}' target='_blank'>more info</a>" info_line += f"<br><a href='{meme.info}' target='_blank'>more info</a>"
info_line += "|" info_line += "|"
img_line += f"" \ if base:
f"<a href='./templates/{meme.template}' target='_blank'>" \ img_line += f"<a href='../templates/{meme.template}' target='_blank'>"
f"<img alt='enlarge' src='./preview/{meme.template}'/>" \ else:
img_line += f"<a href='./templates/{meme.template}' target='_blank'>"
img_line += f"<img alt='enlarge' src='./preview/{meme.template}'/>" \
f"</a>|" f"</a>|"
print(i, meme_id) print(i, meme_id)
info_line += "|" * (COLUMNS - (i % COLUMNS))
img_line += "|" * (COLUMNS - (i % COLUMNS))
doc_content += info_line + img_line
return inject_content(doc_content, content, tag)
doc_content += "|" * (COLUMNS - (i % COLUMNS))
with open(doc_file, mode='r') as f: def produce_example(content: str, tag: str, file_name: str, note: str, *args: str):
content = "".join(f.readlines()) doc_content = f"> {note}\n\n" \
"```\n" + \
" \n".join(['"' + a + '"' if ' ' in a or len(a) == 0 else a for a in args]) + \
"\n```\n\n" \
f"![]({file_name})"
img, err = meme_otron.compute(*args)
if img is not None:
img.save(utils.relative_path(__file__, file_name))
return inject_content(doc_content, content, tag)
i0 = content.index("<!--START-->")
i1 = content.index("<!--END-->") + len("<!--END-->")
with open(doc_file, mode='w') as f: def inject_content(new_content, content, tag):
f.write(content[:i0]) start_str = f"<!--{tag}-START-->"
f.write("<!--START-->\n") end_str = f"<!--{tag}-END-->"
f.write(doc_content) i0 = content.index(start_str)
f.write("\n<!--END-->") i1 = content.index(end_str) + len(end_str)
f.write(content[i1:]) return content[:i0] + start_str + "\n" + new_content + "\n" + end_str + content[i1:]
if __name__ == '__main__':
main()
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 50 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 218 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 80 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 114 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 64 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 89 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 110 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 54 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 99 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 36 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 61 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 158 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 40 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 110 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 68 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 51 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 64 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 78 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 92 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 125 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 70 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 63 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 51 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 62 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 66 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Some files were not shown because too many files have changed in this diff Show More