rDrama/files/helpers/marseyfx/modifiers.py

195 lines
5.4 KiB
Python
Raw Normal View History

2023-09-18 05:40:02 +00:00
import re
2023-09-18 03:01:40 +00:00
from bs4 import BeautifulSoup, Tag
from files.helpers.config.const import SITE_FULL_IMAGES
2023-09-18 15:05:28 +00:00
from files.helpers.marseyfx.tokenizer import GroupToken, NumberLiteralToken, StringLiteralToken, Token, Tokenizer
import files.helpers.marseyfx.parser as parser
2023-09-18 03:01:40 +00:00
modifier_whitelist = []
2023-09-18 05:40:02 +00:00
class Modifier:
name: str
args: list[Token]
def __init__(self, name: str, args: list[Token]):
self.name = name
self.args = args
2023-09-18 03:01:40 +00:00
def modifier(fn):
modifier_whitelist.append(fn.__name__)
def wrapper(*args, **kwargs):
2023-09-18 05:40:02 +00:00
slf = args[0]
2023-09-18 15:05:28 +00:00
slf.child = slf.container
slf.container = slf.child.wrap(slf.soup.new_tag('div', attrs={'class': f'marseyfx-modifier marseyfx-modifier-{fn.__name__}'}))
return fn(*args, **kwargs)
return wrapper
def heavy(fn):
def wrapper(*args, **kwargs):
slf = args[0]
slf.heavy_count += 1
2023-09-18 03:01:40 +00:00
return fn(*args, **kwargs)
return wrapper
class Modified:
soup: BeautifulSoup
2023-09-18 15:05:28 +00:00
container: Tag
child: Tag
tokenizer: Tokenizer
heavy_count = 0
2023-09-18 03:01:40 +00:00
2023-09-18 15:05:28 +00:00
def __init__(self, el, tokenizer):
2023-09-18 03:01:40 +00:00
self.soup = BeautifulSoup()
2023-09-18 15:05:28 +00:00
self.container = el
self.tokenizer = tokenizer
2023-09-18 03:01:40 +00:00
def add_class(self, class_: str):
2023-09-18 15:05:28 +00:00
if not 'class' in self.container.attrs:
self.container.attrs['class'] = ''
else:
self.container.attrs['class'].append(' ' + class_)
def add_child_class(self, class_: str):
if not 'class' in self.child.attrs:
self.child.attrs['class'] = ''
else:
self.child.attrs['class'].append(' ' + class_)
2023-09-18 03:01:40 +00:00
def apply_modifiers(self, modifiers: list[Modifier]):
for modifier in modifiers:
if modifier.name in modifier_whitelist:
getattr(self, modifier.name)(*modifier.args)
# Using this instead of throwing everything in a string and then parsing it helps
# mitigate the risk of XSS attacks
2023-09-19 02:27:27 +00:00
def image(self, name: str):
2023-09-18 05:40:02 +00:00
image = self.soup.new_tag(
2023-09-18 03:01:40 +00:00
'img',
loading='lazy',
2023-09-18 05:40:02 +00:00
src=f'{SITE_FULL_IMAGES}/i/{name}.webp',
attrs={'class': f'marseyfx-image marseyfx-image-{name}'}
)
container = self.soup.new_tag(
'div',
attrs={'class': f'marseyfx-image-container marseyfx-image-container-{name}'}
)
container.append(image)
return container
2023-09-18 03:01:40 +00:00
def underlay(self, underlay: Tag):
2023-09-18 15:05:28 +00:00
self.container.insert(0, underlay)
2023-09-18 03:01:40 +00:00
def overlay(self, overlay: Tag):
2023-09-18 15:05:28 +00:00
self.container.append(overlay)
def add_style(self, style: str):
if 'style' in self.container.attrs:
style = self.container.attrs['style'] + style
self.container.attrs['style'] = style
2023-09-18 03:01:40 +00:00
@modifier
def pat(self):
2023-09-18 05:40:02 +00:00
self.overlay(self.image('pat'))
2023-09-18 03:01:40 +00:00
@modifier
def love(self):
2023-09-18 05:40:02 +00:00
self.overlay(self.image('love-foreground'))
self.underlay(self.image('love-background'))
2023-09-18 03:01:40 +00:00
@modifier
def talking(self):
2023-09-18 05:40:02 +00:00
self.overlay(self.image('talking'))
2023-09-18 03:01:40 +00:00
@modifier
def genocide(self):
pass
@modifier
def says(self, msg):
if not isinstance(msg, StringLiteralToken):
return
2023-09-18 05:40:02 +00:00
self.overlay(self.image('says'))
2023-09-18 15:05:28 +00:00
self.container.append(self.soup.new_tag(
2023-09-18 03:01:40 +00:00
'span',
2023-09-18 05:40:02 +00:00
string=msg.value,
attrs={'class': 'marseyfx-modifier-says-text'}
2023-09-18 03:01:40 +00:00
))
@modifier
def fallover(self):
2023-09-18 15:05:28 +00:00
self.container = self.container.wrap(self.soup.new_tag(
2023-09-18 03:01:40 +00:00
'div',
2023-09-18 05:40:02 +00:00
attrs={'class': 'marseyfx-modifier-fallover-container'}
2023-09-18 03:01:40 +00:00
))
@modifier
2023-09-18 05:40:02 +00:00
def transform(self, transformstyle: StringLiteralToken):
if not re.fullmatch(r'[\w()\s%\.,]*', transformstyle.value):
print(f'Evil transform detected: {transformstyle.value}')
2023-09-18 03:01:40 +00:00
return
2023-09-18 15:05:28 +00:00
self.add_style(f'transform: {transformstyle.value};')
2023-09-18 03:01:40 +00:00
2023-09-18 15:05:28 +00:00
@heavy
2023-09-18 03:01:40 +00:00
@modifier
def enraged(self):
self.underlay(self.soup.new_tag(
'div',
2023-09-19 02:27:27 +00:00
attrs={'class': 'marseyfx-modifier-enraged-underlay'}
2023-09-18 03:01:40 +00:00
))
2023-09-18 15:05:28 +00:00
@heavy
2023-09-18 03:01:40 +00:00
@modifier
2023-09-19 02:27:27 +00:00
def highcontrast(self):
2023-09-18 03:01:40 +00:00
pass
2023-09-18 15:05:28 +00:00
@heavy
2023-09-18 03:01:40 +00:00
@modifier
def wavy(self):
2023-09-18 15:05:28 +00:00
self.container.wrap(self.soup.new_tag('svg'))
@modifier
def toptext(self, text: StringLiteralToken):
if not isinstance(text, StringLiteralToken):
return
self.overlay(self.soup.new_tag(
'span',
string=text.value,
attrs={'class': 'marseyfx-modifier-toptext-text'}
))
@modifier
def bottomtext(self, text: StringLiteralToken):
if not isinstance(text, StringLiteralToken):
return
self.overlay(self.soup.new_tag(
'span',
string=text.value,
attrs={'class': 'marseyfx-modifier-bottomtext-text'}
))
@modifier
def spin(self, speed: NumberLiteralToken):
2023-09-19 02:27:27 +00:00
self.add_style('--marseyfx-spin-peroid-multiplier: ' + (1/speed.value) + ';')
2023-09-18 15:05:28 +00:00
@modifier
def triumphs(self, other: GroupToken):
other_emoji = parser.parse_from_token(self.tokenizer, other)
if other_emoji is None:
return
self.add_child_class('marseyfx-modifier-triumphs-self')
other = other_emoji.create_el().wrap(
self.soup.new_tag('div', attrs={'class': 'marseyfx-modifier-triumphs-other'})
)
self.underlay(other)