72 Commits

Author SHA1 Message Date
CircleCI fde2130eab Automated README [ci skip] 2021-06-09 13:36:17 +00:00
Klemek ee52f44eb3 Create docker.yml 2021-06-09 15:35:58 +02:00
CircleCI 9baf2a59db Automated README [ci skip] 2021-01-21 10:39:57 +00:00
klemek bb265c0a2c Dockerfile support 2021-01-21 11:39:28 +01:00
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
219 changed files with 1551 additions and 455 deletions
+21 -5
View File
@@ -1,5 +1,15 @@
version: 2.1
workflows:
main:
jobs:
- unit-tests
- build-docs:
filters:
branches:
only:
- master
jobs:
build-docs:
docker:
@@ -19,8 +29,14 @@ jobs:
git diff-index --quiet HEAD || git commit -m 'Automated README [ci skip]'
git push origin master
name: Building docs
workflows:
main:
jobs:
- build-docs
unit-tests:
docker:
- image: circleci/python:latest
steps:
- checkout
- run:
command: |
sudo pip install -r requirements.txt
sudo pip install pytest
python -m pytest ./tests/unit
name: Unit tests
+34
View File
@@ -0,0 +1,34 @@
name: Docker
on: ["push", "pull_request"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Build
uses: docker/build-push-action@v2
with:
context: ./
file: ./Dockerfile
builder: ${{ steps.buildx.outputs.name }}
push: false
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
+3 -1
View File
@@ -3,4 +3,6 @@
__pycache__
error_*.txt
tmp
.key*
.key*
*.pyc
.pytest_cache
Executable
+13
View File
@@ -0,0 +1,13 @@
FROM python
# Create app directory
WORKDIR /usr/src/app
COPY requirements.* ./
RUN pip install -r requirements.txt && pip install -r requirements.bot.txt
# Bundle app source
COPY . .
CMD [ "sh", "-c", "python -m discord_bot" ]
+24 -1
View File
@@ -41,4 +41,27 @@ It includes:
## 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
+56 -59
View File
@@ -3,17 +3,17 @@ import traceback
import logging
import discord
import re
import tempfile
from io import BytesIO
import sys
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 img_factory
from meme_otron import meme_db
from meme_otron import utils
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"
t0 = datetime.now()
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")
sys.exit(1)
imgf.load_fonts()
db.load_memes()
img_factory.load_fonts()
meme_db.load_memes()
client = discord.Client()
SENT = {}
def debug(message, txt):
def debug(message: discord.Message, txt: str):
"""
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}")
@@ -60,13 +57,7 @@ async def on_ready():
logging.info(f'- {guild.name}(id: {guild.id})')
async def delete(message):
"""
TODO
:param (discord.Message) message:
:rtype: bool
"""
async def delete(message: discord.Message) -> bool:
try:
await message.delete()
return True
@@ -78,24 +69,22 @@ async def delete(message):
@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
:param (discord.Message) message: message sent
"""
# Ignore self messages
if message.author == client.user:
return
direct = message.channel.type == discord.ChannelType.private
is_direct = message.channel.type == discord.ChannelType.private
if not direct:
mid = f'{message.guild.id}/{message.channel.id}/{message.author.id}'
if not is_direct:
message_id = f'{message.guild.id}/{message.channel.id}/{message.author.id}'
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()
args = utils.parse_arguments(message.content)
debug(message, str(args))
@@ -113,11 +102,11 @@ async def on_message(message):
return
if len(args) > 0 and args[0].lower().strip() == "list":
await message.channel.send(f"Here is a list of all known templates:\n"
f"```{', '.join(db.LIST)}```")
f"```{', '.join(meme_db.LIST)}```")
return
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 not direct:
if message_id in SENT and len(SENT[message_id]) > 0 and await delete(SENT[message_id][-1]):
if not is_direct:
await delete(message)
else:
await message.add_reaction("")
@@ -126,21 +115,34 @@ async def on_message(message):
left_wmark_text = None
if len(args) > 1 and message.author.display_name is not None:
left_wmark_text = f"By {message.author.display_name}"
img = meme_otron.compute(*args, left_wmark_text=left_wmark_text)
if img is None:
hint = db.find_nearest(args[0])
response = f":warning: Template `{args[0]}` not found\n"
if hint is not None:
response += f"Did you mean `{hint}`?\n"
response += f"You can find a more detailed help and a list of templates at:\n" \
logging.info(args[0])
input_data = None
if len(message.attachments) > 0:
input_data = await message.attachments[0].read()
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}>"
await message.channel.send(response)
if len(response) >= 2000:
await message.channel.send(f"{message.author.mention} ... really?")
else:
await message.channel.send(response)
else:
with tempfile.NamedTemporaryFile(delete=False) as output:
img.save(output, format="JPEG")
with BytesIO() as output_file:
img.save(output_file, format="JPEG")
output_file.flush()
output_file.seek(0)
response = None
if len(args) == 1:
meme = db.get_meme(args[0])
meme_id = utils.sanitize_input(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}`:"
if len(meme.aliases) > 0:
response += f"\n- Aliases: `{'`, `'.join(meme.aliases)}`"
@@ -150,18 +152,13 @@ async def on_message(message):
f"\n```{meme.id} \"" + \
"\" \"".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}:"
if mid not in SENT:
SENT[mid] = []
response = await message.channel.send(response,
file=discord.File(filename="meme.jpg", fp=output.name))
SENT[mid] += [response]
try:
os.remove(output.name)
except PermissionError:
pass
if not direct:
if message_id not in SENT:
SENT[message_id] = []
response = await message.channel.send(response, file=discord.File(output_file, "meme.jpg"))
SENT[message_id] += [response]
if not is_direct:
await delete(message)
@@ -171,14 +168,14 @@ while True:
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"
exception_time = datetime.now()
logging.error(f"Exception raised at {exception_time:%Y-%m-%d %H:%M} : {repr(e)}")
fileName = f"error_{exception_time:%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()}")
with open(fileName, 'w') as exception_file:
exception_file.write(f"Meme-Otron v{VERSION} started at {t0:%Y-%m-%d %H:%M}\r\n"
f"Exception raised at {exception_time:%Y-%m-%d %H:%M}\r\n"
f"\r\n"
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
### Simple use
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
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 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:
@@ -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.
> 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
### CLI features
<sub><sup>[↑ back to top](#meme-otron-guide)</sup></sub>
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" ...
```
> 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
<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>
<!--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>|
@@ -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>|
|**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>|
|**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>|
|<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>|
|**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>|
|<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>|
|**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>|
|<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>|
|**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>|
|<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>|
|**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>|
|<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>|
|**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>|
|<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>|
|**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|
|<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>|
|**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>|
|<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>|
|**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>|
|<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>|
|**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>|
|<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>|
|**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>|
|<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>|
|**tough2bis**|**tough3**|**trump**<br>alt: law<br><a href='https://knowyourmeme.com/memes/trumps-first-order-of-business' target='_blank'>more info</a>|
|<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>|
|**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>|
|<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>|||
<!--END-->
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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/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>|
|**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-->
+123 -52
View File
@@ -1,81 +1,152 @@
import os
import logging
from typing import List
import PIL
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 utils
from meme_otron import meme_otron
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()
dst_dir = utils.relative_path(__file__, "templates")
prev_dir = utils.relative_path(__file__, "preview")
templates_dir = utils.relative_path(__file__, "templates")
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")
COLUMNS = 3
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):
for f in os.listdir(target_dir):
if path.isfile(path.join(target_dir, f)):
os.unlink(path.join(target_dir, f))
for file in os.listdir(target_dir):
if path.isfile(path.join(target_dir, file)):
os.unlink(path.join(target_dir, file))
else:
os.mkdir(target_dir)
make_empty(dst_dir)
make_empty(prev_dir)
def produce_template_list(content: str, tag: str, id_list: List[str]):
if len(id_list) == 0:
return content
doc_content = "|" * (COLUMNS + 1) \
+ "\n|" + ":---:|" * COLUMNS
info_line = None
img_line = None
i = None
for i, meme_id in enumerate(id_list):
meme = meme_db.get_meme(meme_id)
img = img_factory.build_from_template(meme.template, meme.texts, debug=True)
if img is not None:
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)
img2 = img.resize(size, resample=PIL.Image.LANCZOS)
img2.save(path.join(preview_dir, meme.template))
if i % COLUMNS == 0:
if info_line is not None and img_line is not None:
doc_content += info_line + img_line
info_line = "\n|"
img_line = "\n|"
info_line += f"**{meme_id}**"
if len(meme.aliases) > 0:
info_line += f"<br>alt: {', '.join(meme.aliases)}"
if meme.info is not None:
info_line += f"<br><a href='{meme.info}' target='_blank'>more info</a>"
info_line += "|"
if base:
img_line += f"<a href='../templates/{meme.template}' target='_blank'>"
else:
img_line += f"<a href='./templates/{meme.template}' target='_blank'>"
img_line += f"<img alt='enlarge' src='./preview/{meme.template}'/>" \
f"</a>|"
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)
ids = sorted(meme_db.LIST)
doc_content = "|" * (COLUMNS + 1) \
+ "\n|" + ":---:|" * COLUMNS
info_line = None
img_line = None
i = None
for i, meme_id in enumerate(ids):
meme = meme_db.get_meme(meme_id)
img = imgf.make(meme.template, meme.texts, debug=True)
def produce_example(content: str, tag: str, file_name: str, note: str, *args: str):
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(path.join(dst_dir, meme.template))
size = (round(img.size[0] * IMG_HEIGHT / img.size[1]), IMG_HEIGHT)
img2 = img.resize(size, resample=PIL.Image.LANCZOS)
img2.save(path.join(prev_dir, meme.template))
if i % COLUMNS == 0:
if info_line is not None and img_line is not None:
doc_content += info_line + img_line
info_line = "\n|"
img_line = "\n|"
info_line += f"**{meme_id}**"
if len(meme.aliases) > 0:
info_line += f"<br>alt: {', '.join(meme.aliases)}"
if meme.info is not None:
info_line += f"<br><a href='{meme.info}' target='_blank'>more info</a>"
info_line += "|"
img_line += f"" \
f"<a href='./templates/{meme.template}' target='_blank'>" \
f"<img alt='enlarge' src='./preview/{meme.template}'/>" \
f"</a>|"
print(i, meme_id)
img.save(utils.relative_path(__file__, file_name))
return inject_content(doc_content, content, tag)
doc_content += "|" * (COLUMNS - (i % COLUMNS))
with open(doc_file, mode='r') as f:
content = "".join(f.readlines())
def inject_content(new_content, content, tag):
start_str = f"<!--{tag}-START-->"
end_str = f"<!--{tag}-END-->"
i0 = content.index(start_str)
i1 = content.index(end_str) + len(end_str)
return content[:i0] + start_str + "\n" + new_content + "\n" + end_str + content[i1:]
i0 = content.index("<!--START-->")
i1 = content.index("<!--END-->") + len("<!--END-->")
with open(doc_file, mode='w') as f:
f.write(content[:i0])
f.write("<!--START-->\n")
f.write(doc_content)
f.write("\n<!--END-->")
f.write(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: 37 KiB

After

Width:  |  Height:  |  Size: 37 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: 41 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: 36 KiB

After

Width:  |  Height:  |  Size: 36 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: 18 KiB

After

Width:  |  Height:  |  Size: 18 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.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 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: 75 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: 40 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: 28 KiB

After

Width:  |  Height:  |  Size: 28 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.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

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: 19 KiB

After

Width:  |  Height:  |  Size: 19 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.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 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: 18 KiB

After

Width:  |  Height:  |  Size: 18 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: 26 KiB

After

Width:  |  Height:  |  Size: 26 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: 26 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: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 217 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: 37 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

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