diff --git a/.gitignore b/.gitignore index ca8d510..f4337da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .env .idea __pycache__ -error_*.txt \ No newline at end of file +error_*.txt +tmp \ No newline at end of file diff --git a/meme_otron/meme_db.py b/meme_otron/meme_db.py index 0003cd0..49cf5e8 100644 --- a/meme_otron/meme_db.py +++ b/meme_otron/meme_db.py @@ -12,10 +12,16 @@ ALIASES = {} logger = logging.getLogger("meme_db") -def load_memes(): +def load_memes(purge=False): """ TODO + + :param (bool) purge: """ + global DATA, ALIASES + if purge: + DATA = {} + ALIASES = {} try: with open(DATA_FILE) as f: content = "".join(f.readlines()) @@ -71,32 +77,37 @@ def load_item(i, item): text = load_text(c, raw_text) if text.text_ref is None: c += 1 - elif text.text_ref < 0 or text.text_ref >= len(meme.texts): - logger.warning(f"Item '{item_id}'({i}) / Text {j}: invalid text reference {text.text_ref}") + elif text.text_ref < 1 or text.text_ref > len(meme.texts): + logger.warning( + f"Item '{item_id}'({i + 1}) / Text {j + 1}: invalid text reference {text.text_ref}") continue else: + text.text_ref -= 1 text.text = meme.texts[text.text_ref].text meme.texts += [text] except TypeError as e: - logger.warning(f"Item '{item_id}'({i}) / Text {j}: {e}") + logger.warning(f"Item '{item_id}'({i + 1}) / Text {j + 1}: {e}") for text in meme.texts: text.update(meme.text_base) if not meme.abstract and len(meme.texts) == 0: - logger.warning(f"Item '{item_id}'({i}): no texts loaded") + logger.warning(f"Item '{item_id}'({i + 1}): no texts loaded") else: DATA[item_id] = meme - for alias in meme.aliases: - if alias in ALIASES: - logger.warning(f"Item '{item_id}'({i}): alias '{alias}' already registered by '{ALIASES[alias]}'") - else: - ALIASES[alias] = item_id + if not meme.abstract: + ALIASES[item_id] = item_id + for alias in meme.aliases: + if alias in ALIASES: + logger.warning( + f"Item '{item_id}'({i + 1}): alias '{alias}' already registered by '{ALIASES[alias]}'") + else: + ALIASES[alias] = item_id logger.info(f"Loaded meme '{item_id}' with {len(meme.texts)} texts") except KeyError as e: - logger.warning(f"Item '{item_id}'({i}): key {e} not found") + logger.warning(f"Item '{item_id}'({i + 1}): key {e} not found") except TypeError as e: - logger.warning(f"Item '{item_id}'({i}): {e}") + logger.warning(f"Item '{item_id}'({i + 1}): {e}") except NameError as e: - logger.warning(f"Item '{item_id}'({i}): {e}") + logger.warning(f"Item '{item_id}'({i + 1}): {e}") def load_text(c, raw_text, text=None): @@ -120,7 +131,8 @@ def load_text(c, raw_text, text=None): text.font_size = utils.read_key_safe(raw_text, "font_size", text.font_size, types=[float, int]) text.fill = utils.read_key_safe(raw_text, "fill", text.fill, types=[int], is_list=True, is_list_size=3) text.stroke_width = utils.read_key_safe(raw_text, "stroke_width", text.stroke_width, types=[float, int]) - text.stroke_fill = utils.read_key_safe(raw_text, "stroke_fill", text.stroke_fill, types=[int], is_list=True, is_list_size=3) + text.stroke_fill = utils.read_key_safe(raw_text, "stroke_fill", text.stroke_fill, types=[int], is_list=True, + is_list_size=3) if "position" in raw_text: if raw_text["position"] not in [p.name for p in Pos]: raise TypeError(f"'position' is not a valid position (ex: NW, E, SE, ...)") @@ -140,9 +152,8 @@ def get_meme(name): :rtype: Meme|None :return: """ - if name in DATA and not DATA[name].abstract: - return DATA[name].clone() - elif name in ALIASES: + name = name.lower().strip().replace(" ", "_") + if name in ALIASES: return DATA[ALIASES[name]].clone() else: return None diff --git a/meme_otron/meme_otron.py b/meme_otron/meme_otron.py index 66bf1f5..9449db7 100644 --- a/meme_otron/meme_otron.py +++ b/meme_otron/meme_otron.py @@ -21,6 +21,16 @@ left_wmark.x_range = [0.005, 0.995] left_wmark.y_range = [0.005, 0.995] +def parse_text(s): + """ + TODO + + :param (str) s: + :rtype: str + """ + return s.replace("\\n", "\n") + + def compute(*args, left_wmark_text=None, debug=False): """ TODO @@ -43,7 +53,7 @@ def compute(*args, left_wmark_text=None, debug=False): for i in range(len(meme.texts)): if meme.texts[i].text_ref is None: if i < len(args) - 1: - meme.texts[i].text = args[c + 1] + meme.texts[i].text = parse_text(args[c + 1]) else: meme.texts[i].text = "" c += 1 diff --git a/memes.json b/memes.json index ad000e6..268b6ac 100644 --- a/memes.json +++ b/memes.json @@ -218,11 +218,11 @@ },{ "x_range": [0.16, 0.45], "y_range": [0.73, 0.91], - "text_ref": 1 + "text_ref": 2 },{ "x_range": [0.69, 0.98], "y_range": [0.72, 0.90], - "text_ref": 1 + "text_ref": 2 }] },{ "id": "aliens", @@ -414,7 +414,7 @@ "x_range": [0.33, 0.48], "y_range": [0.37, 0.43], "font_size": 0.04, - "text_ref": 1 + "text_ref": 2 },{ "x_range": [0.03, 0.29], "y_range": [0.33, 0.45] @@ -422,7 +422,7 @@ "x_range": [0.56, 0.74], "y_range": [0.37, 0.43], "font_size": 0.04, - "text_ref": 1 + "text_ref": 2 },{ "x_range": [0.72, 0.96], "y_range": [0.36, 0.47] @@ -430,7 +430,7 @@ "x_range": [0.27, 0.40], "y_range": [0.65, 0.70], "font_size": 0.04, - "text_ref": 1 + "text_ref": 2 },{ "x_range": [0.12, 0.37], "y_range": [0.53, 0.68] @@ -438,7 +438,7 @@ "x_range": [0.53, 0.64], "y_range": [0.61, 0.67], "font_size": 0.03, - "text_ref": 1 + "text_ref": 2 },{ "x_range": [0.65, 0.95], "y_range": [0.58, 0.70] @@ -476,7 +476,7 @@ },{ "x_range": [0.53, 0.80], "y_range": [0.68, 0.97], - "text_ref": 0 + "text_ref": 1 },{ "x_range": [0.62, 0.95], "y_range": [0.03, 0.26], @@ -500,4 +500,127 @@ "font_size": 0.04, "position": "E" }] +},{ + "id": "flex_tape", + "template": "flex_tape.jpg", + "based_on": "white_text", + "texts": [{ + "x_range": [0.18, 0.43], + "y_range": [0.10, 0.40] + },{ + "x_range": [0.60, 0.90], + "y_range": [0.10, 0.30] + },{ + "x_range": [0.50, 0.84], + "y_range": [0.58, 0.82] + }] +},{ + "id": "girl_cat", + "template": "girl_cat.jpg", + "based_on": "white_text", + "position": "S", + "font_size": 0.12, + "texts": [{ + "x_range": [0.01, 0.49], + "y_range": [0.50, 0.99] + },{ + "x_range": [0.51, 0.99], + "y_range": [0.50, 0.99] + }] +},{ + "id": "gru", + "template": "gru.jpg", + "texts": [{ + "x_range": [0.28, 0.48], + "y_range": [0.08, 0.50], + "angle": -1 + },{ + "x_range": [0.78, 0.98], + "y_range": [0.10, 0.50], + "angle": -1 + },{ + "x_range": [0.28, 0.48], + "y_range": [0.60, 1.00], + "angle": -1 + },{ + "x_range": [0.78, 0.98], + "y_range": [0.60, 1.00], + "angle": -1 + }] +},{ + "id": "handshake", + "template": "handshake.jpg", + "based_on": "white_text", + "font_size": 0.12, + "texts": [{ + "x_range": [-0.05, 0.45], + "y_range": [0.48, 0.78], + "position": "W", + "angle": -50 + },{ + "x_range": [0.43, 0.99], + "y_range": [0.40, 0.70], + "position": "E", + "angle": 25 + },{ + "x_range": [0.25, 0.55], + "y_range": [0.01, 0.50], + "position": "N", + "angle": 5 + }] +},{ + "id": "handshake2", + "template": "handshake2.jpg", + "based_on": "white_text", + "font_size": 0.07, + "texts": [{ + "x_range": [0.10, 0.45], + "y_range": [0.25, 0.70] + },{ + "x_range": [0.55, 0.90], + "y_range": [0.35, 0.75] + }] +},{ + "id": "idea", + "template": "idea.jpg", + "texts": [{ + "x_range": [0.01, 0.58], + "y_range": [0.01, 0.28] + },{ + "x_range": [0.01, 0.40], + "y_range": [0.38, 0.63], + "angle": 18, + "position": "N" + },{ + "x_range": [0.01, 0.40], + "y_range": [0.73, 0.98], + "angle": 18, + "position": "N" + },{ + "x_range": [0.65, 0.98], + "y_range": [0.12, 0.28], + "position": "S", + "font": "impact", + "stroke_fill": [0, 0, 0], + "stroke_width": 0.1, + "fill": [255, 255, 255] + },{ + "x_range": [0.55, 0.98], + "y_range": [0.45, 0.63], + "position": "S", + "text_ref": 4, + "font": "impact", + "stroke_fill": [0, 0, 0], + "stroke_width": 0.1, + "fill": [255, 255, 255] + },{ + "x_range": [0.55, 0.98], + "y_range": [0.80, 0.98], + "position": "S", + "text_ref": 4, + "font": "impact", + "stroke_fill": [0, 0, 0], + "stroke_width": 0.1, + "fill": [255, 255, 255] + }] }] \ No newline at end of file diff --git a/templates/live_edit.py b/templates/live_edit.py new file mode 100644 index 0000000..d300a98 --- /dev/null +++ b/templates/live_edit.py @@ -0,0 +1,37 @@ +import os +import stat +import time +import datetime +import logging +from os import path +from meme_otron import img_factory as imgf +from meme_otron import meme_db +from meme_otron import utils + +logging.basicConfig(format="%(message)s", level=logging.WARNING) + +imgf.load_fonts() + +db_file = utils.relative_path(__file__, "..", meme_db.DATA_FILE) +templates_dir = utils.relative_path(__file__) +dst_dir = utils.relative_path(__file__, "tmp") + +if not path.exists(dst_dir): + os.mkdir(dst_dir) + +last = None + +while True: + while os.stat(db_file)[stat.ST_MTIME] == last: + time.sleep(0.1) + last = os.stat(db_file)[stat.ST_MTIME] + meme_db.load_memes(purge=True) + count = 0 + for meme_id in meme_db.DATA: + meme = meme_db.get_meme(meme_id) + if meme is not None: + img = imgf.make(meme.template, meme.texts, debug=True) + if img is not None: + img.save(path.join(dst_dir, meme.template)) + count += 1 + print(f"{datetime.datetime.now():%H:%M:%S} / {count} registered templates / {len(os.listdir(templates_dir))} files")