code cleaning

This commit is contained in:
klemek
2020-04-27 19:14:28 +02:00
parent 2223770fb8
commit 4bb9bbb23a
8 changed files with 103 additions and 158 deletions
+29 -39
View File
@@ -8,8 +8,8 @@ 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 from meme_otron import VERSION
@@ -26,19 +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}")
@@ -59,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:
"""
Delete a discord message
:param (discord.Message) message:
:rtype: bool
"""
try: try:
await message.delete() await message.delete()
return True return True
@@ -77,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))
@@ -112,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("")
@@ -133,7 +123,7 @@ async def on_message(message):
if len(meme_id) == 0: if len(meme_id) == 0:
response = f":warning: Template not found\n" response = f":warning: Template not found\n"
else: else:
hint = db.find_nearest(meme_id) hint = meme_db.find_nearest(meme_id)
response = f":warning: Template `{meme_id}` not found\n" response = f":warning: Template `{meme_id}` not found\n"
if hint is not None: if hint is not None:
response += f"Did you mean `{hint}`?\n" response += f"Did you mean `{hint}`?\n"
@@ -148,7 +138,7 @@ async def on_message(message):
img.save(output, format="JPEG") img.save(output, format="JPEG")
response = None response = None
if len(args) == 1: if len(args) == 1:
meme = db.get_meme(meme_id) 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)}`"
@@ -158,18 +148,18 @@ 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(filename="meme.jpg", fp=output.name)) file=discord.File(filename="meme.jpg", fp=output.name))
SENT[mid] += [response] SENT[message_id] += [response]
try: try:
os.remove(output.name) os.remove(output.name)
except PermissionError: except PermissionError:
pass pass
if not direct: if not is_direct:
await delete(message) await delete(message)
@@ -179,14 +169,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()}")
+15 -15
View File
@@ -2,36 +2,36 @@ import os
import logging import logging
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
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_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 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) make_empty(templates_dir)
make_empty(prev_dir) make_empty(preview_dir)
ids = sorted(meme_db.LIST) id_list = sorted(meme_db.LIST)
doc_content = "|" * (COLUMNS + 1) \ doc_content = "|" * (COLUMNS + 1) \
+ "\n|" + ":---:|" * COLUMNS + "\n|" + ":---:|" * COLUMNS
@@ -40,14 +40,14 @@ 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_image(meme.template, meme.texts, debug=True)
if img is not None: if img is not None:
img.save(path.join(dst_dir, meme.template)) img.save(path.join(templates_dir, meme.template))
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
+14 -15
View File
@@ -1,15 +1,14 @@
import logging
import sys import sys
import os import os
from . import img_factory as imgf from . import img_factory
from . import meme_db as db from . import meme_db
from . import meme_otron from . import meme_otron
from . import VERSION from . import VERSION
if __name__ == "__main__": if __name__ == "__main__":
db.load_memes() meme_db.load_memes()
imgf.load_fonts() img_factory.load_fonts()
# TODO better arguments reading (-h, -o, -v) # TODO better arguments reading (-h, -o, -v)
@@ -21,29 +20,29 @@ if __name__ == "__main__":
file=sys.stderr) file=sys.stderr)
sys.exit(1) sys.exit(1)
else: else:
output_f = None output_file = None
if "-o" in sys.argv: if "-o" in sys.argv:
i = sys.argv.index("-o") i = sys.argv.index("-o")
if len(sys.argv) >= i: if len(sys.argv) >= i:
output_f = sys.argv[i + 1] output_file = sys.argv[i + 1]
del sys.argv[i + 1] del sys.argv[i + 1]
del sys.argv[i] del sys.argv[i]
img = meme_otron.compute(*sys.argv[1:]) img = meme_otron.compute(*sys.argv[1:])
if img is None: if img is None:
hint = db.find_nearest(sys.argv[1]) proposal = meme_db.find_nearest(sys.argv[1])
if hint is not None: if proposal is not None:
print(f"Did you mean '{hint}'?", file=sys.stderr) print(f"Did you mean '{proposal}'?", file=sys.stderr)
sys.exit(1) sys.exit(1)
if output_f is None: if output_file is None:
with os.fdopen(os.dup(sys.stdout.fileno())) as output: with os.fdopen(os.dup(sys.stdout.fileno())) as output:
img.save(output, format="jpeg") img.save(output, format="jpeg")
else: else:
try: try:
img.save(output_f) img.save(output_file)
print(f"Wrote '{output_f}'") print(f"Wrote '{output_file}'")
except OSError as e: except OSError as e:
print(f"Cannot write '{output_f}': {e}", file=sys.stderr) print(f"Cannot write '{output_file}': {e}", file=sys.stderr)
sys.exit(1) sys.exit(1)
except ValueError as e: except ValueError as e:
print(f"Cannot write '{output_f}': {e}", file=sys.stderr) print(f"Cannot write '{output_file}': {e}", file=sys.stderr)
sys.exit(1) sys.exit(1)
+19 -43
View File
@@ -1,9 +1,11 @@
from typing import List, Optional, Tuple
from PIL import Image, ImageFont, ImageDraw from PIL import Image, ImageFont, ImageDraw
import os import os
import os.path as path import os.path as path
import logging import logging
from . import utils from . import utils
from .types import Text
FONT_DIR = utils.relative_path(__file__, "..", "fonts") FONT_DIR = utils.relative_path(__file__, "..", "fonts")
TEMPLATES_DIR = utils.relative_path(__file__, "..", "templates") TEMPLATES_DIR = utils.relative_path(__file__, "..", "templates")
@@ -24,14 +26,7 @@ def load_fonts():
logger.error(f"Could not load font '{split[0]}'") logger.error(f"Could not load font '{split[0]}'")
def make(template, texts, debug=False): def build_image(template: str, texts: List[Text], debug: bool = False) -> Optional[Image.Image]:
"""
:param (str) template:
:param (list of Text) texts:
:param (bool) debug:
:rtype: PIL.Image.Image
:return:
"""
try: try:
img = Image.open(path.join(TEMPLATES_DIR, template)).convert(mode='RGBA') img = Image.open(path.join(TEMPLATES_DIR, template)).convert(mode='RGBA')
except OSError as e: except OSError as e:
@@ -45,19 +40,13 @@ def make(template, texts, debug=False):
return img.convert(mode='RGB') return img.convert(mode='RGB')
def draw_text(draw, img, text, debug=False): def draw_text(draw: ImageDraw.ImageDraw, img: Image.Image, text: Text, debug: bool = False):
"""
:param (PIL.ImageDraw.ImageDraw) draw: source image canvas
:param (PIL.Image.Image) img: source image
:param (Text) text:
:param (bool) debug:
"""
if text.text is not None and len(text.text.strip()) > 0: if text.text is not None and len(text.text.strip()) > 0:
text.init() # load default values text.init() # load default values
if text.font in FONTS: if text.font in FONTS:
text.text, font = fit_text(img.size, text) text.text, font = fit_text(img.size, text)
if text.angle == 0: if text.angle == 0:
draw.text(get_pos(img.size, text, font), text.text, fill=text.fill, align=text.align, font=font, draw.text(get_text_pos(img.size, text, font), text.text, fill=text.fill, align=text.align, font=font,
stroke_width=round(text.stroke_width * font.size), stroke_fill=text.stroke_fill) stroke_width=round(text.stroke_width * font.size), stroke_fill=text.stroke_fill)
if debug: if debug:
draw.rectangle([(text.x_range[0] * img.size[0], text.y_range[0] * img.size[1]), draw.rectangle([(text.x_range[0] * img.size[0], text.y_range[0] * img.size[1]),
@@ -70,7 +59,7 @@ def draw_text(draw, img, text, debug=False):
center_y = (text.y_range[0] + text.y_range[1]) * img.size[1] / 2 center_y = (text.y_range[0] + text.y_range[1]) * img.size[1] / 2
txt_img = Image.new('RGBA', (width, height)) txt_img = Image.new('RGBA', (width, height))
txt_draw = ImageDraw.Draw(txt_img) txt_draw = ImageDraw.Draw(txt_img)
txt_draw.text(get_pos(img.size, text, font, relative=True), text.text, fill=text.fill, txt_draw.text(get_text_pos(img.size, text, font, relative=True), text.text, fill=text.fill,
align=text.align, font=font, stroke_width=round(text.stroke_width * font.size), align=text.align, font=font, stroke_width=round(text.stroke_width * font.size),
stroke_fill=text.stroke_fill) stroke_fill=text.stroke_fill)
if debug: if debug:
@@ -84,43 +73,30 @@ def draw_text(draw, img, text, debug=False):
logger.warning(f"Invalid font '{text.font}'") logger.warning(f"Invalid font '{text.font}'")
def fit_text(size, text): def fit_text(size: Tuple[int, int], text: Text) -> Tuple[str, ImageFont.FreeTypeFont]:
"""
:param (int,int) size: source image size
:param (Text) text:
:rtype: (str, PIL.ImageFont.FreeTypeFont)
:return:
"""
# TODO rework this function
max_width = round(size[0] * (text.x_range[1] - text.x_range[0])) max_width = round(size[0] * (text.x_range[1] - text.x_range[0]))
max_height = round(size[1] * (text.y_range[1] - text.y_range[0])) max_height = round(size[1] * (text.y_range[1] - text.y_range[0]))
text_size = None text_size = None
font_size = round(text.font_size * min(size)) + 1 font_size = round(text.font_size * min(size)) + 1
font = FONTS[text.font] font = FONTS[text.font]
t = "" text_content = ""
while (text_size is None or text_size[0] >= max_width or text_size[1] >= max_height) and font_size > 1: while (text_size is None or text_size[0] >= max_width or text_size[1] >= max_height) and font_size > 1:
font_size -= 1 font_size -= 1
font = font.font_variant(size=font_size) font = font.font_variant(size=font_size)
k = 0 # number of lines n_lines = 0
while k == 0 or (t is not None and text_size[0] >= max_width): while n_lines == 0 or (text_content is not None and text_size[0] >= max_width):
k += 1 n_lines += 1
t = utils.justify_text(text.text, k) text_content = utils.justify_text(text.text, n_lines)
if t is not None: if text_content is not None:
text_size = font.getsize_multiline(t, stroke_width=text.stroke_width * font_size) text_size = font.getsize_multiline(text_content, stroke_width=text.stroke_width * font_size)
if t is None: if text_content is None:
# max break attained # max break attained
text_size = None # restart text_size = None # retry
return t, font return text_content, font
def get_pos(size, text, font, relative=False): def get_text_pos(size: Tuple[int, int], text: Text,
""" font: ImageFont.FreeTypeFont, relative: bool = False) -> Tuple[int, int]:
:param (int,int) size: source image size
:param (Text) text:
:param (PIL.ImageFont.FreeTypeFont) font:
:rtype (int,int)
:return:
"""
min_x = round(text.x_range[0] * size[0]) min_x = round(text.x_range[0] * size[0])
max_x = round(text.x_range[1] * size[0]) max_x = round(text.x_range[1] * size[0])
min_y = round(text.y_range[0] * size[1]) min_y = round(text.y_range[0] * size[1])
+15 -33
View File
@@ -1,3 +1,4 @@
from typing import Optional
import json import json
import logging import logging
@@ -13,17 +14,14 @@ LIST = []
logger = logging.getLogger("meme_db") logger = logging.getLogger("meme_db")
def load_memes(purge=False): def load_memes(purge: bool = False):
"""
:param (bool) purge:
"""
global DATA, ALIASES global DATA, ALIASES
if purge: if purge:
DATA = {} DATA = {}
ALIASES = {} ALIASES = {}
try: try:
with open(DATA_FILE) as f: with open(DATA_FILE) as input_file:
content = "".join(f.readlines()) content = "".join(input_file.readlines())
raw_data = json.loads(content) raw_data = json.loads(content)
if not (isinstance(raw_data, list)): if not (isinstance(raw_data, list)):
raise TypeError(f"Root is not a list") raise TypeError(f"Root is not a list")
@@ -37,12 +35,9 @@ def load_memes(purge=False):
logger.error(f"Invalid data file: {e}") logger.error(f"Invalid data file: {e}")
def load_item(i, item): def load_item(i: int, item: dict):
"""
:param (int) i:
:param (dict) item:
"""
global LIST global LIST
# TODO reduce complexity
item_id = "" item_id = ""
try: try:
if not (isinstance(item, dict)): if not (isinstance(item, dict)):
@@ -68,13 +63,13 @@ def load_item(i, item):
raw_texts = utils.read_key(item, "texts", meme.texts, types=[dict], is_list=True) raw_texts = utils.read_key(item, "texts", meme.texts, types=[dict], is_list=True)
if "texts" in item: if "texts" in item:
meme.texts = [] meme.texts = []
c = 1 current_text = 1
for j in range(len(raw_texts)): for j in range(len(raw_texts)):
raw_text = raw_texts[j] raw_text = raw_texts[j]
try: try:
text = load_text(c, raw_text) text = load_text(current_text, raw_text)
if text.text_ref is None: if text.text_ref is None:
c += 1 current_text += 1
elif text.text_ref < 1 or text.text_ref > len(meme.texts): elif text.text_ref < 1 or text.text_ref > len(meme.texts):
logger.warning( logger.warning(
f"Item '{item_id}'({i + 1}) / Text {j + 1}: invalid text reference {text.text_ref}") f"Item '{item_id}'({i + 1}) / Text {j + 1}: invalid text reference {text.text_ref}")
@@ -90,7 +85,7 @@ def load_item(i, item):
text.style_ref -= 1 text.style_ref -= 1
text.update(meme.texts[text.style_ref]) text.update(meme.texts[text.style_ref])
meme.texts += [text] meme.texts += [text]
meme.texts_len = c - 1 meme.texts_len = current_text - 1
except TypeError as e: except TypeError as e:
logger.warning(f"Item '{item_id}'({i + 1}) / Text {j + 1}: {e}") logger.warning(f"Item '{item_id}'({i + 1}) / Text {j + 1}: {e}")
for text in meme.texts: for text in meme.texts:
@@ -117,17 +112,9 @@ def load_item(i, item):
logger.warning(f"Item '{item_id}'({i + 1}): {e}") logger.warning(f"Item '{item_id}'({i + 1}): {e}")
def load_text(c, raw_text, text=None): def load_text(current_text: int, raw_text: dict, text: Optional[Text] = None) -> Text:
"""
:param (int) c:
:param (dict) raw_text:
:param (Text|None) text:
:raises TypeError:
:rtype: Text
:return:
"""
if text is None: if text is None:
text = Text(f"text {c}") text = Text(f"text {current_text}")
text.font = utils.read_key_safe(raw_text, "font", text.font, types=[str]) text.font = utils.read_key_safe(raw_text, "font", text.font, types=[str])
text.x_range = utils.read_key_safe(raw_text, "x_range", types=[float, int], is_list=True, is_list_size=2) text.x_range = utils.read_key_safe(raw_text, "x_range", types=[float, int], is_list=True, is_list_size=2)
text.y_range = utils.read_key_safe(raw_text, "y_range", types=[float, int], is_list=True, is_list_size=2) text.y_range = utils.read_key_safe(raw_text, "y_range", types=[float, int], is_list=True, is_list_size=2)
@@ -150,12 +137,7 @@ def load_text(c, raw_text, text=None):
return text return text
def get_meme(name): def get_meme(name: str) -> Optional[Meme]:
"""
:param (str) name:
:rtype: Meme|None
:return:
"""
name = name.lower().strip().replace(" ", "_") name = name.lower().strip().replace(" ", "_")
if name in ALIASES: if name in ALIASES:
return DATA[ALIASES[name]].clone() return DATA[ALIASES[name]].clone()
@@ -163,6 +145,6 @@ def get_meme(name):
return None return None
def find_nearest(word): def find_nearest(word: str) -> str:
word = word.lower().strip().replace(" ", "_") word = word.lower().strip().replace(" ", "_")
return utils.find_nearest(word, ALIASES.keys()) return utils.find_nearest(word, list(ALIASES))
+1 -1
View File
@@ -59,4 +59,4 @@ def compute(*args, left_wmark_text=None, debug=False):
if left_wmark_text is not None: if left_wmark_text is not None:
left_wmark.text = left_wmark_text left_wmark.text = left_wmark_text
meme.texts += [left_wmark] meme.texts += [left_wmark]
return imgf.make(meme.template, meme.texts, debug=debug) return imgf.build_image(meme.template, meme.texts, debug=debug)
+5 -7
View File
@@ -1,3 +1,4 @@
from typing import Optional
from enum import IntEnum from enum import IntEnum
import copy import copy
@@ -18,7 +19,7 @@ class Pos(IntEnum):
class Meme: class Meme:
def __init__(self, meme_id): def __init__(self, meme_id: str):
self.id = meme_id self.id = meme_id
self.aliases = [] self.aliases = []
self.abstract = None self.abstract = None
@@ -28,7 +29,7 @@ class Meme:
self.texts = None self.texts = None
self.texts_len = 0 self.texts_len = 0
def clone(self): def clone(self) -> 'Meme':
return copy.deepcopy(self) return copy.deepcopy(self)
@@ -36,7 +37,7 @@ class Text:
base_properties = ["font", "font_size", "fill", "stroke_width", base_properties = ["font", "font_size", "fill", "stroke_width",
"stroke_fill", "align", "position"] "stroke_fill", "align", "position"]
def __init__(self, text=None): def __init__(self, text: Optional[str] = None):
self.text = text self.text = text
self.text_ref = None self.text_ref = None
@@ -56,10 +57,7 @@ class Text:
self.align = None self.align = None
self.position = None self.position = None
def update(self, base): def update(self, base: 'Text'):
"""
:param (Text) base:
"""
for prop in Text.base_properties: for prop in Text.base_properties:
if getattr(self, prop) is None: if getattr(self, prop) is None:
setattr(self, prop, getattr(base, prop)) setattr(self, prop, getattr(base, prop))
+3 -3
View File
@@ -4,13 +4,13 @@ import time
import datetime import datetime
import logging import logging
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
logging.basicConfig(format="%(message)s", level=logging.WARNING) logging.basicConfig(format="%(message)s", level=logging.WARNING)
imgf.load_fonts() img_factory.load_fonts()
db_file = utils.relative_path(__file__, "..", meme_db.DATA_FILE) db_file = utils.relative_path(__file__, "..", meme_db.DATA_FILE)
templates_dir = utils.relative_path(__file__, "..", "templates") templates_dir = utils.relative_path(__file__, "..", "templates")
@@ -30,7 +30,7 @@ while True:
count = 0 count = 0
for meme_id in meme_db.LIST: for meme_id in meme_db.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_image(meme.template, meme.texts, debug=True)
if img is not None: if img is not None:
img.save(path.join(dst_dir, meme.template)) img.save(path.join(dst_dir, meme.template))
count += 1 count += 1