updates
parent
3ba8fb6d50
commit
5362f8374c
376
automeme.py
376
automeme.py
|
@ -4,7 +4,7 @@ import re
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Callable, TypeVar
|
from typing import Callable, TypeVar
|
||||||
import meme_generator
|
import meme_generator
|
||||||
from meme_generator import WebcomicPanel, OneCharacterWebcomicPanel, TwoCharacterWebcomicPanel, TitleCardWebcomicPanel, add_watermark, create_webcomic
|
from meme_generator import AnimatedImage, WebcomicPanel, OneCharacterWebcomicPanel, TwoCharacterWebcomicPanel, TitleCardWebcomicPanel, add_watermark, create_webcomic
|
||||||
from RDramaAPIInterface import RDramaAPIInterface
|
from RDramaAPIInterface import RDramaAPIInterface
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from os.path import exists, join, realpath, split
|
from os.path import exists, join, realpath, split
|
||||||
|
@ -16,6 +16,7 @@ import os
|
||||||
from markdown import markdown
|
from markdown import markdown
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from utils import get_real_filename
|
from utils import get_real_filename
|
||||||
|
from pympler import tracker, asizeof, classtracker
|
||||||
|
|
||||||
ANTISPAM_MESSAGES = [
|
ANTISPAM_MESSAGES = [
|
||||||
'i have a meme for u :marseyshy:',
|
'i have a meme for u :marseyshy:',
|
||||||
|
@ -45,20 +46,20 @@ ANTISPAM_MESSAGES = [
|
||||||
TEST_MODE = False
|
TEST_MODE = False
|
||||||
DRY_MODE = False
|
DRY_MODE = False
|
||||||
BETA_MODE = False
|
BETA_MODE = False
|
||||||
TEST_AUTH_TOKEN = "lawoSNzuNeBRJBld0boApOceCNSEqBhiRu0aoUWh9kTK7AV37NECZoAK-mEUJ1PM1SsTfTY4f3t_LjooMq4QgPLqPC-F7LNGHQ6_0RFacZmIvC2ixOHPKM821RroJexn"
|
TEST_AUTH_TOKEN = "2PR7FAqx0UVM71HayM33p1OTy_zFGOK1rJlCNi1qzvFJqQGK6NOm7I-mSfYjZgs02FU_LqLTPqDa8KN-LUiGSJ1idFfE5jKnG3DUk9rQjn_ZrAtG_VU9GK5F_EGmixg1"
|
||||||
MINUTES_BEFORE_FORCED_SHUTDOWN = 10
|
MINUTES_BEFORE_FORCED_SHUTDOWN = 10
|
||||||
DB_FILENAME = "automeme_database.db"
|
DB_FILENAME = "automeme_database.db"
|
||||||
PAGES_TO_SCAN = 5
|
MAX_PAGES_TO_SCAN = 10
|
||||||
AUTOMEME_ID = 13427
|
AUTOMEME_ID = 13427
|
||||||
ALLOWED_COMMENTS_PER_POST = 20
|
ALLOWED_COMMENTS_PER_POST = 20
|
||||||
ALLOWED_COMMENTS_PER_USER_PER_DAY = 20
|
ALLOWED_COMMENTS_PER_USER_PER_DAY = 20
|
||||||
|
|
||||||
SOY_VS_CHAD_TRIGGER_CHANGE = 1.0
|
SOY_VS_CHAD_TRIGGER_CHANGE = 0.5
|
||||||
MODERN_MEME_WITH_MARSEY_TRIGGER_CHANGE = 0.01
|
MODERN_MEME_WITH_MARSEY_TRIGGER_CHANGE = 0.01
|
||||||
MODERN_MEME_WITH_IMAGE_TRIGGER_CHANGE = 0.05
|
MODERN_MEME_WITH_IMAGE_TRIGGER_CHANGE = 0.05
|
||||||
CLASSIC_MEME_WITH_MARSEY_TRIGGER_CHANGE = 0.02
|
CLASSIC_MEME_WITH_MARSEY_TRIGGER_CHANGE = 0.02
|
||||||
CLASSIC_MEME_WITH_IMAGE_TRIGGER_CHANGE = 0.1
|
CLASSIC_MEME_WITH_IMAGE_TRIGGER_CHANGE = 0.1
|
||||||
WEBCOMIC_TRIGGER_CHANCE = 1.0
|
WEBCOMIC_TRIGGER_CHANCE = 0.5
|
||||||
|
|
||||||
FREE_POSTS = [6, 97416, 98286]
|
FREE_POSTS = [6, 97416, 98286]
|
||||||
RESTRICTED_POSTS = [5, 16583, 75878, 35835]
|
RESTRICTED_POSTS = [5, 16583, 75878, 35835]
|
||||||
|
@ -111,7 +112,7 @@ class TextLine:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_argument_line(self):
|
def is_argument_line(self):
|
||||||
return len(self.emojis) == 2 and (len(self.captions) == 2 or len(self.captions) == 1) and isinstance(self.line[0], Emoji) and isinstance(self.line[2], Emoji)
|
return len(self.emojis) == 2 and ((len(self.captions) == 0) or (len(self.captions) == 2 or len(self.captions) == 1) and isinstance(self.line[0], Emoji) and isinstance(self.line[2], Emoji))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_pure_text_line(self):
|
def is_pure_text_line(self):
|
||||||
|
@ -125,6 +126,12 @@ class TextLine:
|
||||||
def is_image_line(self):
|
def is_image_line(self):
|
||||||
return len(self.images) == 1 and len(self.captions) == 0
|
return len(self.images) == 1 and len(self.captions) == 0
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.line)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return str(self.line)
|
||||||
|
|
||||||
class TextElement():
|
class TextElement():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -211,9 +218,10 @@ def strip_markdown(markdown_string):
|
||||||
text = re.sub("@(.*?)\s", "", text)
|
text = re.sub("@(.*?)\s", "", text)
|
||||||
text = re.sub("!slots.*?\s", "", text)
|
text = re.sub("!slots.*?\s", "", text)
|
||||||
|
|
||||||
|
text = re.sub("(?i)detrans lives matter", "", text)
|
||||||
text = re.sub("(?i)trans lives matter", "", text)
|
text = re.sub("(?i)trans lives matter", "", text)
|
||||||
|
|
||||||
return text
|
return text.strip()
|
||||||
|
|
||||||
def remove_duplicates(list):
|
def remove_duplicates(list):
|
||||||
return [json.loads(j) for j in set([json.dumps(i) for i in list])]
|
return [json.loads(j) for j in set([json.dumps(i) for i in list])]
|
||||||
|
@ -254,7 +262,8 @@ def get_eligible_comments(rdrama : RDramaAPIInterface, session : Session):
|
||||||
comments = remove_duplicates(comments) #Remove the duplicates
|
comments = remove_duplicates(comments) #Remove the duplicates
|
||||||
|
|
||||||
print([comment['id'] for comment in comments])
|
print([comment['id'] for comment in comments])
|
||||||
|
ScriptCall.register(session)
|
||||||
|
session.commit()
|
||||||
return comments
|
return comments
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -272,14 +281,15 @@ def extract_directives(string : str):
|
||||||
list = [i.lower()[2:] for i in list]
|
list = [i.lower()[2:] for i in list]
|
||||||
return list
|
return list
|
||||||
|
|
||||||
def create_comment_message(chud: bool, pizza: bool, bird : bool, marsey : bool):
|
def create_comment_message(chud: bool, pizza: bool, bird : bool, marsey : bool, mention : str = None):
|
||||||
if (marsey):
|
if (marsey):
|
||||||
return ":marseyshy:"
|
return ":marseyshy:"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
message = choice(ANTISPAM_MESSAGES) +"\n"
|
message = choice(ANTISPAM_MESSAGES) +"\n"
|
||||||
|
if (mention != None):
|
||||||
|
message += f"@{mention}\n"
|
||||||
message += f"<source src=\"{''.join(choices(['a','b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','z'], k=500))}.mp3\">"
|
message += f"<source src=\"{''.join(choices(['a','b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','z'], k=500))}.mp3\">"
|
||||||
|
|
||||||
if (chud):
|
if (chud):
|
||||||
|
@ -289,6 +299,176 @@ def create_comment_message(chud: bool, pizza: bool, bird : bool, marsey : bool):
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
def handle_comment(comment : dict, rdrama : RDramaAPIInterface, session : Session, chud: bool, pizza: bool, bird : bool, is_marsey : bool, starting_directives : 'list[str]'= [], mention : str = None):
|
||||||
|
try:
|
||||||
|
begin = datetime.now()
|
||||||
|
under_post_limit = Post.get_number_of_replies(comment['post_id'], session) < ALLOWED_COMMENTS_PER_POST
|
||||||
|
under_user_limit = User.get_number_of_comments(0 if comment['author'] == '👻' else comment['author']['id'], session) < ALLOWED_COMMENTS_PER_USER_PER_DAY
|
||||||
|
has_not_replied_to_comment = Comment.get_comment(comment['id'], session) is None
|
||||||
|
is_not_restricted_post = comment['post_id'] not in RESTRICTED_POSTS
|
||||||
|
if (not (under_post_limit and under_user_limit and (has_not_replied_to_comment or len(starting_directives) != 0) and is_not_restricted_post)):
|
||||||
|
return
|
||||||
|
|
||||||
|
comment_text = comment['body']
|
||||||
|
directives = extract_directives(comment_text) if len(starting_directives) == 0 else starting_directives
|
||||||
|
cleaned_comment_text = strip_markdown(comment_text)
|
||||||
|
|
||||||
|
if (cleaned_comment_text == "" and len(directives) > 0):
|
||||||
|
parent_id = comment['parent_comment_id']
|
||||||
|
username = None if comment['author'] == '👻' else comment['author']['username']
|
||||||
|
parent = rdrama.get_comment(parent_id)
|
||||||
|
handle_comment(parent, rdrama, session, chud, pizza, bird, is_marsey, starting_directives=directives, mention=username)
|
||||||
|
return
|
||||||
|
|
||||||
|
if ("meme" in directives or comment['post_id'] in FREE_POSTS):
|
||||||
|
random_float = 0.0
|
||||||
|
else:
|
||||||
|
random_float = random()
|
||||||
|
|
||||||
|
comment_lines = cleaned_comment_text.split("\n")
|
||||||
|
comment_lines = [comment_line for comment_line in comment_lines if comment_line != ""]
|
||||||
|
element_lines = [TextLine(line) for line in comment_lines]
|
||||||
|
|
||||||
|
argument_lines_count, dialog_lines_count, text_lines_count, big_marsey_lines_count = 0,0,0,0
|
||||||
|
|
||||||
|
dialog_lines = list(filter(lambda a : a.is_dialogue_line, element_lines))
|
||||||
|
argument_lines = list(filter(lambda a : a.is_argument_line, element_lines))
|
||||||
|
pure_text_lines = list(filter(lambda a : a.is_pure_text_line, element_lines))
|
||||||
|
big_marsey_lines = list(filter(lambda a : a.is_big_marsey_line, element_lines))
|
||||||
|
image_lines = list(filter(lambda a : a.is_image_line, element_lines))
|
||||||
|
|
||||||
|
argument_lines_count = len(argument_lines)
|
||||||
|
dialog_lines_count = len(dialog_lines)
|
||||||
|
pure_text_lines_count = len(pure_text_lines)
|
||||||
|
big_marsey_lines_count = len(big_marsey_lines)
|
||||||
|
image_lines_count = len(image_lines)
|
||||||
|
|
||||||
|
image = None
|
||||||
|
if (dialog_lines_count == 2):
|
||||||
|
print(f"[{comment['id']}] SOY_VS_CHAD")
|
||||||
|
if (random_float <= SOY_VS_CHAD_TRIGGER_CHANGE):
|
||||||
|
#Soy vs Chad
|
||||||
|
|
||||||
|
line1 = dialog_lines[0]
|
||||||
|
line2 = dialog_lines[1]
|
||||||
|
|
||||||
|
emoji1 = line1.emojis[0].emoji
|
||||||
|
emoji2 = line2.emojis[0].emoji
|
||||||
|
caption1 = line1.text
|
||||||
|
caption2 = line2.text
|
||||||
|
|
||||||
|
image = meme_generator.create_soy_vs_chad_meme(emoji1, emoji2, caption1, caption2)
|
||||||
|
elif (big_marsey_lines_count == 1 and pure_text_lines_count == 1):
|
||||||
|
print(f"[{comment['id']}] MODERN_MEME_WITH_MARSEY")
|
||||||
|
if (random_float <= MODERN_MEME_WITH_MARSEY_TRIGGER_CHANGE):
|
||||||
|
|
||||||
|
# Modern Meme with Marsey
|
||||||
|
text_line = pure_text_lines[0]
|
||||||
|
marsey_line = big_marsey_lines[0]
|
||||||
|
|
||||||
|
marsey = marsey_line.emojis[0].emoji
|
||||||
|
caption = text_line.text
|
||||||
|
|
||||||
|
image = meme_generator.create_modern_meme_from_emoji(marsey, caption)
|
||||||
|
elif (image_lines_count == 1 and pure_text_lines_count == 1):
|
||||||
|
print(f"[{comment['id']}] MODERN_MEME_WITH_IMAGE")
|
||||||
|
if (random_float <= MODERN_MEME_WITH_IMAGE_TRIGGER_CHANGE):
|
||||||
|
# Modern Meme with Image
|
||||||
|
text_line = pure_text_lines[0]
|
||||||
|
image_line = image_lines[0]
|
||||||
|
|
||||||
|
image = image_line.images[0]
|
||||||
|
full_image_url = image.url
|
||||||
|
caption = text_line.text
|
||||||
|
|
||||||
|
image = meme_generator.create_modern_meme_from_url(full_image_url, caption)
|
||||||
|
elif (big_marsey_lines_count == 1 and pure_text_lines_count == 2):
|
||||||
|
print(f"[{comment['id']}] CLASSIC_MEME_WITH_MARSEY")
|
||||||
|
if (random_float <= CLASSIC_MEME_WITH_MARSEY_TRIGGER_CHANGE):
|
||||||
|
# Classic Meme with big marsey
|
||||||
|
top_text_line = pure_text_lines[0]
|
||||||
|
bottom_text_line = pure_text_lines[1]
|
||||||
|
marsey_line = big_marsey_lines[0]
|
||||||
|
|
||||||
|
emoji = marsey_line.emojis[0].emoji
|
||||||
|
top_caption = top_text_line.text
|
||||||
|
bottom_caption = bottom_text_line.text
|
||||||
|
image = meme_generator.create_classic_meme_from_emoji(emoji, top_caption, bottom_caption)
|
||||||
|
elif (image_lines_count == 1 and pure_text_lines_count == 2):
|
||||||
|
print(f"[{comment['id']}] CLASSIC_MEME_WITH_IMAGE")
|
||||||
|
if (random_float <= CLASSIC_MEME_WITH_IMAGE_TRIGGER_CHANGE):
|
||||||
|
# Classic Meme with Image
|
||||||
|
top_text_line = pure_text_lines[0]
|
||||||
|
bottom_text_line = pure_text_lines[1]
|
||||||
|
image_line = image_lines[0]
|
||||||
|
|
||||||
|
image = image_line.images[0]
|
||||||
|
full_image_url = image.url
|
||||||
|
top_caption = top_text_line.text
|
||||||
|
bottom_caption = bottom_text_line.text
|
||||||
|
|
||||||
|
image = meme_generator.create_classic_meme_from_url(full_image_url, top_caption, bottom_caption)
|
||||||
|
elif (argument_lines_count + dialog_lines_count >= 2):
|
||||||
|
print(f"[{comment['id']}] WEBCOMIC")
|
||||||
|
if (random_float <= WEBCOMIC_TRIGGER_CHANCE):
|
||||||
|
panels : 'list[WebcomicPanel]' = []
|
||||||
|
|
||||||
|
for element_line in element_lines:
|
||||||
|
if element_line.is_dialogue_line:
|
||||||
|
caption = element_line.text
|
||||||
|
emoji = element_line.emojis[0].emoji
|
||||||
|
if len(caption) > 100:
|
||||||
|
in_background = True
|
||||||
|
else:
|
||||||
|
in_background = False
|
||||||
|
oneCharacterWebcomicPanel = OneCharacterWebcomicPanel(emoji, caption, in_background)
|
||||||
|
panels.append(oneCharacterWebcomicPanel)
|
||||||
|
elif element_line.is_argument_line:
|
||||||
|
|
||||||
|
if len(element_line.captions) == 2:
|
||||||
|
left_caption = element_line.captions[0].text
|
||||||
|
right_caption = element_line.captions[1].text
|
||||||
|
elif (len(element_line.captions) == 1):
|
||||||
|
left_caption = element_line.captions[0].text
|
||||||
|
right_caption = ""
|
||||||
|
else:
|
||||||
|
left_caption = ""
|
||||||
|
right_caption = ""
|
||||||
|
left_emoji = element_line.emojis[0].emoji
|
||||||
|
right_emoji = element_line.emojis[1].emoji
|
||||||
|
twoCharacterWebcomicPanel = TwoCharacterWebcomicPanel(left_emoji, left_caption, right_emoji, right_caption)
|
||||||
|
panels.append(twoCharacterWebcomicPanel)
|
||||||
|
else:
|
||||||
|
panels.append(TitleCardWebcomicPanel(element_line.text))
|
||||||
|
|
||||||
|
image = create_webcomic(panels)
|
||||||
|
print(asizeof.asized(image, detail=1).format())
|
||||||
|
if image != None:
|
||||||
|
print(f"[{comment['id']}] posting...")
|
||||||
|
image = add_watermark(image, comment['author']['username'])
|
||||||
|
user_id = 0 if comment['author'] == '👻' else comment['author']['id']
|
||||||
|
parent_comment_id = comment['id']
|
||||||
|
post_id = comment['post_id']
|
||||||
|
message = create_comment_message(chud, pizza, bird, is_marsey, mention=mention)
|
||||||
|
if not DRY_MODE:
|
||||||
|
automeme_comment_id = comment_with_image(message, image, comment['id'], comment['post_id'])
|
||||||
|
else:
|
||||||
|
automeme_comment_id = None
|
||||||
|
image.save(get_real_filename(f"dry/{comment['id']}.webp"))
|
||||||
|
|
||||||
|
Comment.create_new_comment(parent_comment_id, automeme_comment_id, session)
|
||||||
|
if post_id not in FREE_POSTS:
|
||||||
|
Post.increment_replies(post_id, session)
|
||||||
|
User.increase_number_of_comments(user_id, session)
|
||||||
|
else:
|
||||||
|
print(f"[{comment['id']}] is a free post.")
|
||||||
|
end = datetime.now()
|
||||||
|
print(end-begin)
|
||||||
|
else:
|
||||||
|
Comment.create_new_comment(comment['id'], None, session)
|
||||||
|
except BaseException as e:
|
||||||
|
print(f"YIKERINOS! GOT AN EXCEPTION: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
def main_processing_task(rdrama : RDramaAPIInterface, session : Session):
|
def main_processing_task(rdrama : RDramaAPIInterface, session : Session):
|
||||||
is_chudded = False #Do we have the chud award?
|
is_chudded = False #Do we have the chud award?
|
||||||
can_communicate = True #Can we send any message at all?
|
can_communicate = True #Can we send any message at all?
|
||||||
|
@ -324,179 +504,27 @@ def main_processing_task(rdrama : RDramaAPIInterface, session : Session):
|
||||||
if can_communicate:
|
if can_communicate:
|
||||||
eligible_comments = get_eligible_comments(rdrama, session)
|
eligible_comments = get_eligible_comments(rdrama, session)
|
||||||
for eligible_comment in eligible_comments:
|
for eligible_comment in eligible_comments:
|
||||||
try:
|
handle_comment(eligible_comment, rdrama, session, is_chudded, is_pizzad, is_birdsite, is_marseyed)
|
||||||
begin = datetime.now()
|
|
||||||
under_post_limit = Post.get_number_of_replies(eligible_comment['post_id'], session) < ALLOWED_COMMENTS_PER_POST
|
|
||||||
under_user_limit = User.get_number_of_comments(0 if eligible_comment['author'] == '👻' else eligible_comment['author']['id'], session) < ALLOWED_COMMENTS_PER_USER_PER_DAY
|
|
||||||
has_not_replied_to_comment = Comment.get_comment(eligible_comment['id'], session) is None
|
|
||||||
is_not_restricted_post = eligible_comment['post_id'] not in RESTRICTED_POSTS
|
|
||||||
if (not (under_post_limit and under_user_limit and has_not_replied_to_comment and is_not_restricted_post)):
|
|
||||||
continue
|
|
||||||
|
|
||||||
comment_text = eligible_comment['body']
|
|
||||||
directives = extract_directives(comment_text)
|
|
||||||
cleaned_comment_text = strip_markdown(comment_text)
|
|
||||||
|
|
||||||
|
|
||||||
if ("meme" in directives or eligible_comment['post_id'] in FREE_POSTS):
|
|
||||||
random_float = 0.0
|
|
||||||
else:
|
|
||||||
random_float = random()
|
|
||||||
|
|
||||||
comment_lines = cleaned_comment_text.split("\n")
|
|
||||||
comment_lines = [comment_line for comment_line in comment_lines if comment_line != ""]
|
|
||||||
element_lines = [TextLine(line) for line in comment_lines]
|
|
||||||
|
|
||||||
argument_lines_count, dialog_lines_count, text_lines_count, big_marsey_lines_count = 0,0,0,0
|
|
||||||
|
|
||||||
dialog_lines = list(filter(lambda a : a.is_dialogue_line, element_lines))
|
|
||||||
argument_lines = list(filter(lambda a : a.is_argument_line, element_lines))
|
|
||||||
pure_text_lines = list(filter(lambda a : a.is_pure_text_line, element_lines))
|
|
||||||
big_marsey_lines = list(filter(lambda a : a.is_big_marsey_line, element_lines))
|
|
||||||
image_lines = list(filter(lambda a : a.is_image_line, element_lines))
|
|
||||||
|
|
||||||
argument_lines_count = len(argument_lines)
|
|
||||||
dialog_lines_count = len(dialog_lines)
|
|
||||||
pure_text_lines_count = len(pure_text_lines)
|
|
||||||
big_marsey_lines_count = len(big_marsey_lines)
|
|
||||||
image_lines_count = len(image_lines)
|
|
||||||
|
|
||||||
image = None
|
|
||||||
if (dialog_lines_count == 2):
|
|
||||||
print(f"[{eligible_comment['id']}] SOY_VS_CHAD")
|
|
||||||
if (random_float <= SOY_VS_CHAD_TRIGGER_CHANGE):
|
|
||||||
#Soy vs Chad
|
|
||||||
|
|
||||||
line1 = dialog_lines[0]
|
|
||||||
line2 = dialog_lines[1]
|
|
||||||
|
|
||||||
emoji1 = line1.emojis[0].emoji
|
|
||||||
emoji2 = line2.emojis[0].emoji
|
|
||||||
caption1 = line1.text
|
|
||||||
caption2 = line2.text
|
|
||||||
|
|
||||||
image = meme_generator.create_soy_vs_chad_meme(emoji1, emoji2, caption1, caption2)
|
|
||||||
elif (big_marsey_lines_count == 1 and pure_text_lines_count == 1):
|
|
||||||
print(f"[{eligible_comment['id']}] MODERN_MEME_WITH_MARSEY")
|
|
||||||
if (random_float <= MODERN_MEME_WITH_MARSEY_TRIGGER_CHANGE):
|
|
||||||
|
|
||||||
# Modern Meme with Marsey
|
|
||||||
text_line = pure_text_lines[0]
|
|
||||||
marsey_line = big_marsey_lines[0]
|
|
||||||
|
|
||||||
marsey = marsey_line.emojis[0].emoji
|
|
||||||
caption = text_line.text
|
|
||||||
|
|
||||||
image = meme_generator.create_modern_meme_from_emoji(marsey, caption)
|
|
||||||
elif (image_lines_count == 1 and pure_text_lines_count == 1):
|
|
||||||
print(f"[{eligible_comment['id']}] MODERN_MEME_WITH_IMAGE")
|
|
||||||
if (random_float <= MODERN_MEME_WITH_IMAGE_TRIGGER_CHANGE):
|
|
||||||
# Modern Meme with Image
|
|
||||||
text_line = pure_text_lines[0]
|
|
||||||
image_line = image_lines[0]
|
|
||||||
|
|
||||||
image = image_line.images[0]
|
|
||||||
full_image_url = image.url
|
|
||||||
caption = text_line.text
|
|
||||||
|
|
||||||
image = meme_generator.create_modern_meme_from_url(full_image_url, caption)
|
|
||||||
elif (big_marsey_lines_count == 1 and pure_text_lines_count == 2):
|
|
||||||
print(f"[{eligible_comment['id']}] CLASSIC_MEME_WITH_MARSEY")
|
|
||||||
if (random_float <= CLASSIC_MEME_WITH_MARSEY_TRIGGER_CHANGE):
|
|
||||||
# Classic Meme with big marsey
|
|
||||||
top_text_line = pure_text_lines[0]
|
|
||||||
bottom_text_line = pure_text_lines[1]
|
|
||||||
marsey_line = big_marsey_lines[0]
|
|
||||||
|
|
||||||
emoji = marsey_line.emojis[0].emoji
|
|
||||||
top_caption = top_text_line.text
|
|
||||||
bottom_caption = bottom_text_line.text
|
|
||||||
image = meme_generator.create_classic_meme_from_emoji(emoji, top_caption, bottom_caption)
|
|
||||||
elif (image_lines_count == 1 and pure_text_lines_count == 2):
|
|
||||||
print(f"[{eligible_comment['id']}] CLASSIC_MEME_WITH_IMAGE")
|
|
||||||
if (random_float <= CLASSIC_MEME_WITH_IMAGE_TRIGGER_CHANGE):
|
|
||||||
# Classic Meme with Image
|
|
||||||
top_text_line = pure_text_lines[0]
|
|
||||||
bottom_text_line = pure_text_lines[1]
|
|
||||||
image_line = image_lines[0]
|
|
||||||
|
|
||||||
image = image_line.images[0]
|
|
||||||
full_image_url = image.url
|
|
||||||
top_caption = top_text_line.text
|
|
||||||
bottom_caption = bottom_text_line.text
|
|
||||||
|
|
||||||
image = meme_generator.create_classic_meme_from_url(full_image_url, top_caption, bottom_caption)
|
|
||||||
elif (argument_lines_count + dialog_lines_count >= 2):
|
|
||||||
print(f"[{eligible_comment['id']}] WEBCOMIC")
|
|
||||||
if (random_float <= WEBCOMIC_TRIGGER_CHANCE):
|
|
||||||
panels : 'list[WebcomicPanel]' = []
|
|
||||||
|
|
||||||
for element_line in element_lines:
|
|
||||||
if element_line.is_dialogue_line:
|
|
||||||
caption = element_line.text
|
|
||||||
emoji = element_line.emojis[0].emoji
|
|
||||||
if len(caption) > 100:
|
|
||||||
in_background = True
|
|
||||||
else:
|
|
||||||
in_background = False
|
|
||||||
oneCharacterWebcomicPanel = OneCharacterWebcomicPanel(emoji, caption, in_background)
|
|
||||||
panels.append(oneCharacterWebcomicPanel)
|
|
||||||
elif element_line.is_argument_line:
|
|
||||||
left_caption = element_line.captions[0].text
|
|
||||||
if len(element_line.captions) == 2:
|
|
||||||
right_caption = element_line.captions[1].text
|
|
||||||
else:
|
|
||||||
right_caption = ""
|
|
||||||
left_emoji = element_line.emojis[0].emoji
|
|
||||||
right_emoji = element_line.emojis[1].emoji
|
|
||||||
twoCharacterWebcomicPanel = TwoCharacterWebcomicPanel(left_emoji, left_caption, right_emoji, right_caption)
|
|
||||||
panels.append(twoCharacterWebcomicPanel)
|
|
||||||
elif element_line.is_pure_text_line:
|
|
||||||
panels.append(TitleCardWebcomicPanel(element_line.text))
|
|
||||||
|
|
||||||
image = create_webcomic(panels)
|
|
||||||
if image != None:
|
|
||||||
print(f"[{eligible_comment['id']}] posting...")
|
|
||||||
image = add_watermark(image, eligible_comment['author']['username'])
|
|
||||||
user_id = 0 if eligible_comment['author'] == '👻' else eligible_comment['author']['id']
|
|
||||||
parent_comment_id = eligible_comment['id']
|
|
||||||
post_id = eligible_comment['post_id']
|
|
||||||
message = create_comment_message(is_chudded, is_pizzad, is_birdsite, is_marseyed)
|
|
||||||
if not DRY_MODE:
|
|
||||||
automeme_comment_id = comment_with_image(message, image, eligible_comment['id'], eligible_comment['post_id'])
|
|
||||||
else:
|
|
||||||
automeme_comment_id = None
|
|
||||||
image.save(get_real_filename(f"dry/{eligible_comment['id']}.webp"))
|
|
||||||
|
|
||||||
Comment.create_new_comment(parent_comment_id, automeme_comment_id, session)
|
|
||||||
if post_id not in FREE_POSTS:
|
|
||||||
Post.increment_replies(post_id, session)
|
|
||||||
User.increase_number_of_comments(user_id, session)
|
|
||||||
else:
|
|
||||||
print(f"[{eligible_comment['id']}] is a free post.")
|
|
||||||
end = datetime.now()
|
|
||||||
print(end-begin)
|
|
||||||
else:
|
|
||||||
Comment.create_new_comment(eligible_comment['id'], None, session)
|
|
||||||
except BaseException as e:
|
|
||||||
print(f"YIKERINOS! GOT AN EXCEPTION: {e}")
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
ScriptCall.register(session)
|
|
||||||
|
|
||||||
def comment_chunk(time : datetime, api: RDramaAPIInterface):
|
def comment_chunk(time : datetime, api: RDramaAPIInterface):
|
||||||
current_time_cur = int(time.timestamp()) # int(time.time() - 60*60*8)
|
current_time_cur = int(time.timestamp()) # int(time.time() - 60*60*8)
|
||||||
comments = []
|
comments = []
|
||||||
|
pages = 0
|
||||||
while True:
|
while True:
|
||||||
|
pages+=1
|
||||||
res = api.get_comments(sort="old", lower_bound=current_time_cur)
|
res = api.get_comments(sort="old", lower_bound=current_time_cur)
|
||||||
if len(res['data']) == 0:
|
if len(res['data']) == 0:
|
||||||
break
|
break
|
||||||
|
if pages > MAX_PAGES_TO_SCAN:
|
||||||
|
print("WARNING: Had to drop some pages. Can't make an omelette without cracking a few eggs")
|
||||||
|
break
|
||||||
comments = comments + res['data']
|
comments = comments + res['data']
|
||||||
current_time_cur = res['data'][-1]['created_utc']
|
current_time_cur = res['data'][-1]['created_utc']
|
||||||
|
|
||||||
return comments
|
return comments
|
||||||
if __name__ == "__main__":
|
|
||||||
print(f"======= RUNNING AT {datetime.now().hour}:{datetime.now().minute} ======= ")
|
def get_rdrama():
|
||||||
|
global AUTOMEME_ID, OPERATOR_ID
|
||||||
if TEST_MODE:
|
if TEST_MODE:
|
||||||
website = "localhost"
|
website = "localhost"
|
||||||
auth = TEST_AUTH_TOKEN
|
auth = TEST_AUTH_TOKEN
|
||||||
|
@ -504,7 +532,6 @@ if __name__ == "__main__":
|
||||||
timeout = 1
|
timeout = 1
|
||||||
AUTOMEME_ID = 6
|
AUTOMEME_ID = 6
|
||||||
OPERATOR_ID = 9
|
OPERATOR_ID = 9
|
||||||
ACTUALLY_CALL_OPEN_AI = False
|
|
||||||
else:
|
else:
|
||||||
website = "rdrama.net"
|
website = "rdrama.net"
|
||||||
with open(get_real_filename("rdrama_auth_token"), "r") as f:
|
with open(get_real_filename("rdrama_auth_token"), "r") as f:
|
||||||
|
@ -512,6 +539,11 @@ if __name__ == "__main__":
|
||||||
https = True
|
https = True
|
||||||
timeout = 10
|
timeout = 10
|
||||||
rdrama = RDramaAPIInterface(auth, website, timeout, https=https)
|
rdrama = RDramaAPIInterface(auth, website, timeout, https=https)
|
||||||
|
return rdrama
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(f"======= RUNNING AT {datetime.now().hour}:{datetime.now().minute} ======= ")
|
||||||
|
rdrama = get_rdrama()
|
||||||
|
|
||||||
#Set up fail safe
|
#Set up fail safe
|
||||||
def exitfunc():
|
def exitfunc():
|
||||||
|
|
|
@ -10,9 +10,10 @@ from utils import get_real_filename
|
||||||
from image_utils import ImageText
|
from image_utils import ImageText
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
from random import choice
|
from random import choice
|
||||||
|
from pympler import tracker
|
||||||
|
|
||||||
HIGHLIGHT_MODE = False
|
HIGHLIGHT_MODE = False #Adds a square around the region where text is being put in a text box. Useful for debugging.
|
||||||
CAPTION_FILENAME = "watermark_captions.txt"
|
CAPTION_FILENAME = "watermark_captions.txt" #Name of the file containing watermark captions.
|
||||||
|
|
||||||
class ColorScheme:
|
class ColorScheme:
|
||||||
BLACK = 0
|
BLACK = 0
|
||||||
|
@ -28,7 +29,6 @@ def create_soy_vs_chad_meme(emoji1, emoji2, caption1, caption2):
|
||||||
MIDDLE_MARGIN_ROW = 20
|
MIDDLE_MARGIN_ROW = 20
|
||||||
TEXT_ROW = 100
|
TEXT_ROW = 100
|
||||||
BOTTOM_MARGIN_ROW = 80
|
BOTTOM_MARGIN_ROW = 80
|
||||||
|
|
||||||
total_image_size_x = 2*CONTENT_COLUMN + LEFT_MARGIN_COLUMN + RIGHT_MARGIN_COLUMN + MIDDLE_MARGIN_COLUMN
|
total_image_size_x = 2*CONTENT_COLUMN + LEFT_MARGIN_COLUMN + RIGHT_MARGIN_COLUMN + MIDDLE_MARGIN_COLUMN
|
||||||
total_image_size_y = TOP_MARGIN_ROW + IMAGE_ROW + MIDDLE_MARGIN_ROW + TEXT_ROW + BOTTOM_MARGIN_ROW
|
total_image_size_y = TOP_MARGIN_ROW + IMAGE_ROW + MIDDLE_MARGIN_ROW + TEXT_ROW + BOTTOM_MARGIN_ROW
|
||||||
|
|
||||||
|
@ -116,9 +116,12 @@ def create_modern_meme_from_emoji(emoji: str, caption: str):
|
||||||
return create_modern_meme(base, caption)
|
return create_modern_meme(base, caption)
|
||||||
|
|
||||||
class WebcomicPanel():
|
class WebcomicPanel():
|
||||||
PANEL_SIZE = 400
|
'''
|
||||||
FONT = "impact.ttf"
|
A panel in a webcomic.
|
||||||
COLOR = ColorScheme.WHITE_WITH_BLACK_BORDER
|
'''
|
||||||
|
PANEL_SIZE = 400 #Size of a webcomic panel.
|
||||||
|
FONT = "impact.ttf" #The font to use.
|
||||||
|
COLOR = ColorScheme.WHITE_WITH_BLACK_BORDER #The color of the font.
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
@ -130,6 +133,9 @@ class WebcomicPanel():
|
||||||
return add_text_box(base, caption, region_size, coordinates, align=align, font=self.FONT, color=self.COLOR, init_font_size=int(self.PANEL_SIZE/10))
|
return add_text_box(base, caption, region_size, coordinates, align=align, font=self.FONT, color=self.COLOR, init_font_size=int(self.PANEL_SIZE/10))
|
||||||
|
|
||||||
class OneCharacterWebcomicPanel(WebcomicPanel):
|
class OneCharacterWebcomicPanel(WebcomicPanel):
|
||||||
|
'''
|
||||||
|
Panel with one character talking.
|
||||||
|
'''
|
||||||
def __init__(self, emoji, caption, words_in_background):
|
def __init__(self, emoji, caption, words_in_background):
|
||||||
self.emoji = emoji
|
self.emoji = emoji
|
||||||
self.caption = caption
|
self.caption = caption
|
||||||
|
@ -155,6 +161,9 @@ class OneCharacterWebcomicPanel(WebcomicPanel):
|
||||||
return add_border_to_image(base)
|
return add_border_to_image(base)
|
||||||
|
|
||||||
class TwoCharacterWebcomicPanel(WebcomicPanel):
|
class TwoCharacterWebcomicPanel(WebcomicPanel):
|
||||||
|
'''
|
||||||
|
Panel with two characters talking.
|
||||||
|
'''
|
||||||
def __init__(self, left_emoji, left_caption, right_emoji, right_caption):
|
def __init__(self, left_emoji, left_caption, right_emoji, right_caption):
|
||||||
self.left_emoji = left_emoji
|
self.left_emoji = left_emoji
|
||||||
self.left_caption = left_caption
|
self.left_caption = left_caption
|
||||||
|
@ -204,6 +213,9 @@ class TwoCharacterWebcomicPanel(WebcomicPanel):
|
||||||
return add_border_to_image(base)
|
return add_border_to_image(base)
|
||||||
|
|
||||||
class TitleCardWebcomicPanel(WebcomicPanel):
|
class TitleCardWebcomicPanel(WebcomicPanel):
|
||||||
|
'''
|
||||||
|
A caption in a webcomic.
|
||||||
|
'''
|
||||||
def __init__(self, caption):
|
def __init__(self, caption):
|
||||||
self.caption = caption
|
self.caption = caption
|
||||||
|
|
||||||
|
@ -221,6 +233,7 @@ def create_webcomic(layout : 'list[WebcomicPanel]'):
|
||||||
|
|
||||||
image = AnimatedImage.new((total_image_x_size, total_image_y_size))
|
image = AnimatedImage.new((total_image_x_size, total_image_y_size))
|
||||||
for i in range(len(layout)):
|
for i in range(len(layout)):
|
||||||
|
print(i)
|
||||||
panel = layout[i]
|
panel = layout[i]
|
||||||
x = i%2
|
x = i%2
|
||||||
y = math.floor(i/2)
|
y = math.floor(i/2)
|
||||||
|
@ -228,6 +241,26 @@ def create_webcomic(layout : 'list[WebcomicPanel]'):
|
||||||
return image
|
return image
|
||||||
|
|
||||||
def add_text_box(base : Image, caption : str, region_size : 'tuple[int, int]', coordinates : 'tuple[int, int]', font : str= "arial.ttf", init_font_size = 45, align :str = "", color = ColorScheme.BLACK):
|
def add_text_box(base : Image, caption : str, region_size : 'tuple[int, int]', coordinates : 'tuple[int, int]', font : str= "arial.ttf", init_font_size = 45, align :str = "", color = ColorScheme.BLACK):
|
||||||
|
'''
|
||||||
|
Adds a text box, where the size of the text scales to fit the box as closely as possible.
|
||||||
|
|
||||||
|
base: the image to put the text in.
|
||||||
|
caption: the text
|
||||||
|
region size: the size of the text box.
|
||||||
|
coordinates: the position of the text box.
|
||||||
|
font: name of the font file to use (defaults to arial)
|
||||||
|
init_font_size: the largest font size that will be used.
|
||||||
|
align: sets the alignment of the text.
|
||||||
|
Horizontal Alignments:
|
||||||
|
t: top
|
||||||
|
b: bottom
|
||||||
|
cv: center
|
||||||
|
Vertical Alignments:
|
||||||
|
l: left
|
||||||
|
r: right
|
||||||
|
ch: center
|
||||||
|
color: what colorscheme to use.
|
||||||
|
'''
|
||||||
font = get_real_filename(font)
|
font = get_real_filename(font)
|
||||||
|
|
||||||
if caption == "":
|
if caption == "":
|
||||||
|
@ -288,6 +321,9 @@ def add_text_box(base : Image, caption : str, region_size : 'tuple[int, int]', c
|
||||||
return add_text_box(base, caption, region_size, coordinates, font=font, init_font_size=init_font_size-1, align=align, color=color)
|
return add_text_box(base, caption, region_size, coordinates, font=font, init_font_size=init_font_size-1, align=align, color=color)
|
||||||
|
|
||||||
def add_text(base : Image, caption : str, region_size : 'tuple[int, int]', coordinates : 'tuple[int, int]', font : str= "arial.ttf"):
|
def add_text(base : Image, caption : str, region_size : 'tuple[int, int]', coordinates : 'tuple[int, int]', font : str= "arial.ttf"):
|
||||||
|
'''
|
||||||
|
Very simple interface for adding text.
|
||||||
|
'''
|
||||||
font = get_real_filename(font)
|
font = get_real_filename(font)
|
||||||
print(font)
|
print(font)
|
||||||
if caption == "":
|
if caption == "":
|
||||||
|
@ -298,6 +334,9 @@ def add_text(base : Image, caption : str, region_size : 'tuple[int, int]', coord
|
||||||
return base.paste(AnimatedImage.from_image(line_image.image), coordinates)
|
return base.paste(AnimatedImage.from_image(line_image.image), coordinates)
|
||||||
|
|
||||||
def add_watermark(image : Image, name_of_other_creator):
|
def add_watermark(image : Image, name_of_other_creator):
|
||||||
|
'''
|
||||||
|
Adds the rdrama watermark to the bottom of the image, crediting the other creator of the image.
|
||||||
|
'''
|
||||||
global watermark_captions
|
global watermark_captions
|
||||||
WATERMARK_HEIGHT = int(0.05 * image.height)
|
WATERMARK_HEIGHT = int(0.05 * image.height)
|
||||||
image_size_x, image_size_y = image.size
|
image_size_x, image_size_y = image.size
|
||||||
|
@ -317,6 +356,10 @@ def add_watermark(image : Image, name_of_other_creator):
|
||||||
return base
|
return base
|
||||||
|
|
||||||
def center_and_paste(base : Image, to_paste : Image, coordinates: 'tuple[int, int]', box_size : 'tuple[int, int]') -> 'AnimatedImage':
|
def center_and_paste(base : Image, to_paste : Image, coordinates: 'tuple[int, int]', box_size : 'tuple[int, int]') -> 'AnimatedImage':
|
||||||
|
'''
|
||||||
|
Centers to_paste in a box whose upper-left corder is "coordinates", and with size box_size.
|
||||||
|
'''
|
||||||
|
|
||||||
to_paste = to_paste.fit(box_size)
|
to_paste = to_paste.fit(box_size)
|
||||||
|
|
||||||
image_size_x, image_size_y = to_paste.size
|
image_size_x, image_size_y = to_paste.size
|
||||||
|
@ -335,6 +378,9 @@ def center_and_paste(base : Image, to_paste : Image, coordinates: 'tuple[int, in
|
||||||
return base.paste(to_paste, (x, y))
|
return base.paste(to_paste, (x, y))
|
||||||
|
|
||||||
def add_border_to_image(image : Image, thickness : int = 5):
|
def add_border_to_image(image : Image, thickness : int = 5):
|
||||||
|
'''
|
||||||
|
Adds a black border to an image.
|
||||||
|
'''
|
||||||
inner_image_x_size, inner_image_y_size = image.size
|
inner_image_x_size, inner_image_y_size = image.size
|
||||||
outer_image_x_size, outer_image_y_size = inner_image_x_size + 2*thickness, inner_image_y_size + 2*thickness
|
outer_image_x_size, outer_image_y_size = inner_image_x_size + 2*thickness, inner_image_y_size + 2*thickness
|
||||||
outside_image = AnimatedImage.new((outer_image_x_size,outer_image_y_size), color=(0,0,0))
|
outside_image = AnimatedImage.new((outer_image_x_size,outer_image_y_size), color=(0,0,0))
|
||||||
|
@ -343,6 +389,9 @@ def add_border_to_image(image : Image, thickness : int = 5):
|
||||||
return outside_image
|
return outside_image
|
||||||
|
|
||||||
def get_emoji_from_rdrama(emoji_name) -> 'AnimatedImage':
|
def get_emoji_from_rdrama(emoji_name) -> 'AnimatedImage':
|
||||||
|
'''
|
||||||
|
Gets an emoji from rdrama. If there is a "!" in the emoji name, it will be flipped.
|
||||||
|
'''
|
||||||
cleaned_emoji_name : str = emoji_name
|
cleaned_emoji_name : str = emoji_name
|
||||||
should_flip = False
|
should_flip = False
|
||||||
if '!' in emoji_name:
|
if '!' in emoji_name:
|
||||||
|
@ -360,6 +409,9 @@ def get_emoji_from_rdrama(emoji_name) -> 'AnimatedImage':
|
||||||
return image
|
return image
|
||||||
|
|
||||||
def get_image_file_from_url(url) -> 'AnimatedImage':
|
def get_image_file_from_url(url) -> 'AnimatedImage':
|
||||||
|
'''
|
||||||
|
Gets the image at the given address.
|
||||||
|
'''
|
||||||
try:
|
try:
|
||||||
r = requests.get(url)
|
r = requests.get(url)
|
||||||
image_file = io.BytesIO(r.content)
|
image_file = io.BytesIO(r.content)
|
||||||
|
@ -367,7 +419,11 @@ def get_image_file_from_url(url) -> 'AnimatedImage':
|
||||||
return AnimatedImage.from_image(im)
|
return AnimatedImage.from_image(im)
|
||||||
except:
|
except:
|
||||||
print(f"ERROR GETTING FILE FROM {url}")
|
print(f"ERROR GETTING FILE FROM {url}")
|
||||||
|
|
||||||
def parse_caption_file(filename):
|
def parse_caption_file(filename):
|
||||||
|
'''
|
||||||
|
Opens a file of strings and returns them.
|
||||||
|
'''
|
||||||
if not exists(filename):
|
if not exists(filename):
|
||||||
return []
|
return []
|
||||||
to_return = []
|
to_return = []
|
||||||
|
@ -376,9 +432,12 @@ def parse_caption_file(filename):
|
||||||
to_return.append(id.strip())
|
to_return.append(id.strip())
|
||||||
return to_return
|
return to_return
|
||||||
|
|
||||||
watermark_captions = parse_caption_file(get_real_filename(CAPTION_FILENAME))
|
|
||||||
|
|
||||||
class AnimatedImage():
|
class AnimatedImage():
|
||||||
|
'''
|
||||||
|
Basically a list of images, meant to be animated.
|
||||||
|
'''
|
||||||
def __init__(self, frames : 'list[Image.Image]'):
|
def __init__(self, frames : 'list[Image.Image]'):
|
||||||
if len(frames) > 100:
|
if len(frames) > 100:
|
||||||
self.frames = frames[0:100]
|
self.frames = frames[0:100]
|
||||||
|
@ -387,45 +446,70 @@ class AnimatedImage():
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self) -> 'Tuple[int, int]':
|
def size(self) -> 'Tuple[int, int]':
|
||||||
|
'''
|
||||||
|
Size of the image.
|
||||||
|
'''
|
||||||
return self.frames[0].size
|
return self.frames[0].size
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def height(self) -> int:
|
def height(self) -> int:
|
||||||
|
'''
|
||||||
|
Height of the image.
|
||||||
|
'''
|
||||||
return self.frames[0].size[1]
|
return self.frames[0].size[1]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def width(self) -> int:
|
def width(self) -> int:
|
||||||
|
'''
|
||||||
|
Width of the image.
|
||||||
|
'''
|
||||||
return self.frames[0].size[0]
|
return self.frames[0].size[0]
|
||||||
|
|
||||||
def flip(self) -> 'AnimatedImage':
|
def flip(self) -> 'AnimatedImage':
|
||||||
new_frames = []
|
'''
|
||||||
for frame in self.frames:
|
Flips image horizontally.
|
||||||
#frame.show()
|
'''
|
||||||
new_frame = ImageOps.mirror(frame)
|
|
||||||
#new_frame.show()
|
|
||||||
new_frames.append(new_frame)
|
|
||||||
return AnimatedImage(new_frames)
|
|
||||||
|
|
||||||
def save(self, filename) -> None:
|
return self.perform_transform_for_all_images(lambda image : ImageOps.mirror(image))
|
||||||
|
|
||||||
|
def save(self, filename : str) -> None:
|
||||||
|
'''
|
||||||
|
Saves the image to the filename
|
||||||
|
'''
|
||||||
self.frames[0].save(f"{filename}", save_all = True, append_images = self.frames[1:], duration = 100, loop=0)
|
self.frames[0].save(f"{filename}", save_all = True, append_images = self.frames[1:], duration = 100, loop=0)
|
||||||
|
|
||||||
def get_binary(self) -> bytes:
|
def get_binary(self) -> bytes:
|
||||||
|
'''
|
||||||
|
Converts the image to binary.
|
||||||
|
'''
|
||||||
output = io.BytesIO()
|
output = io.BytesIO()
|
||||||
self.frames[0].save(output, format="webp", save_all = True, append_images = self.frames[1:], duration = 100, loop=0)
|
self.frames[0].save(output, format="webp", save_all = True, append_images = self.frames[1:], duration = 100, loop=0)
|
||||||
return output.getvalue()
|
return output.getvalue()
|
||||||
|
|
||||||
|
def get_binary_gif(self) -> bytes:
|
||||||
|
output = io.BytesIO()
|
||||||
|
self.frames[0].save(output, format="gif", save_all = True, append_images = self.frames[1:], duration = 100, loop=0)
|
||||||
|
return output.getvalue()
|
||||||
|
|
||||||
def from_image(image: Image.Image) -> 'AnimatedImage':
|
def from_image(image: Image.Image) -> 'AnimatedImage':
|
||||||
|
'''
|
||||||
|
Converts a run of the mill PIL image to an AnimatedImage.
|
||||||
|
'''
|
||||||
frames = []
|
frames = []
|
||||||
for image_frame in ImageSequence.Iterator(image):
|
for image_frame in ImageSequence.Iterator(image):
|
||||||
frames.append(image_frame.copy())
|
frames.append(image_frame.copy())
|
||||||
return AnimatedImage(frames)
|
return AnimatedImage(frames)
|
||||||
|
|
||||||
def paste(self, other : 'AnimatedImage', position : 'Tuple[int, int]') -> 'AnimatedImage':
|
def paste(self, other : 'AnimatedImage', position : 'Tuple[int, int]') -> 'AnimatedImage':
|
||||||
|
'''
|
||||||
|
Pastes one image onto another. Tries to do it without breaking the loop.
|
||||||
|
'''
|
||||||
num_self_frames = len(self.frames)
|
num_self_frames = len(self.frames)
|
||||||
num_other_frames = len(other.frames)
|
num_other_frames = len(other.frames)
|
||||||
|
|
||||||
new_frames = []
|
new_frames = []
|
||||||
for i in range(get_ideal_number_of_frames(num_self_frames, num_other_frames)):
|
frames_to_create = min(get_ideal_number_of_frames(num_self_frames, num_other_frames), 100)
|
||||||
|
for i in range(frames_to_create):
|
||||||
self_frame = self.frames[i%num_self_frames]
|
self_frame = self.frames[i%num_self_frames]
|
||||||
other_frame = other.frames[i%num_other_frames]
|
other_frame = other.frames[i%num_other_frames]
|
||||||
|
|
||||||
|
@ -439,6 +523,9 @@ class AnimatedImage():
|
||||||
return AnimatedImage(new_frames)
|
return AnimatedImage(new_frames)
|
||||||
|
|
||||||
def new(size : 'Tuple[int, int]', color=(255,255,255)) -> 'AnimatedImage':
|
def new(size : 'Tuple[int, int]', color=(255,255,255)) -> 'AnimatedImage':
|
||||||
|
'''
|
||||||
|
Creates a blank AnimatedImage.
|
||||||
|
'''
|
||||||
base = Image.new(mode="RGB", size=size, color=color)
|
base = Image.new(mode="RGB", size=size, color=color)
|
||||||
return AnimatedImage.from_image(base)
|
return AnimatedImage.from_image(base)
|
||||||
|
|
||||||
|
@ -446,10 +533,7 @@ class AnimatedImage():
|
||||||
'''
|
'''
|
||||||
Shrinks the image while preserving it's aspect ratio, such that the new image has the same ratio but is contained in the given box.
|
Shrinks the image while preserving it's aspect ratio, such that the new image has the same ratio but is contained in the given box.
|
||||||
'''
|
'''
|
||||||
new_frames = []
|
return self.perform_transform_for_all_images(lambda image : ImageOps.contain(image, region))
|
||||||
for frame in self.frames:
|
|
||||||
new_frames.append(ImageOps.contain(frame, region))
|
|
||||||
return AnimatedImage(new_frames)
|
|
||||||
|
|
||||||
def stretch(self, region : 'Tuple[int, int]') -> 'AnimatedImage':
|
def stretch(self, region : 'Tuple[int, int]') -> 'AnimatedImage':
|
||||||
'''
|
'''
|
||||||
|
@ -507,6 +591,9 @@ def get_leftover_primes(a_, b_):
|
||||||
leftover_primes.append(i)
|
leftover_primes.append(i)
|
||||||
return leftover_primes
|
return leftover_primes
|
||||||
|
|
||||||
|
watermark_captions = parse_caption_file(get_real_filename(CAPTION_FILENAME))
|
||||||
|
|
||||||
|
|
||||||
# shooting = get_emoji_from_rdrama("!marseyshooting")
|
# shooting = get_emoji_from_rdrama("!marseyshooting")
|
||||||
# shooting2 = get_emoji_from_rdrama("marseydeterminedgun")
|
# shooting2 = get_emoji_from_rdrama("marseydeterminedgun")
|
||||||
|
|
||||||
|
@ -525,7 +612,7 @@ def get_leftover_primes(a_, b_):
|
||||||
# TwoCharacterWebcomicPanel("marseytombstone", "", "!marseycry", "He had so much to live for"),
|
# TwoCharacterWebcomicPanel("marseytombstone", "", "!marseycry", "He had so much to live for"),
|
||||||
# OneCharacterWebcomicPanel("marseylaugh", "Just Kidding!", False)
|
# OneCharacterWebcomicPanel("marseylaugh", "Just Kidding!", False)
|
||||||
# ]).save("webcomic.webp")
|
# ]).save("webcomic.webp")
|
||||||
create_modern_meme_from_url("https://media.giphy.com/media/gYkga3bZav66I/giphy.webp", "me when i see a black person (i am extremely racist)").save("racism.webp")
|
#create_modern_meme_from_url("https://media.giphy.com/media/gYkga3bZav66I/giphy.webp", "me when i see a black person (i am extremely racist)").save("racism.webp")
|
||||||
#create_classic_meme_from_url("https://rdrama.net/images/16619117705921352.webp", "I left out 'hiking' intentionally since it's outdoor hobby 101. But even if he's trying to attract a homebody some kind of interest would be good to have. Like home brewing, art, instrument, or god forbid tabletop gaming.", "This just screams most boring, generic, codependent 'man' ever. I need a wife and I'll be happy to do whatever you want to do 24/7 because I have no personality, friends, or interests").save("classic.webp")
|
#create_classic_meme_from_url("https://rdrama.net/images/16619117705921352.webp", "I left out 'hiking' intentionally since it's outdoor hobby 101. But even if he's trying to attract a homebody some kind of interest would be good to have. Like home brewing, art, instrument, or god forbid tabletop gaming.", "This just screams most boring, generic, codependent 'man' ever. I need a wife and I'll be happy to do whatever you want to do 24/7 because I have no personality, friends, or interests").save("classic.webp")
|
||||||
#create_modern_meme_from_url("https://rdrama.net/images/16617243111639555.webp", "It really does, especially with that weird lighting. ANd what's up with the subset of troons with Himmler eyes?").save("modern_image.webp")
|
#create_modern_meme_from_url("https://rdrama.net/images/16617243111639555.webp", "It really does, especially with that weird lighting. ANd what's up with the subset of troons with Himmler eyes?").save("modern_image.webp")
|
||||||
#create_classic_meme_from_emoji("marseycock", "I WANT TO PUT MY DICK", "INSIDE OF MARSEY").save("classic_with_emoji.webp")
|
#create_classic_meme_from_emoji("marseycock", "I WANT TO PUT MY DICK", "INSIDE OF MARSEY").save("classic_with_emoji.webp")
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
from io import BytesIO
|
||||||
|
import tweepy
|
||||||
|
from automeme import TextLine, get_rdrama, strip_markdown
|
||||||
|
import utils
|
||||||
|
import json
|
||||||
|
from meme_generator import get_image_file_from_url
|
||||||
|
|
||||||
|
def load_key_from_file(filename : str) -> str:
|
||||||
|
with open(utils.get_real_filename(filename), "r") as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
consumer_key = load_key_from_file("twitter_api_key")
|
||||||
|
consumer_secret = load_key_from_file("twitter_api_secret")
|
||||||
|
access_token = load_key_from_file("twitter_access_token")
|
||||||
|
access_token_secret = load_key_from_file("twitter_access_token_secret")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
auth = tweepy.OAuth1UserHandler(
|
||||||
|
consumer_key,
|
||||||
|
consumer_secret,
|
||||||
|
access_token,
|
||||||
|
access_token_secret
|
||||||
|
)
|
||||||
|
api = tweepy.API(auth)
|
||||||
|
|
||||||
|
rdrama = get_rdrama()
|
||||||
|
best = rdrama.get_comments(user = "automeme", sort = "top", t="day")['data'][0]
|
||||||
|
print(json.dumps(best, indent=4))
|
||||||
|
|
||||||
|
comment_text = best['body']
|
||||||
|
cleaned_comment_text = strip_markdown(comment_text)
|
||||||
|
comment_lines = cleaned_comment_text.split("\n")
|
||||||
|
comment_lines = [comment_line for comment_line in comment_lines if comment_line != ""]
|
||||||
|
element_lines = [TextLine(line) for line in comment_lines]
|
||||||
|
|
||||||
|
for i in element_lines:
|
||||||
|
print(i)
|
||||||
|
|
||||||
|
image = element_lines[-1].images[0]
|
||||||
|
print(image.url)
|
||||||
|
animated_image = get_image_file_from_url(image.url)
|
||||||
|
file = BytesIO(initial_bytes=animated_image.get_binary_gif())
|
||||||
|
media = api.media_upload(filename = "foo.gif", file=file, chunked=True, wait_for_async_finalize = True)
|
||||||
|
media_id = media.media_id_string
|
||||||
|
api.update_status("#meme", media_ids=[media_id])
|
Loading…
Reference in New Issue